在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

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

            Linux ALSA聲卡驅(qū)動(dòng)之三:PCM設(shè)備的創(chuàng)建

            作者: 時(shí)間:2016-12-14 來(lái)源:網(wǎng)絡(luò) 收藏

              4. 設(shè)備文件節(jié)點(diǎn)的建立(dev/snd/pcmCxxDxxp、pcmCxxDxxc)

            本文引用地址:http://www.biyoush.com/article/201612/341593.htm

              4.1 struct snd_minor

              每個(gè)snd_minor結(jié)構(gòu)體保存了聲卡下某個(gè)邏輯設(shè)備的上下文信息,他在邏輯設(shè)備建立階段被填充,在邏輯設(shè)備被使用時(shí)就可以從該結(jié)構(gòu)體中得到相應(yīng)的信息。pcm設(shè)備也不例外,也需要使用該結(jié)構(gòu)體。該結(jié)構(gòu)體在include/sound/core.h中定義。

              [c-sharp] view plain copystruct snd_minor {

              int type; /* SNDRV_DEVICE_TYPE_XXX */

              int card; /* card number */

              int device; /* device number */

              const struct file_operations *f_ops; /* file operations */

              void *private_data; /* private data for f_ops->open */

              struct device *dev; /* device for sysfs */

              };

              在sound/sound.c中定義了一個(gè)snd_minor指針的全局?jǐn)?shù)組:

              [c-sharp] view plain copystatic struct snd_minor *snd_minors[256];

              前面說(shuō)過(guò),在聲卡的注冊(cè)階段(snd_card_register),會(huì)調(diào)用pcm的回調(diào)函數(shù)snd_pcm_dev_register(),這個(gè)函數(shù)里會(huì)調(diào)用函數(shù)snd_register_device_for_dev():

              [c-sharp] view plain copystatic int snd_pcm_dev_register(struct snd_device *device)

              {

              ......

              /* register pcm */

              err = snd_register_device_for_dev(devtype, pcm->card,

              pcm->device,

              &snd_pcm_f_ops[cidx],

              pcm, str, dev);

              ......

              }

              我們?cè)龠M(jìn)入snd_register_device_for_dev():

              [c-sharp] view plain copyint 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;

              if (snd_BUG_ON(!name))

              return -EINVAL;

              preg = kmalloc(sizeof *preg, GFP_KERNEL);

              if (preg == NULL)

              return -ENOMEM;

              preg->type = type;

              preg->card = card ? card->number : -1;

              preg->device = dev;

              preg->f_ops = f_ops;

              preg->private_data = private_data;

              mutex_lock(&sound_mutex);

              #ifdef CONFIG_SND_DYNAMIC_MINORS

              minor = snd_find_free_minor();

              #else

              minor = snd_kernel_minor(type, card, dev);

              if (minor >= 0 && snd_minors[minor])

              minor = -EBUSY;

              #endif

              if (minor < 0) {

              mutex_unlock(&sound_mutex);

              kfree(preg);

              return minor;

              }

              snd_minors[minor] = preg;

              preg->dev = device_create(sound_class, device, MKDEV(major, minor),

              private_data, "%s", name);

              if (IS_ERR(preg->dev)) {

              snd_minors[minor] = NULL;

              mutex_unlock(&sound_mutex);

              minor = PTR_ERR(preg->dev);

              kfree(preg);

              return minor;

              }

              mutex_unlock(&sound_mutex);

              return 0;

              }

              首先,分配并初始化一個(gè)snd_minor結(jié)構(gòu)中的各字段

              type:SNDRV_DEVICE_TYPE_PCM_PLAYBACK/SNDRV_DEVICE_TYPE_PCM_CAPTURE

              card: card的編號(hào)

              device:pcm實(shí)例的編號(hào),大多數(shù)情況為0

              f_ops:snd_pcm_f_ops

              private_data:指向該pcm的實(shí)例

              根據(jù)type,card和pcm的編號(hào),確定數(shù)組的索引值minor,minor也作為pcm設(shè)備的此設(shè)備號(hào)

              把該snd_minor結(jié)構(gòu)的地址放入全局?jǐn)?shù)組snd_minors[minor]中

              最后,調(diào)用device_create創(chuàng)建設(shè)備節(jié)點(diǎn)

              4.2 設(shè)備文件的建立

              在4.1節(jié)的最后,設(shè)備文件已經(jīng)建立,不過(guò)4.1節(jié)的重點(diǎn)在于snd_minors數(shù)組的賦值過(guò)程,在本節(jié)中,我們把重點(diǎn)放在設(shè)備文件中。

              回到pcm的回調(diào)函數(shù)snd_pcm_dev_register()中:

              [c-sharp] view plain copystatic int snd_pcm_dev_register(struct snd_device *device)

              {

              int cidx, err;

              char str[16];

              struct snd_pcm *pcm;

              struct device *dev;

              pcm = device->device_data;

              ......

              for (cidx = 0; cidx < 2; cidx++) {

              ......

              switch (cidx) {

              case SNDRV_PCM_STREAM_PLAYBACK:

              sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);

              devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;

              break;

              case SNDRV_PCM_STREAM_CAPTURE:

              sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);

              devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;

              break;

              }

              /* device pointer to use, pcm->dev takes precedence if

              * it is assigned, otherwise fall back to card's device

              * if possible */

              dev = pcm->dev;

              if (!dev)

              dev = snd_card_get_device_link(pcm->card);

              /* register pcm */

              err = snd_register_device_for_dev(devtype, pcm->card,

              pcm->device,

              &snd_pcm_f_ops[cidx],

              pcm, str, dev);

              ......

              }

              ......

              }

              以上代碼我們可以看出,對(duì)于一個(gè)pcm設(shè)備,可以生成兩個(gè)設(shè)備文件,一個(gè)用于playback,一個(gè)用于capture,代碼中也確定了他們的命名規(guī)則:

              playback -- pcmCxDxp,通常系統(tǒng)中只有一各聲卡和一個(gè)pcm,它就是pcmC0D0p

              capture -- pcmCxDxc,通常系統(tǒng)中只有一各聲卡和一個(gè)pcm,它就是pcmC0D0c

              snd_pcm_f_ops

              snd_pcm_f_ops是一個(gè)標(biāo)準(zhǔn)的文件系統(tǒng)file_operations結(jié)構(gòu)數(shù)組,它的定義在sound/core/pcm_native.c中:

              [c-sharp] view plain copyconst struct file_operations snd_pcm_f_ops[2] = {

              {

              .owner = THIS_MODULE,

              .write = snd_pcm_write,

              .aio_write = snd_pcm_aio_write,

              .open = snd_pcm_playback_open,

              .release = snd_pcm_release,

              .llseek = no_llseek,

              .poll = snd_pcm_playback_poll,

              .unlocked_ioctl = snd_pcm_playback_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,

              .aio_read = snd_pcm_aio_read,

              .open = snd_pcm_capture_open,

              .release = snd_pcm_release,

              .llseek = no_llseek,

              .poll = snd_pcm_capture_poll,

              .unlocked_ioctl = snd_pcm_capture_ioctl,

              .compat_ioctl = snd_pcm_ioctl_compat,

              .mmap = snd_pcm_mmap,

              .fasync = snd_pcm_fasync,

              .get_unmapped_area = snd_pcm_get_unmapped_area,

              }

              };

              snd_pcm_f_ops作為snd_register_device_for_dev的參數(shù)被傳入,并被記錄在snd_minors[minor]中的字段f_ops中。最后,在snd_register_device_for_dev中創(chuàng)建設(shè)備節(jié)點(diǎn):

              [c-sharp] view plain copysnd_minors[minor] = preg;

              preg->dev = device_create(sound_class, device, MKDEV(major, minor),

              private_data, "%s", name);

              4.3 層層深入,從應(yīng)用程序到驅(qū)動(dòng)層pcm

              4.3.1 字符設(shè)備注冊(cè)

              在sound/core/sound.c中有alsa_sound_init()函數(shù),定義如下:

              [c-sharp] view plain copystatic 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/n", major);

              return -EIO;

              }

              if (snd_info_init() < 0) {

              unregister_chrdev(major, "alsa");

              return -ENOMEM;

              }

              snd_info_minor_register();

              return 0;

              }

              register_chrdev中的參數(shù)major與之前創(chuàng)建pcm設(shè)備是device_create時(shí)的major是同一個(gè),這樣的結(jié)果是,當(dāng)應(yīng)用程序open設(shè)備文件/dev/snd/pcmCxDxp時(shí),會(huì)進(jìn)入snd_fops的open回調(diào)函數(shù),我們將在下一節(jié)中講述open的過(guò)程。

              4.3.2 打開pcm設(shè)備

              從上一節(jié)中我們得知,open一個(gè)pcm設(shè)備時(shí),將會(huì)調(diào)用snd_fops的open回調(diào)函數(shù),我們先看看snd_fops的定義:

              [c-sharp] view plain copystatic const struct file_operations snd_fops =

              {

              .owner = THIS_MODULE,

              .open = snd_open

              };

              跟入snd_open函數(shù),它首先從inode中取出此設(shè)備號(hào),然后以次設(shè)備號(hào)為索引,從snd_minors全局?jǐn)?shù)組中取出當(dāng)初注冊(cè)pcm設(shè)備時(shí)填充的snd_minor結(jié)構(gòu)(參看4.1節(jié)的內(nèi)容),然后從snd_minor結(jié)構(gòu)中取出pcm設(shè)備的f_ops,并且把file->f_op替換為pcm設(shè)備的f_ops,緊接著直接調(diào)用pcm設(shè)備的f_ops->open(),然后返回。因?yàn)閒ile->f_op已經(jīng)被替換,以后,應(yīng)用程序的所有read/write/ioctl調(diào)用都會(huì)進(jìn)入pcm設(shè)備自己的回調(diào)函數(shù)中,也就是4.2節(jié)中提到的snd_pcm_f_ops結(jié)構(gòu)中定義的回調(diào)。

              [c-sharp] view plain copystatic 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;

              int err = 0;

              if (minor >= ARRAY_SIZE(snd_minors))

              return -ENODEV;

              mutex_lock(&sound_mutex);

              mptr = snd_minors[minor];

              if (mptr == NULL) {

              mptr = autoload_device(minor);

              if (!mptr) {

              mutex_unlock(&sound_mutex);

              return -ENODEV;

              }

              }

              old_fops = file->f_op;

              file->f_op = fops_get(mptr->f_ops);

              if (file->f_op == NULL) {

              file->f_op = old_fops;

              err = -ENODEV;

              }

              mutex_unlock(&sound_mutex);

              if (err < 0)

              return err;

              if (file->f_op->open) {

              err = file->f_op->open(inode, file);

              if (err) {

              fops_put(file->f_op);

              file->f_op = fops_get(old_fops);

              }

              }

              fops_put(old_fops);

              return err;

              }

              下面的序列圖展示了應(yīng)用程序如何最終調(diào)用到snd_pcm_f_ops結(jié)構(gòu)中的回調(diào)函數(shù):

              圖4.3.2.1 應(yīng)用程序操作pcm設(shè)備


            上一頁(yè) 1 2 下一頁(yè)

            關(guān)鍵詞: Linux ALSA

            評(píng)論


            相關(guān)推薦

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

            關(guān)閉