/**
 * snd_dmaengine_pcm_trigger - dmaengine based PCM trigger implementation
 * @substream: PCM substream
 * @cmd: Trigger command
 *
 * Returns 0 on success, a negative error code otherwise.
 *
 * This function can be used as the PCM trigger callback for dmaengine based PCM
 * driver implementations.
 */
int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	int ret;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		ret = dmaengine_pcm_prepare_and_submit(substream);
		if (ret)
			return ret;
		dma_async_issue_pending(prtd->dma_chan);
		break;
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		dmaengine_resume(prtd->dma_chan);
		break;
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		dmaengine_pause(prtd->dma_chan);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
		dmaengine_terminate_all(prtd->dma_chan);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}
static void dmaengine_pcm_dma_complete(void *arg)
{
	struct snd_pcm_substream *substream = arg;
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

#ifdef CONFIG_ARCH_ROCKCHIP
	if(debug_audio_timeout){
		struct snd_pcm_runtime *runtime = substream->runtime;
		static ktime_t before = {0},after = {0};
		s64 t;
		before = after;
		after = ktime_get();
		t = ktime_to_us(ktime_sub(after, before));

		if(t > (snd_pcm_lib_period_bytes(substream)/4+32)*1000*1000/runtime->rate
			&& t != ktime_to_us(after)) // (23220)4096/4/44100 + 32/44100
		{
				printk(KERN_DEBUG "Time out:: Audio DMA buffdone time out!!! the time = %lld!\n", t);
		}
		//printk(KERN_DEBUG "audio DMA callback time = %lld\n", t);
	}
#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);
}
Ejemplo n.º 3
0
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_chan *chan = prtd->dma_chan;
	struct dma_async_tx_descriptor *desc;
	enum dma_transfer_direction direction;
	unsigned long flags = DMA_CTRL_ACK;

	direction = snd_pcm_substream_to_dma_direction(substream);

	if (!substream->runtime->no_period_wakeup)
		flags |= DMA_PREP_INTERRUPT;

	prtd->pos = 0;
	desc = dmaengine_prep_dma_cyclic(chan,
		substream->runtime->dma_addr,
		snd_pcm_lib_buffer_bytes(substream),
		snd_pcm_lib_period_bytes(substream), direction, flags);

	if (!desc)
		return -ENOMEM;

	desc->callback = dmaengine_pcm_dma_complete;
	desc->callback_param = substream;
	prtd->cookie = dmaengine_submit(desc);

	return 0;
}
static void dmaengine_pcm_dma_complete(void *arg)
{
	struct snd_pcm_substream *substream = arg;
	struct dmaengine_pcm_runtime_data *prtd;

	snd_pcm_stream_lock(substream);
	if (!substream || !substream->runtime) {
		snd_pcm_stream_unlock(substream);
		return;
	}

	prtd = substream_to_prtd(substream);
	prtd->pos += snd_pcm_lib_period_bytes(substream);
	if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
		prtd->pos = 0;

	snd_pcm_stream_unlock(substream);

	snd_pcm_period_elapsed(substream);

#ifdef CONFIG_SND_PXA_SSP_DUMP
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
			&& ssp_playback_enable) {
		prtd->playback_transfer_addr =
				substream->runtime->dma_addr + prtd->pos;
		queue_work(ssp_playback_wq, &prtd->playback_dump_work);
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
			&& ssp_capture_enable) {
		prtd->capture_transfer_addr =
				substream->runtime->dma_addr + prtd->pos;
		queue_work(ssp_capture_wq, &prtd->capture_dump_work);
	}
#endif
}
/**
 * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
 * @substream: PCM substream
 *
 * Releases the DMA channel associated with the PCM substream.
 */
int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	dma_release_channel(prtd->dma_chan);

	return snd_dmaengine_pcm_close(substream);
}
/**
 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
 * @substream: PCM substream
 */
int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	kfree(prtd);

	return 0;
}
Ejemplo n.º 7
0
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_chan *chan = prtd->dma_chan;
	struct dma_async_tx_descriptor *desc;
	enum dma_transfer_direction direction;
	unsigned long flags = DMA_CTRL_ACK;

	direction = snd_pcm_substream_to_dma_direction(substream);

	if (!substream->runtime->no_period_wakeup)
		flags |= DMA_PREP_INTERRUPT;

	prtd->pos = 0;
