writing-an-alsa-driver(编写一个ALSA驱动)翻译稿 第三章

1351阅读 0评论2012-07-13 zhou991
分类:

翻译:creator

第三章 管理card和组件

card实例

对于每个声卡,都要分配一个card记录。

一个card记录相当于一个声卡的总部。它管理着声卡中的所有设备(组件),例如PCM,mixersMIDI,音序器等等。同时,card记录还保持着卡的IDname字符串,管理proc文件,控制电源管理状态和热拔插。Card的组件列表用来在合适的时候释放资源。

如上,为了创建一个card实例,需要调用snd_card_new().

Struct snd_card *card;

card = snd_card_new(index, id, module, extra_size);

这个函数需要4个参数,card-index号,id字符串,module指针(通常是THIS_MODULE),extra-data空间的大小。最后一个参数是用来分配chip-specific数据card->private_data的。注意这个数据是通过snd_card_new()进行分配。


组件

card被创建之后,你可以把组件(设备)附加到card实例上面。在ALSA驱动 程序中,一个组件用一个snd_devie结构体表示。可以是PCM,控制接口或raw MIDI接口等等。每个组件都有个入口函数。

通过snd_device_new()函数来创建组件。

snd_device_new(card, SNDRV_DEV_XXX, chip, &ops);


它需要card指针,device_levelSNDRV_DEV_XXX),数据指针和回调函数(&ops)device-level定义了组件类型和注册和卸载的顺序。对于大部分的组件来说, device_level已经定义好了。对于用户自定义的组件,你可以用SNDRV_DEV_LOWLEVEL.

这个函数自己并不分配数据空间。数据必须提前分配,同时把分配好的数据指针传递给这个函数作为参数。这个指针可以作为设备实例的标识符(上述代码的chip)。

每个ALSA预定义组件,如ac97pcm都是通过在各自的构造函数中调用snd_device_new().在一些回调函数中定义了每个组件的析构函数。因此,你不需要关心这种组件的析构函数的调用。

假如你要创建一个自己的组件,你需要在dev_free中的回调函数ops中设定析构函数。

以便它可以通过snd_card_free()自动被释放。下面的例子就会显示chip-specific数据的实现。


Chip-Specific Data

chip-specific信息,如:i/o口,资源,或者中断号就会保持在 chip-specific记录里面。

Struct mychip{

....

};

通常来说,有两种方式来分配chip记录。

1.通过snd_card_new()分配。

如上面所述,你可以通过传递extra-data-lengthsnd_card_new()的第四个参数。

card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct mychip));

无论struct mychip是否是chip记录类型。

分配之后,可以通过如下方式引用:

struct mychip *chip = char->private_data;

通过这种方法,你不必分配两次。这个记录将会和card实例一起被释放。

2.分配一个extra device

当你通过snd_card_new()(第四个参数要设定为NULL)分配之后,通过调用kzalloc().

Struct snd_card *card;

struct mychip *chip;

card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);

....

chip = kzalloc(sizeof(*chip), GFP_KERNEL);

chip记录应该至少拥有一个snd_card指针的成员变量。


Struct mychip {

struct snd_card *card;

....

};

然后,设定chipcardsnd_card_new返回的card指针。

chip->card = card;


下一步,初始化各个成员变量,使用一个含有特殊的opslow-level设备注册chip记录。

Static struct snd_device_ops ops = {

.dev_free = snd_mychip_dev_free;

};

....

snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);

snd_mychip_dev_free()是作为设备的析构函数会调用真正的析构函数调用。

static int snd_mychip_dev_free(struct snd_device *device)

{

return snd_mychip_free(device->private_data);

}

snd_mychip_free是真正的设备析构函数。


注册和释放

当所有的组件都被分配之后,就可以通过snd_card_register()来注册card实例了。对于设备文件的操作也会使能。那是因为,在调用snd_card_register()调用之前,组件是不能被外界调用的。假如注册失败,必须要调用snd_card_free()来释放card

对于释放card,你可以简单的通过snd_card_free().如前所述,所有的组件都可以通过它来自动释放。

要特别注意,这些析构函数(包括snd_mychip_dev_freesnd_mychip_free)不能被定义加入__devexit前缀,因为它们也有可能被构造函数调用(当构造失败的时候调用)。

对于一个运行热拔插的设备,你可以用snd_card_free_when_closed。 它将推迟析构直到所有的设备都关闭。

上一篇:writing-an-alsa-driver(编写一个ALSA驱动)翻译稿 第一章
下一篇:writing-an-alsa-driver(编写一个ALSA驱动)翻译稿 第四章