- add mmap support

- correct bug which wouldn't free allocated DMA segments
This commit is contained in:
gmcgarry 2000-06-12 22:40:20 +00:00
parent cc29e9b22c
commit 6ab5c3364c
1 changed files with 86 additions and 44 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bba.c,v 1.5 2000/06/05 23:02:04 gmcgarry Exp $ */
/* $NetBSD: bba.c,v 1.6 2000/06/12 22:40:20 gmcgarry Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -63,14 +63,17 @@
#define DPRINTF(x)
#endif /* AUDIO_DEBUG */
#define BBA_MAX_DMA_SEGMENTS 16
#define BBA_REGISTER_SHIFT 6
#define BBA_MAX_DMA_SEGMENTS 16
#define BBA_DMABUF_SIZE (BBA_MAX_DMA_SEGMENTS*PAGE_SIZE)
#define BBA_DMABUF_ALIGN PAGE_SIZE
#define BBA_DMABUF_BOUNDARY 0
struct bba_mem {
struct bba_mem *next;
bus_addr_t addr;
bus_size_t size;
caddr_t kva;
struct bba_mem *next;
};
struct bba_dma_state {
@ -138,10 +141,12 @@ int bba_getdev __P((void *, struct audio_device *));
void *bba_allocm __P((void *, int, size_t, int, int));
void bba_freem __P((void *, void *, int));
size_t bba_round_buffersize __P((void *, int, size_t));
int bba_get_props __P((void *));
int bba_mappage __P((void *, void *, int, int));
int bba_trigger_output __P((void *, void *, void *, int,
void (*)(void *), void *, struct audio_params *));
void (*)(void *), void *, struct audio_params *));
int bba_trigger_input __P((void *, void *, void *, int,
void (*)(void *), void *, struct audio_params *));
void (*)(void *), void *, struct audio_params *));
struct audio_hw_if sa_hw_if = {
am7930_open,
@ -166,8 +171,8 @@ struct audio_hw_if sa_hw_if = {
bba_allocm, /* md */
bba_freem, /* md */
bba_round_buffersize, /* md */
0,
am7930_get_props,
bba_mappage,
bba_get_props,
bba_trigger_output, /* md */
bba_trigger_input /* md */
};
@ -190,9 +195,9 @@ int bba_match(parent, cf, aux)
{
struct ioasicdev_attach_args *ia = aux;
if (strcmp(ia->iada_modname, "isdn") != 0 &&
strcmp(ia->iada_modname, "AMD79c30") != 0)
return 0;
if (strcmp(ia->iada_modname, "isdn") != 0 &&
strcmp(ia->iada_modname, "AMD79c30") != 0)
return 0;
return 1;
}
@ -214,7 +219,7 @@ bba_attach(parent, self, aux)
/* get the bus space handle for codec */
if (bus_space_subregion(sc->sc_bst, sc->sc_bsh,
ia->iada_offset, 0, &sc->sc_codec_bsh)) {
ia->iada_offset, 0, &sc->sc_codec_bsh)) {
printf("%s: unable to map device\n", asc->sc_dev.dv_xname);
return;
}
@ -234,7 +239,7 @@ bba_attach(parent, self, aux)
am7930_init(asc, AUDIOAMD_DMA_MODE);
ioasic_intr_establish(parent, ia->iada_cookie, TC_IPL_NONE,
bba_intr, sc);
bba_intr, sc);
audio_attach_mi(&sa_hw_if, asc, &asc->sc_dev);
}
@ -300,20 +305,23 @@ bba_allocm(addr, direction, size, pool, flags)
int rseg;
caddr_t kva;
struct bba_mem *m;
int w;
int state = 0;
DPRINTF(("bba_allocm: size = %d\n",size));
if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg,
1, &rseg, BUS_DMA_NOWAIT)) {
w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN,
BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) {
printf("%s: can't allocate DMA buffer\n",
asc->sc_dev.dv_xname);
asc->sc_dev.dv_xname);
goto bad;
}
state |= 1;
if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
&kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
&kva, w | BUS_DMA_COHERENT)) {
printf("%s: can't map DMA buffer\n", asc->sc_dev.dv_xname);
goto bad;
}
@ -351,11 +359,11 @@ bba_freem(addr, ptr, pool)
caddr_t kva = (caddr_t)addr;
for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva;
mp = &(*mp)->next)
mp = &(*mp)->next)
/* nothing */ ;
m = *mp;
if (m != NULL) {
printf("bba_freem: freeing unallocted memory\n");
if (m == NULL) {
printf("bba_freem: freeing unallocated memory\n");
return;
}
*mp = m->next;
@ -376,8 +384,7 @@ bba_round_buffersize(addr, direction, size)
{
DPRINTF(("bba_round_buffersize: size=%d\n", size));
#define BBA_BUFFERSIZE (BBA_MAX_DMA_SEGMENTS * PAGE_SIZE)
return (size > BBA_BUFFERSIZE ? BBA_BUFFERSIZE : round_page(size));
return (size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE : round_page(size));
}
@ -457,27 +464,28 @@ bba_trigger_output(addr, start, end, blksize, intr, arg, param)
int state = 0;
DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
addr, start, end, blksize, intr, arg));
addr, start, end, blksize, intr, arg));
/* disable any DMA */
ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) {
BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, BBA_DMABUF_BOUNDARY,
BUS_DMA_NOWAIT, &d->dmam)) {
printf("bba_trigger_output: can't create DMA map\n");
goto bad;
}
state |= 1;
if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
printf("bba_trigger_output: can't load DMA map\n");
(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
printf("bba_trigger_output: can't load DMA map\n");
goto bad;
}
state |= 2;
/* disable any DMA */
ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
d->intr = intr;
d->intr_arg = arg;
d->curseg = 1;
@ -488,9 +496,9 @@ bba_trigger_output(addr, start, end, blksize, intr, arg, param)
/* setup DMA pointer */
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR,
IOASIC_DMA_ADDR(phys));
IOASIC_DMA_ADDR(phys));
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR,
IOASIC_DMA_ADDR(nphys));
IOASIC_DMA_ADDR(nphys));
/* kick off DMA */
ssr |= IOASIC_CSR_DMAEN_ISDN_T;
@ -525,27 +533,28 @@ bba_trigger_input(addr, start, end, blksize, intr, arg, param)
int state = 0;
DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
addr, start, end, blksize, intr, arg));
addr, start, end, blksize, intr, arg));
/* disable any DMA */
ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) {
BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, BBA_DMABUF_BOUNDARY,
BUS_DMA_NOWAIT, &d->dmam)) {
printf("bba_trigger_input: can't create DMA map\n");
goto bad;
}
state |= 1;
if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
printf("bba_trigger_input: can't load DMA map\n");
goto bad;
}
state |= 2;
/* disable any DMA */
ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
d->intr = intr;
d->intr_arg = arg;
d->curseg = 1;
@ -556,9 +565,9 @@ bba_trigger_input(addr, start, end, blksize, intr, arg, param)
/* setup DMA pointer */
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR,
IOASIC_DMA_ADDR(phys));
IOASIC_DMA_ADDR(phys));
bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR,
IOASIC_DMA_ADDR(nphys));
IOASIC_DMA_ADDR(nphys));
/* kick off DMA */
ssr |= IOASIC_CSR_DMAEN_ISDN_R;
@ -594,7 +603,7 @@ bba_intr(addr)
d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
bus_space_write_4(sc->sc_bst, sc->sc_bsh,
IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
if (d->intr != NULL)
(*d->intr)(d->intr_arg);
}
@ -603,7 +612,7 @@ bba_intr(addr)
d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
bus_space_write_4(sc->sc_bst, sc->sc_bsh,
IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
if (d->intr != NULL)
(*d->intr)(d->intr_arg);
}
@ -613,6 +622,39 @@ bba_intr(addr)
return 0;
}
int
bba_get_props(addr)
void *addr;
{
return (AUDIO_PROP_MMAP | am7930_get_props(addr));
}
int
bba_mappage(addr, mem, offset, prot)
void *addr;
void *mem;
int offset;
int prot;
{
struct bba_softc *sc = addr;
struct bba_mem **mp;
bus_dma_segment_t seg;
caddr_t kva = (caddr_t)mem;
for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva;
mp = &(*mp)->next)
/* nothing */ ;
if (*mp == NULL || offset < 0) {
return -1;
}
seg.ds_addr = (*mp)->addr;
seg.ds_len = (*mp)->size;
return bus_dmamem_mmap(sc->sc_dmat, &seg, 1, offset,
prot, BUS_DMA_WAITOK);
}
void
bba_input_conv(v, p, cc)