예제 #1
0
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;
}
예제 #2
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;
}
예제 #3
0
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;
}
예제 #4
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;
}