/* reclaim completed transmit descriptors and packets */ static void BCMFASTPATH chiptxreclaim(struct bcm4xxx *ch, bool forceall) { ET_TRACE(("et%d: chiptxreclaim\n", ch->etc->unit)); dma_txreclaim(ch->di, forceall ? HNDDMA_RANGE_ALL : HNDDMA_RANGE_TRANSMITTED); ch->intstatus &= ~I_XI; }
static int bcm947xx_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data; struct bcm947xx_runtime_data *brtd = substream->runtime->private_data; DBG("%s %s\n", __FUNCTION__, bcm947xx_direction_str(substream)); DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__, R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus), R_REG(snd_bcm->osh, &snd_bcm->regs->intmask)); /* #if required because dma_dump is unavailable in non-debug builds. */ #if BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON { /* dump dma rings to console */ #if !defined(FIFOERROR_DUMP_SIZE) #define FIFOERROR_DUMP_SIZE 8192 #endif char *tmp; struct bcmstrbuf b; if (snd_bcm->di[0] && (tmp = MALLOC(snd_bcm->osh, FIFOERROR_DUMP_SIZE))) { bcm_binit(&b, tmp, FIFOERROR_DUMP_SIZE); dma_dump(snd_bcm->di[0], &b, TRUE); printbig(tmp); MFREE(snd_bcm->osh, tmp, FIFOERROR_DUMP_SIZE); } } #endif /* BCM947XX_DUMP_RING_BUFFER_ON_PCM_CLOSE_ON */ /* reclaim all descriptors */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { dma_rxreset(snd_bcm->di[0]); dma_rxreclaim(snd_bcm->di[0]); } else { dma_txreset(snd_bcm->di[0]); dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL); } if (brtd) kfree(brtd); else DBG("%s: called with brtd == NULL\n", __FUNCTION__); return 0; }
/* Maybe called from snd_period_elapsed. */ static int bcm947xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct bcm947xx_runtime_data *brtd = runtime->private_data; uint32 intmask = R_REG(snd_bcm->osh, &snd_bcm->regs->intmask); int ret = 0; DBG("%s %s w/cmd=%d\n", __FUNCTION__, bcm947xx_direction_str(substream), cmd); spin_lock(&brtd->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { brtd->bytes_pending = snd_pcm_lib_buffer_bytes(substream); bcm947xx_pcm_enqueue(substream); } else { // dma_txresume(snd_bcm->di[0]); } break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { // dma_txsuspend(snd_bcm->di[0]); break; } /* fall-thru */ case SNDRV_PCM_TRIGGER_STOP: /* Reset the disable interrupts, DMA RX/TX channel. Might get here as a result of calling snd_pcm_period_elapsed. */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { intmask &= ~intmask_capture; W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask); dma_rxreset(snd_bcm->di[0]); dma_rxreclaim(snd_bcm->di[0]); dma_rxinit(snd_bcm->di[0]); } else { /* Disable transmit interrupts. */ intmask &= ~intmask_playback; W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, intmask); dma_txreset(snd_bcm->di[0]); dma_txreclaim(snd_bcm->di[0], HNDDMA_RANGE_ALL); dma_txinit(snd_bcm->di[0]); if (BCM947XX_DMA_LOOPBACK_ENABLED) dma_fifoloopbackenable(snd_bcm->di[0]); // dma_txsuspend(snd_bcm->di[0]); } break; default: ret = -EINVAL; } spin_unlock(&brtd->lock); DBG("%s: i2s intstatus 0x%x intmask 0x%x\n", __FUNCTION__, R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus), R_REG(snd_bcm->osh, &snd_bcm->regs->intmask)); return ret; }