zoukankan      html  css  js  c++  java
  • 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接口。

     



  • 相关阅读:
    例题6-8 Tree Uva548
    例题6-7 Trees on the level ,Uva122
    caffe Mac 安装
    Codeforces Round #467 (Div. 1) B. Sleepy Game
    Educational Codeforces Round37 E
    Educational Codeforces Round 36 (Rated for Div. 2) E. Physical Education Lessons
    Good Bye 2017 E. New Year and Entity Enumeration
    Good Bye 2017 D. New Year and Arbitrary Arrangement
    Codeforces Round #454 D. Seating of Students
    浙大紫金港两日游
  • 原文地址:https://www.cnblogs.com/-glb/p/13722228.html
Copyright © 2011-2022 走看看