- 论坛徽章:
- 0
|
翻译:creator
sz111@126.com
第三章
管理card和组件
card实例
对于每个声卡,都要分配一个card记录。
一个card记录相当于一个声卡的总部。它管理着声卡中的所有设备(组件),例如PCM,mixers,MIDI,音序器等等。同时,card记录还保持着卡的ID和name字符串,管理proc文件,控制电源管理状态和热拔插。[color="#800000"]Card[color="#800000"]的组件列表用来在合适的时候释放资源。
[color="#000000"]如上,为了创建一个card[color="#000000"]实例,需要调用snd_card_new().
[color="#800000"]
Struct
snd_card *card;
card
= snd_card_new(index, id, module, extra_size);
这个函数需要4[color="#000000"]个参数,card-index[color="#000000"]号,id[color="#000000"]字符串,module[color="#000000"]指针(通常是THIS_MODULE),extra-data[color="#000000"]空间的大小。最后一个参数是用来分配chip-specific[color="#000000"]数据card->private_data[color="#000000"]的。注意这个数据是通过snd_card_new()[color="#000000"]进行分配。
[color="#000000"]组件
card[color="#000000"]被创建之后,你可以把组件(设备)附加到card[color="#000000"]实例上面。在ALSA驱动
程序中,一个组件用一个snd_devie[color="#000000"]结构体表示。可以是PCM[color="#000000"],控制接口或raw
MIDI[color="#000000"]接口等等。每个组件都有个入口函数。
通过snd_device_new()[color="#000000"]函数来创建组件。
snd_device_new(card,
SNDRV_DEV_XXX, chip, &ops);
它需要card[color="#000000"]指针,device_level[color="#000000"](SNDRV_DEV_XXX),[color="#000000"]数据指针和回调函数(&ops)[color="#000000"]。device-level定义了组件类型和注册和卸载的顺序。对于大部分的组件来说,
device_level[color="#000000"]已经定义好了。对于用户自定义的组件,你可以用SNDRV_DEV_LOWLEVEL.
这个函数自己并不分配数据空间。数据必须提前分配,同时把分配好的数据指针传递给这个函数作为参数。这个指针可以作为设备实例的标识符(上述代码的chip[color="#000000"])。
每个ALSA[color="#000000"]预定义组件,如ac97[color="#000000"]或pcm[color="#000000"]都是通过在各自的构造函数中调用snd_device_new().[color="#000000"]在一些回调函数中定义了每个组件的析构函数。因此,你不需要关心这种组件的析构函数的调用。
假如你要创建一个自己的组件,你需要在dev_free[color="#000000"]中的回调函数ops[color="#000000"]中设定析构函数。
[color="#000000"]以便它可以通过snd_card_free()[color="#000000"]自动被释放。下面的例子就会显示chip-specific[color="#000000"]数据的实现。
Chip-Specific
Data
chip-specific[color="#000000"]信息,如:i/o口,资源,或者中断号就会保持在
chip-specific[color="#000000"]记录里面。
Struct
mychip{
[color="#000000"] ....
[color="#000000"] };
通常来说,有两种方式来分配chip[color="#000000"]记录。
1.[color="#000000"]通过snd_card_new()[color="#000000"]分配。
如上面所述,你可以通过传递extra-data-length[color="#000000"]到snd_card_new()[color="#000000"]的第四个参数。
card
= snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct
mychip));
[color="#000000"] 无论struct
mychip[color="#000000"]是否是chip[color="#000000"]记录类型。
分配之后,可以通过如下方式引用:
struct
mychip *chip = char->private_data;
通过这种方法,你不必分配两次。这个记录将会和card[color="#000000"]实例一起被释放。
[color="#000000"]
[color="#000000"] 2.[color="#000000"]分配一个extra
device[color="#000000"]。
当你通过snd_card_new()([color="#000000"]第四个参数要设定为NULL)[color="#000000"]分配之后,通过调用kzalloc().
Struct
snd_card *card;
struct
mychip *chip;
card
= snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
[color="#000000"] ....
chip
= kzalloc(sizeof(*chip), GFP_KERNEL);
chip[color="#000000"]记录应该至少拥有一个snd_card[color="#000000"]指针的成员变量。
Struct
mychip {
struct
snd_card *card;
....
[color="#000000"] };
然后,设定chip[color="#000000"]的card[color="#000000"]为snd_card_new[color="#000000"]返回的card[color="#000000"]指针。
chip->card
= card;
下一步,初始化各个成员变量,使用一个含有特殊的ops[color="#000000"]的low-level[color="#000000"]设备注册chip[color="#000000"]记录。
Static
struct snd_device_ops ops = {
.dev_free =
snd_mychip_dev_free;
[color="#000000"] };
[color="#000000"] ....
snd_device_new(card,
SNDRV_DEV_LOWLEVEL, chip, &ops);
snd_mychip_dev_free()[color="#000000"]是作为设备的析构函数会调用真正的析构函数调用。
[color="#000000"]
static
int snd_mychip_dev_free(struct snd_device *device)
[color="#000000"] {
return
snd_mychip_free(device->private_data);
[color="#000000"] }
snd_mychip_free[color="#000000"]是真正的设备析构函数。
[color="#000000"]注册和释放
当所有的组件都被分配之后,就可以通过snd_card_register()[color="#000000"]来注册card[color="#000000"]实例了。对于设备文件的操作也会使能。那是因为,在调用snd_card_register()[color="#000000"]调用之前,组件是不能被外界调用的。假如注册失败,必须要调用snd_card_free()[color="#000000"]来释放card[color="#000000"]。
对于释放card[color="#000000"],你可以简单的通过snd_card_free().[color="#000000"]如前所述,所有的组件都可以通过它来自动释放。
要特别注意,这些析构函数(包括snd_mychip_dev_free[color="#000000"]和snd_mychip_free)[color="#000000"]不能被定义加入__devexit[color="#000000"]前缀,因为它们也有可能被构造函数调用(当构造失败的时候调用)。
对于一个运行热拔插的设备,你可以用snd_card_free_when_closed。
它将推迟析构直到所有的设备都关闭。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/49088/showart_1006027.html |
|