alsa driver--card
https://www.kernel.org/doc/html/v4.11/sound/kernel-api/writing-an-alsa-driver.html
1.创建声卡
snd_card是对声卡硬件抽象出来的结构体,几乎所有与声音相关的逻辑设备都是在snd_card的管理之下,声卡驱动的第一个动作通常就是创建一个snd_card结构体。
我们可以通过调用snd_card_new来创建一个snd_card结构体。
struct snd_card *card; int err; err = snd_card_new(&pci->dev, index, id, module, extra_size, &card);
/**
* snd_card_new - create and initialize a soundcard structure
* @parent: the parent device object
* @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
*/
int snd_card_new(struct device *parent, int idx, const char *xid, struct module *module, int extra_size, struct snd_card **card_ret)
这里extra_size是为card->private_data分配的内存大小。通常private_data保存chip-specifc data.
2.创建声卡的芯片专用数据
chip-specific data包含I/O port address, its resource pointer, or the irq number等信息。
有两种方法可以来分配chip specific data.
1).通过snd_card_new实现:
struct mychip { struct snd_card *card; .... };
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, sizeof(struct mychip), &card);
struct mychip *chip = card->private_data;
chip->card = card;
在snd_card_new中分配chip。并将chip和card关联起来。card结构中的private_data就是chip,chip中又包含card。
2).通过snd_device_new来将chip作为一个低阶device注册到card上。
在snd_device_new中指定extra_size为0.
struct snd_card *card; struct mychip *chip; err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); ..... chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip->card = card;
static struct snd_device_ops ops = { .dev_free = snd_mychip_dev_free, }; .... snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
static int snd_mychip_dev_free(struct snd_device *device) { return snd_mychip_free(device->device_data); }
/**
* snd_device_new - create an ALSA device component
* @card: the card instance
* @type: the device type, SNDRV_DEV_XXX
* @device_data: the data pointer of this device
* @ops: the operator table
*/
int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops)
snd_device_new不为芯片专用数据device_data分配空间,因此在调用之前,必须为芯片专用分配空间,在ops的dev_free中定义析构函数对芯片专用数据进行析构。dev_free会在调用snd_card_free时自动调用。对于用户自定义的 device, type可以使用SNDRV_DEV_LOWLEVEL。
snd_mychip_dev_free()
是用来free前面kzmalloc的空间。
3.设置声卡驱动名字和声卡名字。
strcpy(card->driver, "My Chip"); strcpy(card->shortname, "My Own Chip 123"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->ioport, chip->irq);
.每一种部件的创建最终会调用snd_device_new()来生成一个snd_device实例,并把该实例链接到snd_card的devices链表中。
通常,alsa-driver的已经提供了一些常用的部件的创建函数,而不必直接调用snd_device_new(),比如: snd_pcm_new()
5.注册声卡
err = snd_card_register(card); if (err < 0) { snd_card_free(card); return err; }
具体声卡创建的例子可参考sound/sparc/amd9730.c