Linux ALSA架构:驱动综述(七)

Linux ALSA架构:驱动综述(七)

一、驱动综述

在声卡及设备、Platform & Codec驱动和Machine驱动中已经简单介绍了各个部分的实现。本节综合以上内容进行简单总结。

二、驱动实现过程

Machine驱动的probe会调用到snd_soc_bind_card。

snd_soc_bind_card(card);
    struct snd_soc_pcm_runtime *rtd;
    struct snd_soc_component *component;
    struct snd_soc_dai_link *dai_link;

    //为每个dai_link初始化一个rtd
    for_each_card_prelinks(card, i, dai_link)
        ret = snd_soc_add_pcm_runtime(card, dai_link);

    //初始化snd_card,并创建Control设备
    ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
            card->owner, 0, &card->snd_card);

    //为每个rtd创建对应的pcm设备
    for_each_card_rtds(card, rtd)
        ret = soc_init_pcm_runtime(card, rtd);

    //注册设备
    ret = snd_card_register(card->snd_card);

1. snd_soc_add_pcm_runtime对rtd的初始化

snd_soc_add_pcm_runtime
    rtd = soc_new_pcm_runtime(card, dai_link);
        struct snd_soc_pcm_runtime *rtd;
        struct snd_soc_component *component;
        struct device *dev;

        dev = kzalloc(sizeof(struct device), GFP_KERNEL);
        ret = device_register(dev);
        rtd = devm_kzalloc(dev, sizeof(*rtd) + sizeof(*component) * (dai_link->num_cpus +
                         dai_link->num_codecs + dai_link->num_platforms), GFP_KERNEL);
        rtd->dais = devm_kcalloc(dev, dai_link->num_cpus + dai_link->num_codecs,
                        sizeof(struct snd_soc_dai *), GFP_KERNEL);
        rtd->dai_link    = dai_link;
        ret = device_add_groups(dev, soc_dev_attr_groups);

        //把对应component加到rtd中
        //i = 0;(i < link->num_cpus) && (cpu = &link->cpus[i]); i++
        for_each_link_cpus(dai_link, i, cpu)
            // asoc_rtd_to_cpu(rtd, i) = rtd->dais[i]
            asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
            snd_soc_rtd_add_component(rtd, asoc_rtd_to_cpu(rtd, i)->component);
        ../codec & platform

2. snd_card_new 声卡初始化

snd_card_new
    struct snd_card *card;
    card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
    err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
    //初始化card参数
    ...
    // dev/snd里的controlC0设备
    err = snd_ctl_create(card);
        static const struct snd_device_ops ops = {
            .dev_free = snd_ctl_dev_free,
            .dev_register =    snd_ctl_dev_register,
            .dev_disconnect = snd_ctl_dev_disconnect,
        };
        dev_set_name(&card->ctl_dev, "controlC%d", card->number);
        err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
            struct snd_device *dev;
            struct list_head *p;
            dev = kzalloc(sizeof(*dev), GFP_KERNEL);
            ... //初始化dev
            dev->ops = ops;
            list_for_each_prev(p, &card->devices) {
            struct snd_device *pdev = list_entry(p, struct snd_device, list);
            list_add(&dev->list, p);

        err = snd_info_card_create(card);
            entry = create_subdir(card->module, str);

3. soc_init_pcm_runtime pcm初始化

soc_init_pcm_runtime
    struct snd_soc_dai_link *dai_link = rtd->dai_link;
    struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    struct snd_soc_component *component;

    ret = soc_new_pcm(rtd, num);
        snd_pcm_new(rtd->card->snd_card, new_name, num, playback, capture, &pcm);
            struct snd_pcm *pcm;
            staic const struct snd_device_ops ops = {
                .dev_free = snd_pcm_dev_free,
                .dev_register =    snd_pcm_dev_register,
                .dev_disconnect = snd_pcm_dev_disconnect,
            };
            pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
            err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count);
                struct snd_pcm_str *pstr = &pcm->streams[stream];
                struct snd_pcm_substream *substream, *prev;
                pstr->stream = stream;
                pstr->pcm = pcm;
                pstr->substream_count = substream_count;

            err = snd_device_new(card, SNDRV_DEV_PCM, pcm,
                             internal ? &internal_ops : &ops);

    rtd->pcm = pcm;
    pcm->private_data = rtd;

    //no dynamic
    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;

    if (playback)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
            substream->ops = ops;

    ret = snd_soc_pcm_component_new(rtd);
        //调用platform的pcm_construct函数
        ret = component->driver->pcm_construct(component, rtd);

4. snd_card_register 声卡注册

snd_card_register
    err = device_add(&card->card_dev);
    err = snd_device_register_all(card)
        list_for_each_entry(dev, &card->devices, list)
            err = __snd_device_register(dev);
                err = dev->ops->dev_register(dev);
                snd_pcm_dev_register(struct snd_device *device)
                    struct snd_pcm_substream *substream;
                    struct snd_pcm *pcm;
                    err = snd_pcm_add(pcm);
                    err = snd_register_device(devtype, pcm->card, pcm->device,
                              &snd_pcm_f_ops[cidx], pcm,
                              &pcm->streams[cidx].dev);
                        struct snd_minor *preg;
                        preg = kmalloc(sizeof *preg, GFP_KERNEL);
                        preg->f_ops = f_ops;
                        device->devt = MKDEV(major, minor);
                        err = device_add(device);
                        snd_minors[minor] = preg;
                    snd_pcm_timer_init(substream);

*snd_pcm_f_ops的借口如下:

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_poll,
        .unlocked_ioctl =    snd_pcm_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_poll,
        .unlocked_ioctl =    snd_pcm_ioctl,
        .compat_ioctl =     snd_pcm_ioctl_compat,
        .mmap =            snd_pcm_mmap,
        .fasync =        snd_pcm_fasync,
        .get_unmapped_area =    snd_pcm_get_unmapped_area,
    }
};

三、总结

本章简介总结了machine驱动与其他部分的联系。声卡注册之后,用户层可以调用对应的借口对设备进行操作。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值