static enum hrtimer_restart jz_asoc_hrtimer_callback(struct hrtimer *hr_timer) {
	struct jz_pcm_runtime_data *prtd = container_of(hr_timer,
			struct jz_pcm_runtime_data, hr_timer);
	struct snd_pcm_substream *substream = prtd->substream;
	struct dma_chan *dma_chan = prtd->dma_chan;
	dma_addr_t pdma_addr = 0;
	dma_addr_t pdma_addr_1 = 0;
	size_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
	size_t curr_pos = 0;
	enum dma_transfer_direction direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
		DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;


	if (atomic_read(&prtd->stopped))
		goto out;

	hrtimer_start(&prtd->hr_timer, prtd->expires , HRTIMER_MODE_REL);
	pdma_addr = dma_chan->device->get_current_trans_addr(dma_chan,
			NULL,
			NULL,
			direction);
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		curr_pos = snd_pcm_get_pos_algin_period(substream, pdma_addr);
		if (curr_pos == prtd->pos)
			goto out;
#ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM
		if (prtd->pos < curr_pos) {
			memset(snd_pcm_get_ptr(substream, prtd->pos), 0 , (curr_pos - prtd->pos));
		}
		if (prtd->pos > curr_pos) {
			memset(snd_pcm_get_ptr(substream, prtd->pos), 0, (buffer_bytes - prtd->pos));
			memset(snd_pcm_get_ptr(substream, 0), 0, curr_pos);
		}
#endif
		prtd->pos = curr_pos;
	} else {
		curr_pos = snd_pcm_get_pos(substream, pdma_addr);
		if (curr_pos == prtd->pos)
			goto out;
		prtd->pos = curr_pos;
	/*pdma_addr_1 = pdma_addr - 64;*/
	/*while(pdma_addr_1 < pdma_addr)*/
	/*{*/
		/*printk("[0] = 0x%08x [1] = 0x%08x\n", *(unsigned short *)(pdma_addr_1 | 0xa0000000), *(unsigned short *)((pdma_addr_1 | 0xa0000000)+2));*/
		/*pdma_addr_1 += 4;*/
	/*}*/
	}
	//printk("curr_pos = %d buffer_bytes = %d\n", curr_pos, buffer_bytes);

	snd_pcm_period_elapsed(substream);
out:

	return HRTIMER_NORESTART;
}
示例#2
0
static void jz_asoc_dma_callback(void *data)
{
	struct snd_pcm_substream *substream = data;
	struct jz_pcm_runtime_data *prtd = substream->runtime->private_data;
	void* old_pos_addr = snd_pcm_get_ptr(substream, prtd->pos);

	DMA_SUBSTREAM_MSG(substream,"%s enter stopped_pending == %d\n", __func__,
			atomic_read(&prtd->stopped_pending));
	if (!atomic_dec_if_positive(&prtd->stopped_pending)) {
		struct snd_soc_pcm_runtime *rtd = substream->private_data;
		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
		DMA_SUBSTREAM_MSG(substream,"stop real\n");
		cancel_delayed_work(&prtd->dwork_stop_dma);
		dmaengine_terminate_all(prtd->dma_chan);
		if (cpu_dai->driver->ops->trigger)
			cpu_dai->driver->ops->trigger(substream, prtd->stopped_cmd, cpu_dai);
		return;
	}

	if (!IS_ERR_OR_NULL(prtd->file) && !work_pending(&prtd->debug_work)) {
		prtd->copy_start = old_pos_addr;
		prtd->copy_length = snd_pcm_lib_period_bytes(substream);
		schedule_work(&prtd->debug_work);
	} else {
#if defined(CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM)
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			DMA_DEBUG_MSG("dma start %x pos %p size %d\n",
					substream->runtime->dma_addr,
					old_pos_addr,
					snd_pcm_lib_period_bytes(substream));
			memset(old_pos_addr, 0,
					snd_pcm_lib_period_bytes(substream));
		}
#endif
	}

	prtd->pos += snd_pcm_lib_period_bytes(substream);
	if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
		prtd->pos = 0;
	snd_pcm_period_elapsed(substream);
	return;
}
示例#3
0
static int jz_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct jz_pcm_runtime_data *prtd = substream->runtime->private_data;

#ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
#endif

#ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM
	size_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
#endif
	int ret;

	DMA_SUBSTREAM_MSG(substream,"%s enter cmd %d\n", __func__, cmd);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
#ifndef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE
		if (atomic_read(&prtd->stopped_pending))
			return -EPIPE;
#endif
		DMA_SUBSTREAM_MSG(substream,"start trigger\n");
		ret = jz_asoc_dma_prepare_and_submit(substream);
		if (ret)
			return ret;
		dma_async_issue_pending(prtd->dma_chan);
#ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE
		atomic_set(&prtd->stopped, 0);
		hrtimer_start(&prtd->hr_timer, prtd->expires , HRTIMER_MODE_REL);
#endif
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		DMA_SUBSTREAM_MSG(substream,"stop trigger\n");
#ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE
		atomic_set(&prtd->stopped, 1);
		/* To make sure there is not data transfer on AHB bus,
		 * then we can stop the dma, Wait tur or ror happen
		 */
		if (cpu_dai->driver->ops->trigger) {
			ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
			if (ret < 0)
				return ret;
		}
		dmaengine_terminate_all(prtd->dma_chan);
#else
		/* To make sure there is not data transfer on AHB bus,
		 * then we can stop the dma, Wait dma callback happen
		 */
		if (dmaengine_terminate_all(prtd->dma_chan)) {
			prtd->stopped_cmd = cmd;
			atomic_set(&prtd->stopped_pending, 1);
			schedule_delayed_work(&prtd->dwork_stop_dma, prtd->delayed_jiffies);
		}
#endif
#ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM
		printk(KERN_DEBUG"show the time memset1 %d\n", buffer_bytes);
		memset(snd_pcm_get_ptr(substream, 0), 0, buffer_bytes);
		printk(KERN_DEBUG"show the time memset2 %d\n", buffer_bytes);
#endif
		break;
	default:
		return -EINVAL;
	}
	return 0;
}