中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

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

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

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

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

        本文引用地址:http://www.antipu.com.cn/article/201612/341246.htm

          這時候可以創(chuàng)建聲卡的各種功能部件了,還記得開頭的snd_card結(jié)構(gòu)體的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)建步驟之后,聲卡的邏輯結(jié)構(gòu)如下圖所示:

            

         

          圖 2.2.1 聲卡的軟件邏輯結(jié)構(gòu)

          下面的章節(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結(jié)構(gòu)中必要的字段:

          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

          建立邏輯設(shè)備: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下的設(shè)備:

          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()也決定了相應(yīng)的設(shè)備節(jié)點也將會出現(xiàn)在/dev/snd/下面。

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

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

          return err;

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

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


        上一頁 1 2 下一頁

        關(guān)鍵詞: Linux ALSA

        評論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