创建pcm device

来源:互联网 发布:支持java的虚拟主机 编辑:程序博客网 时间:2024/06/16 07:07

声卡下面有多种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_cardsoc_probe_link_dais   soc_new_pcmsnd_pcm_new   _snd_pcm_newsnd_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 oksprd-codec-v3-vaudio <-> vaudio mapping okcodec-i2s-ext <-> vbc-r2p0-ad23 mapping okcodec-vaudio-ext <-> vaudio-ad23 mapping oksprd-codec-v3-fm <-> vbc-dfm mapping oknull-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 0
原创粉丝点击