• ALSA驱动框架


     一.前言

    在alsa架构中,当应用程序调用open、read、write时,将调用驱动程序中的相应接口,本篇博客就从驱动程序中的snd_fops结构体开始说起。

    二.  入口函数alsa_sound_init

    kernel/linux-3.4.2/sound/core/Sound.c

    1. snd_fops结构体

    static const struct file_operations snd_fops =
    {
        .owner =   THIS_MODULE,
        .open =    snd_open,
        .llseek =  noop_llseek,
    };
    static int __init alsa_sound_init(void)
    {
        snd_major = major;
        snd_ecards_limit = cards_limit;
        if (register_chrdev(major, "alsa", &snd_fops)) {
            snd_printk(KERN_ERR "unable to register native major device number %d
    ", major);
    }

    snp_fops结构体最终通过register_chrdev函数注册到系统中。从这个地方可以看出alsa驱动也是字符设备驱动。

    在snd_fops中只有open函数,并没有读写函数。可以猜测的出来,这个snd_fops中的open函数只是起到一个中转的作用,它肯定会找到一个新的file_operation结构体。

    static int snd_open(struct inode *inode, struct file *file)
    {
        unsigned int minor = iminor(inode);
        struct snd_minor *mptr = NULL;
        const struct file_operations *old_fops;
    
        //以次设备号minor在数组snd_minors中找到一项。
        mptr = snd_minors[minor];
        
        old_fops = file->f_op;
        
        //取出file_operation结构体
        file->f_op = fops_get(mptr->f_ops);
        
        if (file->f_op->open) {
            err = file->f_op->open(inode, file);
    }

    2.数组snd_minors数组的设置

    /**
     * snd_register_device_for_dev - Register the ALSA device file for the card
     * @type: the device type, SNDRV_DEVICE_TYPE_XXX
     * @card: the card instance
     * @dev: the device index
     * @f_ops: the file operations
     * @private_data: user pointer for f_ops->open()
     * @name: the device file name
     * @device: the &struct device to link this new device to
     *
     * Registers an ALSA device file for the given card.
     * The operators have to be set in reg parameter.
     *
     * Returns zero if successful, or a negative error code on failure.
     */
    int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
                    const struct file_operations *f_ops,
                    void *private_data,
                    const char *name, struct device *device)
    {
        int minor;
        struct snd_minor *preg;
    
        preg = kmalloc(sizeof *preg, GFP_KERNEL);
        
        preg->type = type;
        preg->card = card ? card->number : -1;
        preg->device = dev;
        preg->f_ops = f_ops;
        preg->private_data = private_data;
    
    #ifdef CONFIG_SND_DYNAMIC_MINORS
        minor = snd_find_free_minor(type);
    #else
        minor = snd_kernel_minor(type, card, dev);
    #endif
        
        snd_minors[minor] = preg;
        preg->dev = device_create(sound_class, device, MKDEV(major, minor),
                      private_data, "%s", name);
        return 0;
    }

    3.函数snd_register_device_for_dev

    函数snd_register_device_for_dev在两个地方被调用:
    1)snd_register_device:声卡设备的控制接口
    2)snd_pcm_dev_register:声卡设备的数据接口

    3.1 snd_register_device

    kernel/linux-3.4.2/include/sound/Core.h
    static inline int snd_register_device(int type, struct snd_card *card, int dev,
                          const struct file_operations *f_ops,
                          void *private_data,
                          const char *name)
    {
        return snd_register_device_for_dev(type, card, dev, f_ops,
                           private_data, name,
                           snd_card_get_device_link(card));
    }

     3.1.1函数snd_register_device

    kernel/linux-3.4.2/sound/core/Control.c

    /*
     * registration of the control device
     */
    static int snd_ctl_dev_register(struct snd_device *device)
    {
        struct snd_card *card = device->device_data;
        int err, cardnum;
        char name[16];
    
        cardnum = card->number;
        sprintf(name, "controlC%i", cardnum);
        if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
                           &snd_ctl_f_ops, card, name)) < 0)
            return err;
        return 0;
    }

    3.1.2函数snd_ctl_dev_register

    /*
     * create control core:
     * called from init.c
     */
    int snd_ctl_create(struct snd_card *card)
    {
        static struct snd_device_ops ops = {
            .dev_free = snd_ctl_dev_free,
            .dev_register =    snd_ctl_dev_register,
            .dev_disconnect = snd_ctl_dev_disconnect,
        };
    
        return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
    }

    3.1.3 snd_ctl_create

    /**
     *  snd_card_create - create and initialize a soundcard structure
     *  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
     *  @xid: card identification (ASCII string)
     *  @module: top level module for locking
     *  @extra_size: allocate this extra size after the main soundcard structure
     *  @card_ret: the pointer to store the created card instance
     *
     *  Creates and initializes a soundcard structure.
     *
     *  The function allocates snd_card instance via kzalloc with the given
     *  space for the driver to use freely.  The allocated struct is stored
     *  in the given card_ret pointer.
     *
     *  Returns zero if successful or a negative error code.
     */
    int snd_card_create(int idx, const char *xid,
                struct module *module, int extra_size,
                struct snd_card **card_ret)
    {
        struct snd_card *card;
    
        card->number = idx;
        card->module = module;
    
        /* the control interface cannot be accessed from the user space until */
        /* snd_cards_bitmask and snd_cards are set with snd_card_register */
        err = snd_ctl_create(card);
    
    }

    3.1.4 函数snd_card_create

    3.2  函数snd_pcm_dev_register

    kernel/linux-3.4.2/sound/core/Pcm.c

    static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
            int playback_count, int capture_count, bool internal,
            struct snd_pcm **rpcm)
    {
        struct snd_pcm *pcm;
        int err;
        static struct snd_device_ops ops = {
            .dev_free = snd_pcm_dev_free,
            .dev_register =    snd_pcm_dev_register,
            .dev_disconnect = snd_pcm_dev_disconnect,
        };
    }

    3.2.1  函数_snd_pcm_new

    /**
     * snd_pcm_new - create a new PCM instance
     * @card: the card instance
     * @id: the id string
     * @device: the device index (zero based)
     * @playback_count: the number of substreams for playback
     * @capture_count: the number of substreams for capture
     * @rpcm: the pointer to store the new pcm instance
     *
     * Creates a new PCM instance.
     *
     * The pcm operators have to be set afterwards to the new instance
     * via snd_pcm_set_ops().
     *
     * Returns zero if successful, or a negative error code on failure.
     */
    int snd_pcm_new(struct snd_card *card, const char *id, int device,
            int playback_count, int capture_count, struct snd_pcm **rpcm)
    {
        return _snd_pcm_new(card, id, device, playback_count, capture_count,
                false, rpcm);
    }

    3.2.2函数snd_pcm_new

    有很多文件调用了snd_pcm_new接口,对应不同的声卡。某个声卡驱动程序中调用了snd_pcm_new接口。

     



  • 相关阅读:
    Swift_数据存储
    Swift_零碎知识
    Flutter安装与使用
    供热
    iOS_2022_动画
    依赖管理
    Swift_协议
    Swift_网络请求
    数据转换的使用
    Map相关、MapUtils、MultiMap、LazyMap、BidiMap
  • 原文地址:https://www.cnblogs.com/-glb/p/13722228.html
Copyright © 2020-2023  润新知