alsa driver--card
阅读原文时间:2023年07月15日阅读:1

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);

4.创建声卡功能部件,如PCM,mixer, MIDI
.每一种部件的创建最终会调用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