Linux ALSA声卡驱动详细分析(6)

2019-01-27 16:59

4.2 设备文件的建立

在4.1节的最后,设备文件已经建立,不过4.1节的重点在于snd_minors数组的赋值过程,在本节中,我们把重点放在设备文件中。 回到pcm的回调函数snd_pcm_dev_register()中: [c-sharp] view plain copy

1. static int snd_pcm_dev_register(struct snd_device *device) 2. {

3. int cidx, err; 4. char str[16];

5. struct snd_pcm *pcm; 6. struct device *dev; 7.

8. pcm = device->device_data; 9. ...... 10. for (cidx = 0; cidx < 2; cidx++) { 11. ...... 12. switch (cidx) { 13. case SNDRV_PCM_STREAM_PLAYBACK: 14. sprintf(str, \, pcm->card->number, pcm->de

vice); 15. devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; 16. break; 17. case SNDRV_PCM_STREAM_CAPTURE: 18. sprintf(str, \, pcm->card->number, pcm->de

vice); 19. devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; 20. break; 21. } 22. /* device pointer to use, pcm->dev takes precedence if 23. * it is assigned, otherwise fall back to card's device 24. * if possible */ 25. dev = pcm->dev; 26. if (!dev) 27. dev = snd_card_get_device_link(pcm->card); 28. /* register pcm */ 29. err = snd_register_device_for_dev(devtype, pcm->card, 30. pcm->device, 31. &snd_pcm_f_ops[cidx], 32. pcm, str, dev); 33. ......

26

34. } 35. ...... 36. }

以上代码我们可以看出,对于一个pcm设备,可以生成两个设备文件,一个用于playback,一个用于capture,代码中也确定了他们的命名规则:

?

playback -- pcmCxDxp,通常系统中只有一各声卡和一个pcm,它就是pcmC0D0p

capture -- pcmCxDxc,通常系统中只有一各声卡和一个pcm,它就是pcmC0D0c

?

snd_pcm_f_ops

snd_pcm_f_ops是一个标准的文件系统file_operations结构数组,它的定义在sound/core/pcm_native.c中: [c-sharp] view plain copy

1. const struct file_operations snd_pcm_f_ops[2] = { 2. {

3. .owner = THIS_MODULE, 4. .write = snd_pcm_write,

5. .aio_write = snd_pcm_aio_write, 6. .open = snd_pcm_playback_open, 7. .release = snd_pcm_release, 8. .llseek = no_llseek,

9. .poll = snd_pcm_playback_poll,

10. .unlocked_ioctl = snd_pcm_playback_ioctl, 11. .compat_ioctl = snd_pcm_ioctl_compat, 12. .mmap = snd_pcm_mmap, 13. .fasync = snd_pcm_fasync,

14. .get_unmapped_area = snd_pcm_get_unmapped_area,

15. }, 16. {

17. .owner = THIS_MODULE, 18. .read = snd_pcm_read,

19. .aio_read = snd_pcm_aio_read,

20. .open = snd_pcm_capture_open, 21. .release = snd_pcm_release,

27

22. .llseek = no_llseek,

23. .poll = snd_pcm_capture_poll,

24. .unlocked_ioctl = snd_pcm_capture_ioctl, 25. .compat_ioctl = snd_pcm_ioctl_compat, 26. .mmap = snd_pcm_mmap, 27. .fasync = snd_pcm_fasync,

28. .get_unmapped_area = snd_pcm_get_unmapped_area,

29. } 30. };

snd_pcm_f_ops作为snd_register_device_for_dev的参数被传入,并被记录在snd_minors[minor]中的字段f_ops中。最后,在snd_register_device_for_dev中创建设备节点:

[c-sharp] view plain copy

1. snd_minors[minor] = preg;

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

3. private_data, \, name); 4.3 层层深入,从应用程序到驱动层pcm 4.3.1 字符设备注册

在sound/core/sound.c中有alsa_sound_init()函数,定义如下: [c-sharp] view plain copy

1. static int __init alsa_sound_init(void) 2. {

3. snd_major = major;

4. snd_ecards_limit = cards_limit;

5. if (register_chrdev(major, \, &snd_fops)) { 6. snd_printk(KERN_ERR \jor device number %d/n\, major); 7. return -EIO; 8. }

9. if (snd_info_init() < 0) {

10. unregister_chrdev(major, \); 11. return -ENOMEM; 12. }

13. snd_info_minor_register(); 14. return 0;

28

15. }

register_chrdev中的参数major与之前创建pcm设备是device_create时的major是同一个,这样的结果是,当应用程序open设备文件/dev/snd/pcmCxDxp时,会进入snd_fops的open回调函数,我们将在下一节中讲述open的过程。 4.3.2 打开pcm设备

从上一节中我们得知,open一个pcm设备时,将会调用snd_fops的open回调函数,我们先看看snd_fops的定义: [c-sharp] view plain copy

1. static const struct file_operations snd_fops = 2. {

3. .owner = THIS_MODULE, 4. .open = snd_open 5. };

跟入snd_open函数,它首先从inode中取出此设备号,然后以次设备号为索引,从snd_minors全局数组中取出当初注册pcm设备时填充的snd_minor结构(参看4.1节的内容),然后从snd_minor结构中取出pcm设备的f_ops,并且把file->f_op替换为pcm设备的f_ops,紧接着直接调用pcm设备的f_ops->open(),然后返回。因为file->f_op已经被替换,以后,应用程序的所有read/write/ioctl调用都会进入pcm设备自己的回调函数中,也就是4.2节中提到的snd_pcm_f_ops结构中定义的回调。 [c-sharp] view plain copy

1. static int snd_open(struct inode *inode, struct file *fil

e) 2. {

3. unsigned int minor = iminor(inode); 4. struct snd_minor *mptr = NULL;

5. const struct file_operations *old_fops; 6. int err = 0; 7.

8. if (minor >= ARRAY_SIZE(snd_minors)) 9. return -ENODEV;

10. mutex_lock(&sound_mutex); 11. mptr = snd_minors[minor]; 12. if (mptr == NULL) {

29

13. mptr = autoload_device(minor); 14. if (!mptr) {

15. mutex_unlock(&sound_mutex); 16. return -ENODEV; 17. } 18. }

19. old_fops = file->f_op;

20. file->f_op = fops_get(mptr->f_ops); 21. if (file->f_op == NULL) { 22. file->f_op = old_fops; 23. err = -ENODEV; 24. }

25. mutex_unlock(&sound_mutex); 26. if (err < 0) 27. return err; 28.

29. if (file->f_op->open) {

30. err = file->f_op->open(inode, file); 31. if (err) {

32. fops_put(file->f_op);

33. file->f_op = fops_get(old_fops); 34. } 35. }

36. fops_put(old_fops); 37. return err; 38. }

下面的序列图展示了应用程序如何最终调用到snd_pcm_f_ops结构中的回调函数:

30


Linux ALSA声卡驱动详细分析(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:乡镇2014年上半年工作总结 - 0

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: