<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > Linux ALSA聲卡驅(qū)動之二:聲卡的創(chuàng)建

          Linux ALSA聲卡驅(qū)動之二:聲卡的創(chuàng)建

          作者: 時間:2016-12-07 來源:網(wǎng)絡 收藏

            2.1.4. 第四步,創(chuàng)建聲卡的功能部件(邏輯設備),例如PCM,Mixer,MIDI等

          本文引用地址:http://www.ex-cimer.com/article/201612/341246.htm

            這時候可以創(chuàng)建聲卡的各種功能部件了,還記得開頭的snd_card結構體的devices字段嗎?每一種部件的創(chuàng)建最終會調(diào)用snd_device_new()來生成一個snd_device實例,并把該實例鏈接到snd_card的devices鏈表中。

            通常,alsa-driver的已經(jīng)提供了一些常用的部件的創(chuàng)建函數(shù),而不必直接調(diào)用snd_device_new(),比如:

            PCM ---- snd_pcm_new()

            RAWMIDI -- snd_rawmidi_new()

            CONTROL -- snd_ctl_create()

            TIMER -- snd_timer_new()

            INFO -- snd_card_proc_new()

            JACK -- snd_jack_new()

            2.1.5. 第五步,注冊聲卡

            err = snd_card_register(card);

            if (err < 0) {

            snd_card_free(card);

            return err;

            }

            2.2. 一個實際的例子

            我把/sound/arm/pxa2xx-ac97.c的部分代碼貼上來:

            static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)

            {

            struct snd_card *card;

            struct snd_ac97_bus *ac97_bus;

            struct snd_ac97_template ac97_template;

            int ret;

            pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;

            if (dev->id >= 0) {

            dev_err(&dev->dev, "PXA2xx has only one AC97 port./n");

            ret = -ENXIO;

            goto err_dev;

            }

            ////(1)////

            ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,

            THIS_MODULE, 0, &card);

            if (ret < 0)

            goto err;

            card->dev = &dev->dev;

            ////(3)////

            strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver));

            ////(4)////

            ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);

            if (ret)

            goto err;

            ////(2)////

            ret = pxa2xx_ac97_hw_probe(dev);

            if (ret)

            goto err;

            ////(4)////

            ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);

            if (ret)

            goto err_remove;

            memset(&ac97_template, 0, sizeof(ac97_template));

            ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);

            if (ret)

            goto err_remove;

            ////(3)////

            snprintf(card->shortname, sizeof(card->shortname),

            "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));

            snprintf(card->longname, sizeof(card->longname),

            "%s (%s)", dev->dev.driver->name, card->mixername);

            if (pdata && pdata->codec_pdata[0])

            snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]);

            snd_card_set_dev(card, &dev->dev);

            ////(5)////

            ret = snd_card_register(card);

            if (ret == 0) {

            platform_set_drvdata(dev, card);

            return 0;

            }

            err_remove:

            pxa2xx_ac97_hw_remove(dev);

            err:

            if (card)

            snd_card_free(card);

            err_dev:

            return ret;

            }

            static int __devexit pxa2xx_ac97_remove(struct platform_device *dev)

            {

            struct snd_card *card = platform_get_drvdata(dev);

            if (card) {

            snd_card_free(card);

            platform_set_drvdata(dev, NULL);

            pxa2xx_ac97_hw_remove(dev);

            }

            return 0;

            }

            static struct platform_driver pxa2xx_ac97_driver = {

            .probe = pxa2xx_ac97_probe,

            .remove = __devexit_p(pxa2xx_ac97_remove),

            .driver = {

            .name = "pxa2xx-ac97",

            .owner = THIS_MODULE,

            #ifdef CONFIG_PM

            .pm = &pxa2xx_ac97_pm_ops,

            #endif

            },

            };

            static int __init pxa2xx_ac97_init(void)

            {

            return platform_driver_register(&pxa2xx_ac97_driver);

            }

            static void __exit pxa2xx_ac97_exit(void)

            {

            platform_driver_unregister(&pxa2xx_ac97_driver);

            }

            module_init(pxa2xx_ac97_init);

            module_exit(pxa2xx_ac97_exit);

            MODULE_AUTHOR("Nicolas Pitre");

            MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");

            驅(qū)動程序通常由probe回調(diào)函數(shù)開始,對一下2.1中的步驟,是否有相似之處?

            經(jīng)過以上的創(chuàng)建步驟之后,聲卡的邏輯結構如下圖所示:

              

           

            圖 2.2.1 聲卡的軟件邏輯結構

            下面的章節(jié)里我們分別討論一下snd_card_create()和snd_card_register()這兩個函數(shù)。

            3. snd_card_create()

            snd_card_create()在/sound/core/init.c中定義。

            /**

            * 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)

            首先,根據(jù)extra_size參數(shù)的大小分配內(nèi)存,該內(nèi)存區(qū)可以作為芯片的專有數(shù)據(jù)使用(見前面的介紹):

            card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);

            if (!card)

            return -ENOMEM;

            拷貝聲卡的ID字符串:

            if (xid)

            strlcpy(card->id, xid, sizeof(card->id));

            如果傳入的聲卡編號為-1,自動分配一個索引編號:

            if (idx < 0) {

            for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)

            /* idx == -1 == 0xffff means: take any free slot */

            if (~snd_cards_lock & idx & 1<

            if (module_slot_match(module, idx2)) {

            idx = idx2;

            break;

            }

            }

            }

            if (idx < 0) {

            for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)

            /* idx == -1 == 0xffff means: take any free slot */

            if (~snd_cards_lock & idx & 1<

            if (!slots[idx2] || !*slots[idx2]) {

            idx = idx2;

            break;

            }

            }

            }

            初始化snd_card結構中必要的字段:

            card->number = idx;

            card->module = module;

            INIT_LIST_HEAD(&card->devices);

            init_rwsem(&card->controls_rwsem);

            rwlock_init(&card->ctl_files_rwlock);

            INIT_LIST_HEAD(&card->controls);

            INIT_LIST_HEAD(&card->ctl_files);

            spin_lock_init(&card->files_lock);

            INIT_LIST_HEAD(&card->files_list);

            init_waitqueue_head(&card->shutdown_sleep);

            #ifdef CONFIG_PM

            mutex_init(&card->power_lock);

            init_waitqueue_head(&card->power_sleep);

            #endif

            建立邏輯設備:Control

            /* 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);

            建立proc文件中的info節(jié)點:通常就是/proc/asound/card0

            err = snd_info_card_create(card);

            把第一步分配的內(nèi)存指針放入private_data字段中:

            if (extra_size > 0)

            card->private_data = (char *)card + sizeof(struct snd_card);

            4. snd_card_register()

            snd_card_create()在/sound/core/init.c中定義。

            /**

            * snd_card_register - register the soundcard

            * @card: soundcard structure

            *

            * This function registers all the devices assigned to the soundcard.

            * Until calling this, the  control interface is blocked from the

            * external accesses. Thus, you should call this function at the end

            * of the initialization of the card.

            *

            * Returns zero otherwise a negative error code if the registrain failed.

            */

            int snd_card_register(struct snd_card *card)

            首先,創(chuàng)建sysfs下的設備:

            if (!card->card_dev) {

            card->card_dev = device_create(sound_class, card->dev,

            MKDEV(0, 0), card,

            "card%i", card->number);

            if (IS_ERR(card->card_dev))

            card->card_dev = NULL;

            }

            其中,sound_class是在/sound/sound_core.c中創(chuàng)建的:

            static char *sound_devnode(struct device *dev, mode_t *mode)

            {

            if (MAJOR(dev->devt) == SOUND_MAJOR)

            return NULL;

            return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));

            }

            static int __init init_soundcore(void)

            {

            int rc;

            rc = init_oss_soundcore();

            if (rc)

            return rc;

            sound_class = class_create(THIS_MODULE, "sound");

            if (IS_ERR(sound_class)) {

            cleanup_oss_soundcore();

            return PTR_ERR(sound_class);

            }

            sound_class->devnode = sound_devnode;

            return 0;

            }

            由此可見,聲卡的class將會出現(xiàn)在文件系統(tǒng)的/sys/class/sound/下面,并且,sound_devnode()也決定了相應的設備節(jié)點也將會出現(xiàn)在/dev/snd/下面。

            接下來的步驟,通過snd_device_register_all()注冊所有掛在該聲卡下的邏輯設備,snd_device_register_all()實際上是通過snd_card的devices鏈表,遍歷所有的snd_device,并且調(diào)用snd_device的ops->dev_register()來實現(xiàn)各自設備的注冊的。

            if ((err = snd_device_register_all(card)) < 0)

            return err;

            最后就是建立一些相應的proc和sysfs下的文件或?qū)傩怨?jié)點,代碼就不貼了。

            至此,整個聲卡完成了建立過程。


          上一頁 1 2 下一頁

          關鍵詞: Linux ALSA

          評論


          相關推薦

          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();