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),
\ snprintf(card->longname, sizeof(card->longname),
\
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 = \ .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(\
MODULE_DESCRIPTION(\ 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, \ 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), \ snprintf(card->longname, sizeof(card->longname), \ 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 = \ .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(\
MODULE_DESCRIPTION(\
驱动程序通常由probe回调函数开始,对一下2.1中的步骤,是否有相似之处?
经过以上的创建步骤之后,声卡的逻辑结构如下图所示:
图 2.2.1 声卡的软件逻辑结构
下面的章节里我们分别讨论一下snd_card_create()和snd_card_register()这两个函数。
3. snd_card_create()
snd_card_create()在/sound/core/init.c中定义。
view plaincopy to clipboardprint? /**
* 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) /**
* 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. *