#if defined CONFIG_ARCH_SUN9IW1 || defined (CONFIG_ARCH_SUN8IW6) || defined CONFIG_ARCH_SUN8IW7
		if (!strcmp(substream->pcm->card->id, "sndhdmiraw")) {
			desc = dmaengine_prep_dma_cyclic(chan,
				substream->runtime->dma_addr,
				2*snd_pcm_lib_buffer_bytes(substream),
				2*snd_pcm_lib_period_bytes(substream), direction, flags);
		} else if (!strcmp(substream->pcm->card->id, "snddaudio")) {
		#ifdef CONFIG_ARCH_SUN9IW1
			desc = dmaengine_prep_dma_cyclic(chan,
				substream->runtime->dma_addr,
				snd_pcm_lib_buffer_bytes(substream),
				snd_pcm_lib_buffer_bytes(substream), direction, flags);
		#else//CONFIG_ARCH_SUN8IW6
			desc = dmaengine_prep_dma_cyclic(chan,
				substream->runtime->dma_addr,
				snd_pcm_lib_buffer_bytes(substream),
				snd_pcm_lib_period_bytes(substream), direction, flags);
		#endif
		} else {
			desc = dmaengine_prep_dma_cyclic(chan,
				substream->runtime->dma_addr,
				snd_pcm_lib_buffer_bytes(substream),
				snd_pcm_lib_period_bytes(substream), direction, flags);
		}
#else
		desc = dmaengine_prep_dma_cyclic(chan,
			substream->runtime->dma_addr,
			snd_pcm_lib_buffer_bytes(substream),
			snd_pcm_lib_period_bytes(substream), direction, flags);
#endif

	if (!desc)
		return -ENOMEM;

	desc->callback = dmaengine_pcm_dma_complete;
	desc->callback_param = substream;
	prtd->cookie = dmaengine_submit(desc);

	return 0;
}
static void dmaengine_pcm_dma_complete(void *arg)
{
	struct snd_pcm_substream *substream = arg;
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	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);
}
/**
 * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
 * @substream: PCM substream
 *
 * This function is deprecated and should not be used by new drivers, as its
 * results may be unreliable.
 */
snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
#ifdef CONFIG_ARCH_ROCKCHIP
	dma_addr_t src, dst;

	prtd->dma_chan->device->dma_getposition(prtd->dma_chan, &src, &dst);
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
		prtd->pos = dst - substream->runtime->dma_addr;
	else
		prtd->pos = src - substream->runtime->dma_addr;
#endif
	return bytes_to_frames(substream->runtime, prtd->pos);
}
/**
 * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
 * @substream: PCM substream
 *
 * This function can be used as the PCM pointer callback for dmaengine based PCM
 * driver implementations.
 */
snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_tx_state state;
	enum dma_status status;
	unsigned int buf_size;
	unsigned int pos = 0;

	status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
	if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
		buf_size = snd_pcm_lib_buffer_bytes(substream);
		if (state.residue > 0 && state.residue <= buf_size)
			pos = buf_size - state.residue;
	}

	return bytes_to_frames(substream->runtime, pos);
}
/**
 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
 * @substream: PCM substream
 */
int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

#ifdef CONFIG_SND_PXA_SSP_DUMP
	if (ssp_playback_wq)
		flush_workqueue(ssp_playback_wq);
	if (ssp_capture_wq)
		flush_workqueue(ssp_capture_wq);
	if (prtd->playback_fp)
		filp_close(prtd->playback_fp, NULL);
	if (prtd->capture_fp)
		filp_close(prtd->capture_fp, NULL);
#endif
	kfree(prtd);

	return 0;
}
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_chan *chan = prtd->dma_chan;
	struct dma_async_tx_descriptor *desc;
	enum dma_transfer_direction direction;
	unsigned long flags = DMA_CTRL_ACK;

	direction = snd_pcm_substream_to_dma_direction(substream);

	if (!substream->runtime->no_period_wakeup)
		flags |= DMA_PREP_INTERRUPT;

	prtd->pos = 0;
