int auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch, struct auvia_dma *p, void *start, void *end, int blksize) { struct auvia_dma_op *op; struct auvia_dma *dp; bus_addr_t s; size_t l; int segs; s = p->map->dm_segs[0].ds_addr; l = (vaddr_t)end - (vaddr_t)start; segs = howmany(l, blksize); if (segs > AUVIA_DMALIST_MAX) { panic("%s: build_dma_ops: too many DMA segments", sc->sc_dev.dv_xname); } if (segs > ch->sc_dma_op_count) { /* if old list was too small, free it */ if (ch->sc_dma_ops) auvia_free(sc, ch->sc_dma_ops, M_DEVBUF); ch->sc_dma_ops = auvia_malloc(sc, 0, sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK); for (dp = sc->sc_dmas; dp && dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next) ; if (!dp) panic("%s: build_dma_ops: where'd my memory go??? " "address (%p)", sc->sc_dev.dv_xname, ch->sc_dma_ops); ch->sc_dma_op_count = segs; ch->sc_dma_ops_dma = dp; } op = ch->sc_dma_ops; while (l) { op->ptr = htole32(s); l = l - min(l, blksize); /* if last block */ op->flags = htole32((l? AUVIA_DMAOP_FLAG : AUVIA_DMAOP_EOL) | blksize); s += blksize; op++; } return 0; }
static void * auvia_malloc(void *addr, int direction, size_t size) { struct auvia_softc *sc; void *p; sc = addr; p = auvia_malloc_dmamem(addr, direction, size); if (p == NULL) { return NULL; } if (auvia_malloc_channel(sc, &sc->sc_play, size) != 0) { auvia_free(addr, p, size); return NULL; } if (auvia_malloc_channel(sc, &sc->sc_record, size) != 0) { auvia_free(addr, p, size); return NULL; } return p; }
static int auvia_detach(device_t self, int flags) { int rc; struct auvia_softc *sc = device_private(self); if ((rc = config_detach_children(self, flags)) != 0) return rc; pmf_device_deregister(self); mutex_enter(&sc->sc_lock); auconv_delete_encodings(sc->sc_encodings); auconv_delete_encodings(sc->sc_spdif_encodings); if (sc->codec_if != NULL) sc->codec_if->vtbl->detach(sc->codec_if); mutex_exit(&sc->sc_lock); /* XXX restore compatibility? */ if (sc->sc_ih != NULL) pci_intr_disestablish(sc->sc_pc, sc->sc_ih); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); if (sc->sc_play.sc_dma_ops != NULL) { auvia_free(sc, sc->sc_play.sc_dma_ops, sc->sc_play.sc_dma_op_count * sizeof(struct auvia_dma_op)); } if (sc->sc_record.sc_dma_ops != NULL) { auvia_free(sc, sc->sc_record.sc_dma_ops, sc->sc_play.sc_dma_op_count * sizeof(struct auvia_dma_op)); } mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return 0; }
static int auvia_malloc_channel(struct auvia_softc *sc, struct auvia_softc_chan *ch, size_t size) { struct auvia_dma *dp; int segs; /* if old list is large enough, nothing to do */ segs = (size + AUVIA_MINBLKSZ - 1) / AUVIA_MINBLKSZ; if (segs <= ch->sc_dma_op_count) { return 0; } if (ch->sc_dma_ops) { auvia_free(sc, ch->sc_dma_ops, ch->sc_dma_op_count * sizeof(*dp)); } ch->sc_dma_ops = auvia_malloc_dmamem(sc, 0, sizeof(struct auvia_dma_op) * segs); if (ch->sc_dma_ops == NULL) { aprint_error_dev(sc->sc_dev, "couldn't build dmaops\n"); return ENOMEM; } for (dp = sc->sc_dmas; dp && dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next) continue; if (!dp) panic("%s: build_dma_ops: where'd my memory go??? " "address (%p)\n", device_xname(sc->sc_dev), ch->sc_dma_ops); ch->sc_dma_op_count = segs; ch->sc_dma_ops_dma = dp; return 0; }