Ejemplo n.º 1
0
/* count is contiguous within the period. */
static int bcm947xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
        snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm947xx_runtime_data *brtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	ssize_t framebytes = frames_to_bytes(runtime, count);
	char *hwbuf;
	unsigned long flags;
	
	/* Linear position to DMA pointer. */
	spin_lock_irqsave(&brtd->lock, flags);
	hwbuf = bcm947xx_from_linear(substream, pos);
	spin_unlock_irqrestore(&brtd->lock, flags);

	/* Copy (capture). */
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		if (BCM947XX_DMA_RX_CACHE_INVALIDATE_WAR_ON &&
			pos % runtime->period_size == 0)
		{
			DMA_MAP(snd_bcm->osh, hwbuf-brtd->dma_ofs, BCM947XX_DMA_DATA_BYTES_MAX, DMA_RX, NULL, NULL);
		}
		if (copy_to_user(src, hwbuf, framebytes))
			return -EFAULT;
		if (BCM947XX_TRACE_CAPTURE_COPY_ON) {
			DBG("%s hwbuf=%p pos=%lu count=%lu (%zd bytes)\n", __FUNCTION__,
				hwbuf, pos, count, framebytes);
		}

	/* Copy (playback). */
	} else {
		if (copy_from_user(hwbuf, src, framebytes))
			return -EFAULT;
		if (BCM947XX_TRACE_PLAYBACK_COPY_ON) {
			DBG("%s hwbuf=%p pos=%lu count=%lu (%zd bytes)\n", __FUNCTION__,
				hwbuf, pos, count, framebytes);
		}
	}

	spin_lock_irqsave(&brtd->lock, flags);
	brtd->bytes_pending += frames_to_bytes(runtime, count);
	bcm947xx_pcm_enqueue(substream);
	spin_unlock_irqrestore(&brtd->lock, flags);

	return 0;
}
Ejemplo n.º 2
0
Archivo: hnddma.c Proyecto: ariavie/bcm
/* post receive buffers */
void
dma_rxfill(dma_info_t *di)
{
	void *p;
	uint rxin, rxout;
	uint ctrl;
	uint n;
	uint i;
	uint32 pa;
	uint rxbufsize;

	/*
	 * Determine how many receive buffers we're lacking
	 * from the full complement, allocate, initialize,
	 * and post them, then update the chip rx lastdscr.
	 */

	rxin = di->rxin;
	rxout = di->rxout;
	rxbufsize = di->rxbufsize;

	n = di->nrxpost - NRXDACTIVE(rxin, rxout);

	DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));

	for (i = 0; i < n; i++) {
		if ((p = PKTGET(di->drv, rxbufsize, FALSE)) == NULL) {
			DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
			di->hnddma.rxnobuf++;
			break;
		}

		/* PR3263 & PR3387 & PR4642 war: rxh.len=0 means dma writes not complete */
		*(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0;

		pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p);
		ASSERT(ISALIGNED(pa, 4));

		/* save the free packet pointer */
#if 0
		ASSERT(di->rxp[rxout] == NULL);
#endif
		di->rxp[rxout] = p;

		/* paranoia */
		ASSERT(R_SM(&di->rxd[rxout].addr) == 0);

		/* prep the descriptor control value */
		ctrl = rxbufsize;
		if (rxout == (di->nrxd - 1))
			ctrl |= CTRL_EOT;

		/* init the rx descriptor */
		W_SM(&di->rxd[rxout].ctrl, BUS_SWAP32(ctrl));
		W_SM(&di->rxd[rxout].addr, BUS_SWAP32(pa + di->dataoffset));

		DMA_TRACE(("%s: dma_rxfill:  ctrl %08x dataoffset: %08x\n", di->name, BUS_SWAP32(ctrl), BUS_SWAP32(pa + di->dataoffset)));

		rxout = NEXTRXD(rxout);
	}

	di->rxout = rxout;

	/* update the chip lastdscr pointer */
	W_REG(&di->regs->rcvptr, I2B(rxout));
}
Ejemplo n.º 3
0
Archivo: hnddma.c Proyecto: ariavie/bcm
/*
 * Just like above except go through the extra effort of splitting
 * buffers that cross 4Kbyte boundaries into multiple tx descriptors.
 */
int
dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
{
	void *p, *next;
	uchar *data;
	uint plen, len;
	uchar *page, *start, *end;
	uint txout;
	uint32 ctrl;
	uint32 pa;

	DMA_TRACE(("%s: dma_tx\n", di->name));

	txout = di->txout;
	ctrl = 0;

	/*
	 * Walk the chain of packet buffers
	 * splitting those that cross 4 Kbyte boundaries
	 * allocating and initializing transmit descriptor entries.
	 */
	for (p = p0; p; p = next) {
		data = PKTDATA(di->drv, p);
		plen = PKTLEN(di->drv, p);
		next = PKTNEXT(di->drv, p);

		/* PR988 - skip zero length buffers */
		if (plen == 0)
			continue;

		for (page = (uchar*)PAGEBASE(data);
			page <= (uchar*)PAGEBASE(data + plen - 1);
			page += PAGESZ) {

			/* return nonzero if out of tx descriptors */
			if (NEXTTXD(txout) == di->txin)
				goto outoftxd;

			start = (page == (uchar*)PAGEBASE(data))?  data: page;
			end = (page == (uchar*)PAGEBASE(data + plen))?
				(data + plen): (page + PAGESZ);
			len = end - start;

			/* build the descriptor control value */
			ctrl = len & CTRL_BC_MASK;

			/* PR3697: Descriptor flags are not ignored for descriptors where SOF is clear */
			ctrl |= coreflags;

			if ((p == p0) && (start == data))
				ctrl |= CTRL_SOF;
			if ((next == NULL) && (end == (data + plen)))
				ctrl |= (CTRL_IOC | CTRL_EOF);
			if (txout == (di->ntxd - 1))
				ctrl |= CTRL_EOT;

			/* get physical address of buffer start */
			pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);

			/* init the tx descriptor */
			W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
			W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));

			ASSERT(di->txp[txout] == NULL);

			txout = NEXTTXD(txout);
		}
	}

	/* if last txd eof not set, fix it */
	if (!(ctrl & CTRL_EOF))
		W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));

	/* save the packet */
	di->txp[di->txout] = p0;

	/* bump the tx descriptor index */
	di->txout = txout;

	/* kick the chip */
	W_REG(&di->regs->xmtptr, I2B(txout));

	/* tx flow control */
	di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;

	return (0);

outoftxd:
	DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
	PKTFREE(di->drv, p0, TRUE);
	di->txavail = 0;
	di->hnddma.txnobuf++;
	return (-1);
}