asoc框架学习
asoc框架经典文章
external/tinyalsa/pcm.c
1.1 pcm_open-------->
i2s_runtime_resume---------------->rockchip_i2s.c
clk_prepare_enable(i2s->mclk)
1.1.1 open(fn, O_RDWR|O_NONBLOCK)------->下面会调到kernel层
soc_pcm_open----->(soc-pcm.c)---->
cpu_dai->driver->ops->startup(substream, cpu_dai)
platform->driver->ops->open(substream)-------------------->dma操作,sound/soc/soc-generic-dmaengine-pcm.c 文件里定义
static const struct snd_pcm_ops dmaengine_pcm_ops = {
.open = dmaengine_pcm_open,
.close = snd_dmaengine_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = dmaengine_pcm_hw_params,
.hw_free = snd_pcm_lib_free_pages,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
};
static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
.component_driver = {
.probe_order = SND_SOC_COMP_ORDER_LATE,
},
.ops = &dmaengine_pcm_ops,
.pcm_new = dmaengine_pcm_new,
};
snd_soc_add_platform(dev, &pcm->platform, &dmaengine_pcm_platform) //注册
rockchip_i2s_probe------------------------------》//rockchip_i2s.c
devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0) //注册dma操作
codec_dai->driver->ops->startup(substream,codec_dai)
rtd->dai_link->ops->startup(substream)------------------------------>simple-card.c
clk_prepare_enable(dai_props->cpu_dai.clk)
clk_prepare_enable(dai_props->cpu_dai.clk)
1.1.2 ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)------->下面会调到kernel层
soc_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params)---->
rtd->dai_link->ops->hw_params(substream, params)---------------------->
snd_soc_dai_set_sysclk(codec_dai, 0, mclk,SND_SOC_CLOCK_IN)------------------------>
dai->driver->ops->set_sysclk(dai, clk_id, freq, dir)---------------------->
reg = snd_soc_read(codec, ES8396_CLK_CTRL_REG08);
reg &= 0xf0;
snd_soc_write(codec, ES8396_CLK_CTRL_REG08, reg); //使用clk1
/* bclkdiv m1 use clk1 */
snd_soc_update_bits(codec, ES8396_BCLK_DIV_M1_REG0E,0x20, 0x00);//设置bclk
/* lrckdiv m3 use clk1 */
snd_soc_update_bits(codec, ES8396_LRCK_DIV_M3_REG10,0x20, 0x00);//设置lrck
dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,freq, dir)
snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,SND_SOC_CLOCK_OUT)------------------------>
dai->driver->ops->set_sysclk(dai, clk_id, freq, dir)-------------------->
clk_set_rate(i2s->mclk, freq) //设置mclk,1128000000
dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,freq, dir)
soc_dai_hw_params(substream, &codec_params, codec_dai)------>
dai->driver->ops->hw_params(substream, params, dai)-----------------------》
bdiv = snd_soc_read(codec, ES8396_BCLK_DIV_M2_REG0F);
bdiv &= 0xe0;
bdiv |= es8396_mclk_coeffs[mclk_coeff].bclkdiv;
lrdiv = snd_soc_read(codec, ES8396_LRCK_DIV_M4_REG11);
lrdiv &= 0xe0;
lrdiv |= 0x22; /* es8396_mclk_coeffs[mclk_coeff].lrcdiv; */
snd_soc_write(codec, ES8396_BCLK_DIV_M2_REG0F, bdiv);
snd_soc_write(codec, ES8396_LRCK_DIV_M4_REG11, lrdiv);
priv->config[id].srate = srate;
priv->config[id].lrcdiv = lrdiv;
priv->config[id].sclkdiv = bdiv;
soc_dai_hw_params(substream, params, cpu_dai)--------------->
dai->driver->ops->hw_params(substream, params, dai)
//as master,设置bclk lcrk mclk
mclk_rate = clk_get_rate(i2s->mclk);
bclk_rate = i2s->bclk_fs * params_rate(params);
if (!bclk_rate)
return -EINVAL;
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
div_lrck = bclk_rate / params_rate(params);
regmap_update_bits(i2s->regmap, I2S_CKR,
I2S_CKR_MDIV_MASK,
I2S_CKR_MDIV(div_bclk));
regmap_update_bits(i2s->regmap, I2S_CKR,
I2S_CKR_TSD_MASK |
I2S_CKR_RSD_MASK,
I2S_CKR_TSD(div_lrck) |
I2S_CKR_RSD(div_lrck));
1.2 pcm_read---------------->
1.2.1 pcm_start(pcm)------->下面会调到kernel层
soc_pcm_trigger-------->
codec_dai->driver->ops->trigger //codec中没有用到
platform->driver->ops->trigger //soc-generic-dmaengine-pcm.c中调到了
cpu_dai->driver->ops->trigger //rockchip_i2s.c中调到了
rtd->dai_link->ops->trigger //simple-card.c中没有用到
1.3 pcm_prepare------------------>下面会调到kernel层
1.3.1 soc_pcm_prepare------->
rtd->dai_link->ops->prepare
platform->driver->ops->prepare
codec_dai->driver->ops->prepare
cpu_dai->driver->ops->prepare
snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,substream->stream)
snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream)------------>
dai->driver->ops->digital_mute(dai, mute)
1.4 pcm_read--------------------------------------------->
函数调用流程:snd_pcm_capture_ioctl(pcm_native.c)->snd_pcm_capture_ioctl1->snd_pcm_lib_read->snd_pcm_lib_read_transfer
static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
if (substream->ops->copy) {
if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
return err;
} else {//rk平台走这个流程
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
return -EFAULT;
}
return 0;
}
1.5 pcm_write--------------------------------------------->
函数调用流程:snd_pcm_playback_ioctl(pcm_native.c)->snd_pcm_playback_ioctl1->snd_pcm_lib_writev->snd_pcm_lib_write1
static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
unsigned long data,
snd_pcm_uframes_t size,
int nonblock,
transfer_f transfer)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
snd_pcm_uframes_t avail;
int err = 0;
if (size == 0)
return 0;
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_RUNNING:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
goto _end_unlock;
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
goto _end_unlock;
default:
err = -EBADFD;
goto _end_unlock;
}
runtime->twake = runtime->control->avail_min ? : 1;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
snd_pcm_update_hw_ptr(substream);
avail = snd_pcm_playback_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t cont;
if (!avail) {
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;
}
frames = size > avail ? avail : size;
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
if (frames > cont)
frames = cont;
if (snd_BUG_ON(!frames)) {
runtime->twake = 0;
snd_pcm_stream_unlock_irq(substream);
return -EINVAL;
}
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
err = transfer(substream, appl_ofs, data, offset, frames);
snd_pcm_stream_lock_irq(substream);
if (err < 0)
goto _end_unlock;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
goto _end_unlock;
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
goto _end_unlock;
default:
break;
}
appl_ptr += frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
xfer += frames;
avail -= frames;
if (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);
snd_pcm_stream_unlock_irq(substream);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
1.6 上面1.4的函数是在哪里注册的
//上层开始调的都是这里的函数(sound/corepcm_native.c)
const struct file_operations snd_pcm_f_ops[2] = {
{
.owner = THIS_MODULE,
.write = snd_pcm_write,
.write_iter = snd_pcm_writev,
.open = snd_pcm_playback_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_playback_poll,
.unlocked_ioctl = snd_pcm_playback_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
.owner = THIS_MODULE,
.read = snd_pcm_read,
.read_iter = snd_pcm_readv,
.open = snd_pcm_capture_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_capture_poll,
.unlocked_ioctl = snd_pcm_capture_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
}
};
//注册pcm设备时会注册以上函数(sound/core/pcm.c)
static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
struct snd_pcm *pcm;
if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
pcm = device->device_data;
if (pcm->internal)
return 0;
mutex_lock(®ister_mutex);
err = snd_pcm_add(pcm);
if (err)
goto unlock;
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
if (pcm->streams[cidx].substream == NULL)
continue;
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
case SNDRV_PCM_STREAM_CAPTURE:
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
/* register pcm */
err = snd_register_device(devtype, pcm->card, pcm->device,
&snd_pcm_f_ops[cidx], pcm,
&pcm->streams[cidx].dev);
if (err < 0) {
list_del_init(&pcm->list);
goto unlock;
}
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
list_for_each_entry(notify, &snd_pcm_notify_list, list)
notify->n_register(pcm);
unlock:
mutex_unlock(®ister_mutex);
return err;
}
二: machine驱动
snd_soc_register_card(struct snd_soc_card *card)------------------>
2.1snd_soc_instantiate_card------------------------------>
2.1.1 snd_card_new--------------------->创建声卡结构体 创建control设备
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);//申请内存
snd_ctl_create(card) // 创建control设备
2.1.2 soc_bind_dai_link------------------------------------->//绑定cpu_dai 、codec_dai 、codec和 platform 到rtd中
rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component)
rtd->num_codecs = dai_link->num_codecs
codec_dais[i] = snd_soc_find_dai(&codecs[i])
rtd->codec_dai = codec_dais[0]
rtd->codec = rtd->codec_dai->codec
rtd->platform = platform
2.1.3 soc_probe_link_components----------------------->
component = rtd->cpu_dai->component
soc_probe_component(card, component)
component = rtd->codec_dais[i]->component
soc_probe_component(card, component)
struct snd_soc_platform *platform = rtd->platform
soc_probe_component(card, &platform->component)--------------->
component->probe(component)
2.1.4 soc_probe_link_dais(card, i, order)------------------------->
soc_probe_dai(cpu_dai, order)
soc_probe_dai(rtd->codec_dais[i], order)------------------------>
dai->driver->probe(dai)
dai_link->init(rtd) //只调用一次
snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,unsigned int dai_fmt)----->设置maser/slave mode
snd_soc_dai_set_fmt(codec_dai, dai_fmt)
snd_soc_dai_set_fmt(cpu_dai, dai_fmt)----------------->
dai->driver->ops->set_fmt(dai, fmt)
2.1.5 soc_new_pcm//创建pcm
soc_new_pcm----------------------------------->
确认rtd下面是否有playback和 capture,有的rtd有capture而没有playback
对rtd->ops进行赋值 open close等这些赋值的意义在于上层对pcm设备的操作比如pcm_open
创建substream 并且通过substream->next挂载到pcm下面
此处pcm设备创建完成--------------------------------------->
snd_pcm_new(rtd->card->snd_card, new_name, num, playback,capture, &pcm)---------------->
//创建pcm以及pcm下面挂载的substream
snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)新建playback
snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)/新建capture
snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)//创建snd_device 挂载到snd_card上面
rtd->ops.open = soc_pcm_open;
rtd->ops.hw_params = soc_pcm_hw_params;
rtd->ops.prepare = soc_pcm_prepare;
rtd->ops.trigger = soc_pcm_trigger;
rtd->ops.hw_free = soc_pcm_hw_free;
rtd->ops.close = soc_pcm_close;
rtd->ops.pointer = soc_pcm_pointer;
rtd->ops.ioctl = soc_pcm_ioctl
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops)--------------->
substream->ops = ops
platform->driver->pcm_new(rtd)
2.1.6 snd_card_register 会调用snd_device_register_all来对pcm设备和control 设备的注册
snd_device_register_all(card)