创建pcm device

声卡下面有多种device,最重要的是pcm和control两类。


先看pcm device

创建pcm

创建device最终使用的都是snd_device_new。常使用的是 snd_pcm_new来创建pcm device。(类似的还有snd_ctl_create)

先贴下调用关系

snd_soc_register_card
    snd_soc_instantiate_card
	soc_probe_link_dais
	   soc_new_pcm
		snd_pcm_new
		   _snd_pcm_new
			snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)
			snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)
			snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)
		rtd->ops.open       = soc_pcm_open;

在创建pcm是可以看到如下log

sprd-codec-v3-i2s <-> vbc-r2p0 mapping ok
sprd-codec-v3-vaudio <-> vaudio mapping ok
codec-i2s-ext <-> vbc-r2p0-ad23 mapping ok
codec-vaudio-ext <-> vaudio-ad23 mapping ok
sprd-codec-v3-fm <-> vbc-dfm mapping ok

null-codec-dai <-> i2s.0 mapping ok

分别对应vbc_r2p0_codec_v3_dai和all_i2s_dai两个dai.这里vbc_r2p0_codec_v3_dai中platform_name是 sprd-pcm-audio

注意snd_device_new最后一个参数

static struct snd_device_ops ops = {
        .dev_free = snd_pcm_dev_free,
        .dev_register = snd_pcm_dev_register,
        .dev_disconnect = snd_pcm_dev_disconnect,
}; 

static int snd_pcm_dev_register(struct snd_device *device)
{
        err = snd_register_device_for_dev(devtype, pcm->card,
                          pcm->device,
                          &snd_pcm_f_ops[cidx],
                          pcm, str, dev);
}

const struct file_operations snd_pcm_f_ops[2] = {
    {    
        .owner =        THIS_MODULE,
        .write =        snd_pcm_write,
        .aio_write =        snd_pcm_aio_write,
        .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,
        .aio_read =     snd_pcm_aio_read,
        .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 device(pcmC0D0p)就会调用这里的函数

看snd_pcm_write

snd_pcm_write
  snd_pcm_lib_write
     snd_pcm_lib_write1
       snd_pcm_start
          snd_pcm_action
            snd_pcm_action_start
               snd_pcm_do_start
                  substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
这个substream又 来自那?
看snd_pcm_write
snd_pcm_write
{
    struct snd_pcm_file *pcm_file;

    pcm_file = file->private_data;
    substream = pcm_file->substream;
}
关键是这个pcm_file,其实是来自snd_pcm_open_file

snd_pcm_open_substream(pcm, stream, file, &substream);
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
pcm_file->substream = substream;
而snd_pcm_open_file被snd_pcm_open调用,再往上是snd_pcm_playback_open
snd_pcm_playback_open是snd_pcm_f_ops的一个open函数 

再回到snd_soc_register_card,这里注册的card的dai中是.platform_name = "sprd-pcm-audio",

这个sprd-pcm-audio对于的pcm操作在那?

static struct snd_pcm_ops sprd_pcm_ops = {                                                                                                                                                                                                   
    .open = sprd_pcm_open,
    .close = sprd_pcm_close,
    .ioctl = snd_pcm_lib_ioctl,
    .hw_params = sprd_pcm_hw_params,
    .hw_free = sprd_pcm_hw_free,
    .prepare = sprd_pcm_prepare,
    .trigger = sprd_pcm_trigger,
    .pointer = sprd_pcm_pointer,
    .mmap = sprd_pcm_mmap,
};
static struct platform_driver sprd_pcm_driver = {
    .driver = {
           .name = "sprd-pcm-audio",
           .owner = THIS_MODULE,
           .of_match_table = of_match_ptr(sprd_pcm_of_match),
           },   

    .probe = sprd_soc_platform_probe,
    .remove = sprd_soc_platform_remove,
};

platform怎么和substream联系起来那? 

看snd_soc_instantiate_card。这个函数先调用soc_bind_dai_link,找到dai对应的platform,放到rtd中。

而substream来自与soc_new_pcm.soc_new_pcm第一个参数就是这个rtd

snd_soc_instantiate_card
        soc_bind_dai_link
           <strong>rtd</strong>->platform = platform;
	soc_probe_link_dais
	   soc_new_pcm(<strong>rtd</strong>, num);


DroidPhone的blog中有几个图片非常好,这里转一下

pcm的数据结构


创建pcm device


用户写数据的流程


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值