__snd_pcm_lib_xfer
/* the common loop for read/write data */
snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
void *data, bool interleaved,
snd_pcm_uframes_t size, bool in_kernel)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
snd_pcm_uframes_t avail;
pcm_copy_f writer;
pcm_transfer_f transfer;
bool nonblock;
bool is_playback;
int err;
err = pcm_sanity_check(substream);
if (err < 0)
return err;
is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
if (interleaved) { interleave 的copy函数 L0R0L1R1
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
runtime->channels > 1)
return -EINVAL;
writer = interleaved_copy;
} else {//non interleave copy函数,L0ROL1R1
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
writer = noninterleaved_copy;
}
if (!data) {
if (is_playback)
transfer = fill_silence;//如果没有data,就填0
else
return -EINVAL;
} else if (in_kernel) {
if (substream->ops->copy_kernel)
transfer = substream->ops->copy_kernel;
else
transfer = is_playback ?
default_write_copy_kernel : default_read_copy_kernel;
} else {
if (substream->ops->copy_user)
transfer = (pcm_transfer_f)substream->ops->copy_user;//platfrom中定义的copy函数,将data从user space copy到DMA中,然后HW会从DMA中搬数据
else
transfer = is_playback ?
default_write_copy : default_read_copy;
}
if (size == 0)
return 0;
nonblock = !!(substream->f_flags & O_NONBLOCK);
snd_pcm_stream_lock_irq(substream);
err = pcm_accessible_state(runtime);
if (err < 0)
goto _end_unlock;
runtime->twake = runtime->control->avail_min ? : 1;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)//如果已经是播放状态,则更新hw_ptr
snd_pcm_update_hw_ptr(substream);
/*
* If size < start_threshold, wait indefinitely. Another
* thread may start capture
*/
if (!is_playback && //capture hw trigger的flow
runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
size >= runtime->start_threshold) { //capture要都的data size>start_threshold
err = snd_pcm_start(substream); //启动HW或者trigger HW,开始工作传数据
if (err < 0)
goto _end_unlock;
}
avail = snd_pcm_avail(substream);//对playback指DMA的space size;对capture是指DMA中的data size
while (size > 0) {//想要write的data size或者是想要读的data size
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t cont;
if (!avail) {
if (!is_playback &&
runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
goto _end_unlock;
}
if (nonblock) {
err = -EAGAIN;
goto _end_unlock;
}
runtime->twake = min_t(snd_pcm_uframes_t, size,
runtime->control->avail_min ? : 1);
err = wait_for_avail(substream, &avail);
if (err < 0)
goto _end_unlock;
if (!avail)
continue; /* draining */
}
frames = size > avail ? avail : size;
appl_ptr = READ_ONCE(runtime->control->appl_ptr);//获取app_ptr
appl_ofs = appl_ptr % runtime->buffer_size;//app_ptr不能超过buf size
cont = runtime->buffer_size - appl_ofs;
if (frames > cont)
frames = cont;
if (snd_BUG_ON(!frames)) {
err = -EINVAL;
goto _end_unlock;
}
snd_pcm_stream_unlock_irq(substream);
err = writer(substream, appl_ofs, data, offset, frames,//开始写数据到dma
transfer);
snd_pcm_stream_lock_irq(substream);
if (err < 0)
goto _end_unlock;
err = pcm_accessible_state(runtime);
if (err < 0)
goto _end_unlock;
appl_ptr += frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;//不能超过boundary
err = pcm_lib_apply_appl_ptr(substream, appl_ptr);//更新app_ptr
if (err < 0)
goto _end_unlock;
offset += frames;
size -= frames;
xfer += frames;
avail -= frames;
if (is_playback && //playback,write到dma的data超过start threshold开始trigger HW,开始传数据
runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
err = snd_pcm_start(substream);
if (err < 0)
goto _end_unlock;
}
}
_end_unlock:
runtime->twake = 0;
if (xfer > 0 && err >= 0)
snd_pcm_update_state(substream, runtime);//更新runtime 的state
snd_pcm_stream_unlock_irq(substream);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
(1)bounddary的值
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime;
int err, usecs;
unsigned int bits;
snd_pcm_uframes_t frames;
....
/* Default sw params */
runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
runtime->period_step = 1;
runtime->control->avail_min = runtime->period_size;
runtime->start_threshold = 1;
runtime->stop_threshold = runtime->buffer_size;
runtime->silence_threshold = 0;
runtime->silence_size = 0;
runtime->boundary = runtime->buffer_size;
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;//设置long型的最大值,且为buf size的整数倍
(2)更新app_ptr到runtime的变量中
int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t appl_ptr)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
int ret;
if (old_appl_ptr == appl_ptr)
return 0;
runtime->control->appl_ptr = appl_ptr;
if (substream->ops->ack) {
ret = substream->ops->ack(substream);
if (ret < 0) {
runtime->control->appl_ptr = old_appl_ptr;
return ret;
}
}
trace_applptr(substream, old_appl_ptr, appl_ptr);
return 0;
}
行胜于言,自强不息。

浙公网安备 33010602011771号