#ifdef CONFIG_ARCH_ROCKCHIP
	//printk("soc dma buffersize = %d , periodsize=%d, periods=%d\n",
	//	snd_pcm_lib_buffer_bytes(substream),
	//	snd_pcm_lib_period_bytes(substream),
	//	snd_pcm_lib_buffer_bytes(substream)/snd_pcm_lib_period_bytes(substream));
	desc = dmaengine_prep_dma_infiniteloop(chan,
		substream->runtime->dma_addr,
		snd_pcm_lib_buffer_bytes(substream),
		snd_pcm_lib_period_bytes(substream),
		direction, flags,
		snd_pcm_lib_buffer_bytes(substream)/snd_pcm_lib_period_bytes(substream));
#else
	desc = dmaengine_prep_dma_cyclic(chan,
		substream->runtime->dma_addr,
		snd_pcm_lib_buffer_bytes(substream),
		snd_pcm_lib_period_bytes(substream), direction, flags);
#endif

	if (!desc)
		return -ENOMEM;

	desc->callback = dmaengine_pcm_dma_complete;
	desc->callback_param = substream;
	prtd->cookie = dmaengine_submit(desc);

	return 0;
}
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_chan *chan = prtd->dma_chan;
	struct dma_async_tx_descriptor *desc;
	enum dma_transfer_direction direction;
	unsigned long flags = DMA_CTRL_ACK;

	direction = snd_pcm_substream_to_dma_direction(substream);

	if (!substream->runtime->no_period_wakeup)
		flags |= DMA_PREP_INTERRUPT;

	prtd->pos = 0;
	desc = dmaengine_prep_dma_cyclic(chan,
		substream->runtime->dma_addr,
		snd_pcm_lib_buffer_bytes(substream),
		snd_pcm_lib_period_bytes(substream), direction, flags);

	if (!desc)
		return -ENOMEM;

	desc->callback = dmaengine_pcm_dma_complete;
	desc->callback_param = substream;
	prtd->cookie = dmaengine_submit(desc);

#ifdef CONFIG_SND_PXA_SSP_DUMP
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
			&& ssp_playback_enable) {
		prtd->playback_totsize = snd_pcm_lib_buffer_bytes(substream);
		prtd->playback_transfer_addr = substream->runtime->dma_addr;
		prtd->playback_dump_addr = substream->runtime->dma_addr;
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
			&& ssp_capture_enable) {
		prtd->capture_totsize = snd_pcm_lib_buffer_bytes(substream);
		prtd->capture_transfer_addr = substream->runtime->dma_addr;
		prtd->capture_dump_addr = substream->runtime->dma_addr;
	}
#endif
	return 0;
}
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	struct dma_chan *chan = prtd->dma_chan;
	struct dma_async_tx_descriptor *desc;
	enum dma_transfer_direction direction;

	direction = snd_pcm_substream_to_dma_direction(substream);

	prtd->pos = 0;
	desc = dmaengine_prep_dma_cyclic(chan,
		substream->runtime->dma_addr,
		snd_pcm_lib_buffer_bytes(substream),
		snd_pcm_lib_period_bytes(substream), direction);

	if (!desc)
		return -ENOMEM;

	desc->callback = dmaengine_pcm_dma_complete;
	desc->callback_param = substream;
	dmaengine_submit(desc);

	return 0;
}
Ejemplo n.º 15
0
static void dmaengine_pcm_dma_complete(void *arg)
{
	struct snd_pcm_substream *substream = NULL;
	struct dmaengine_pcm_runtime_data *prtd = NULL;
	unsigned long flags;

	substream = arg;
	if (!substream) {
		return;
	}
	snd_pcm_stream_lock_irqsave(substream, flags);
	if (!substream->runtime) {
		snd_pcm_stream_unlock_irqrestore(substream, flags);
		return;
	}
	prtd = substream_to_prtd(substream);

	prtd->pos += snd_pcm_lib_period_bytes(substream);
	if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
		prtd->pos = 0;
	snd_pcm_stream_unlock_irqrestore(substream, flags);

	snd_pcm_period_elapsed(substream);
}
/**
 * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
 * @substream: PCM substream
 *
 * This function is deprecated and should not be used by new drivers, as its
 * results may be unreliable.
 */
snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
	return bytes_to_frames(substream->runtime, prtd->pos);
}
/**
 * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
 * @substream: PCM substream
 *
 * Returns the data previously set with snd_dmaengine_pcm_set_data
 */
void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	return prtd->data;
}
struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	return prtd->dma_chan;
}
/**
 * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
 * @substream: PCM substream
 * @data: Data to set
 */
void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
{
	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);

	prtd->data = data;
}