asoc框架学习

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, &params)------->下面会调到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(&register_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(&register_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)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值