22. strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver)); 23.
24. ////(4)////
25. ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm); 26. if (ret) 27. goto err; 28. ////(2)////
29. ret = pxa2xx_ac97_hw_probe(dev); 30. if (ret) 31. goto err; 32.
33. ////(4)////
34. ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus); 35. if (ret)
36. goto err_remove;
37. memset(&ac97_template, 0, sizeof(ac97_template));
38. ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97); 39. if (ret)
40. goto err_remove; 41. ////(3)////
42. snprintf(card->shortname, sizeof(card->shortname), 43. \, snd_ac97_get_short_name(pxa2xx_ac97_ac97)); 44. snprintf(card->longname, sizeof(card->longname),
45. \, dev->dev.driver->name, card->mixername); 46.
47. if (pdata && pdata->codec_pdata[0])
48. snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]); 49. snd_card_set_dev(card, &dev->dev); 50. ////(5)////
51. ret = snd_card_register(card); 52. if (ret == 0) {
53. platform_set_drvdata(dev, card); 54. return 0; 55. } 56.
57. err_remove:
58. pxa2xx_ac97_hw_remove(dev); 59. err:
60. if (card)
61. snd_card_free(card); 62. err_dev: 63. return ret; 64. } 65.
11
66. static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) 67. {
68. struct snd_card *card = platform_get_drvdata(dev); 69.
70. if (card) {
71. snd_card_free(card);
72. platform_set_drvdata(dev, NULL); 73. pxa2xx_ac97_hw_remove(dev); 74. } 75.
76. return 0; 77. } 78.
79. static struct platform_driver pxa2xx_ac97_driver = { 80. .probe = pxa2xx_ac97_probe,
81. .remove = __devexit_p(pxa2xx_ac97_remove), 82. .driver = {
83. .name = \, 84. .owner = THIS_MODULE, 85. #ifdef CONFIG_PM
86. .pm = &pxa2xx_ac97_pm_ops, 87. #endif 88. }, 89. }; 90.
91. static int __init pxa2xx_ac97_init(void) 92. {
93. return platform_driver_register(&pxa2xx_ac97_driver); 94. } 95.
96. static void __exit pxa2xx_ac97_exit(void) 97. {
98. platform_driver_unregister(&pxa2xx_ac97_driver); 99. } 100.
101. module_init(pxa2xx_ac97_init); 102. module_exit(pxa2xx_ac97_exit); 103.
104. MODULE_AUTHOR(\);
105. MODULE_DESCRIPTION(\);
驱动程序通常由probe回调函数开始,对一下2.1中的步骤,是否有相似之处? 经过以上的创建步骤之后,声卡的逻辑结构如下图所示:
12
图 2.2.1 声卡的软件逻辑结构
下面的章节里我们分别讨论一下snd_card_create()和snd_card_register()这两个函数。
3. snd_card_create()
snd_card_create()在/sound/core/init.c中定义。 [cpp] view plain copy
1. /**
2. * snd_card_create - create and initialize a soundcard structure
3. * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] 4. * @xid: card identification (ASCII string) 5. * @module: top level module for locking
6. * @extra_size: allocate this extra size after the main soundcard structure
7. * @card_ret: the pointer to store the created card instance 8. *
9. * Creates and initializes a soundcard structure. 10. *
11. * The function allocates snd_card instance via kzalloc with the given
12. * space for the driver to use freely. The allocated struct is stored
13. * in the given card_ret pointer. 14. *
13
15. * Returns zero if successful or a negative error code.
16. */
17. int snd_card_create(int idx, const char *xid,
18. struct module *module, int extra_size, 19. struct snd_card **card_ret)
首先,根据extra_size参数的大小分配内存,该内存区可以作为芯片的专有数据使用(见前面的介绍): [c-sharp] view plain copy 1. card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); 2. if (!card)
3. return -ENOMEM; 拷贝声卡的ID字符串: [c-sharp] view plain copy 1. if (xid)
2. strlcpy(card->id, xid, sizeof(card->id)); 如果传入的声卡编号为-1,自动分配一个索引编号: [c-sharp] view plain copy 1. if (idx < 0) {
2. for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
3. /* idx == -1 == 0xffff means: take any free slot */
4. if (~snd_cards_lock & idx & 1< 5. if (module_slot_match(module, idx2)) { 6. idx = idx2; 7. break; 8. } 9. } 10. } 11. if (idx < 0) { 12. for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) 13. /* idx == -1 == 0xffff means: take any free slot */ 14. if (~snd_cards_lock & idx & 1< 14 16. idx = idx2; 17. break; 18. } 19. } 20. } 初始化snd_card结构中必要的字段: [c-sharp] view plain copy 1. card->number = idx; 2. card->module = module; 3. INIT_LIST_HEAD(&card->devices); 4. init_rwsem(&card->controls_rwsem); 5. rwlock_init(&card->ctl_files_rwlock); 6. INIT_LIST_HEAD(&card->controls); 7. INIT_LIST_HEAD(&card->ctl_files); 8. spin_lock_init(&card->files_lock); 9. INIT_LIST_HEAD(&card->files_list); 10. init_waitqueue_head(&card->shutdown_sleep); 11. #ifdef CONFIG_PM 12. mutex_init(&card->power_lock); 13. init_waitqueue_head(&card->power_sleep); 14. #endif 建立逻辑设备:Control [c-sharp] view plain copy 1. /* the control interface cannot be accessed from the user space until */ 2. /* snd_cards_bitmask and snd_cards are set with snd_card_register */ 3. err = snd_ctl_create(card); 建立proc文件中的info节点:通常就是/proc/asound/card0 [c-sharp] view plain copy 1. err = snd_info_card_create(card); 把第一步分配的内存指针放入private_data字段中: [c-sharp] view plain copy 15