Linux音频设备驱动-2【转】
Linux音频设备驱动-2【转】
2011年01月20日
转:http://hi.baidu.com/geyangshun/blog/item/2df32a382 e6b2e22b9998f39.html 17.4.2 PCM设备
每个声卡最多可以有4个PCM实例,1个PCM实例对应1个设备文件。PCM实例由PCM放音和录音流组成,而每个PCM流又由1个或多个PCM子流组成。有的声卡支持多重放音功能,例如,emu10k1包含1个32个立体声子流的PCM放音设备。
1、PCM实例构造
int snd_pcm_new(struct snd_card *card, char *id, int device,
int playback_count, int capture_count, struct snd_pcm ** rpcm);
第 1个参数是card指针,第2个是标识字符串,第3个是PCM设备索引(0表示第1个PCM设备),第4和第5个分别为放音和录音设备的子流数。当存在多个子流时,需要恰当地处理open()、close()和其它函数。在每个回调函数中,可以通过snd_pcm_substream的number成员得知目前操作的究竟是哪个子流,如:
struct snd_pcm_substream *substream;
int index = substream->number;
一种习惯的做法是在驱动中定义1个PCM"构造函数",负责PCM实例的创建,如代码清单17.7。
代码清单17.7 PCM设备"构造函数"
1 static int __devinit snd_xxxchip_new_pcm(struct xxxchip *chip)
2 {
3 struct snd_pcm *pcm;
4 int err;
5 //创建PCM实例
6 if ((err = snd_pcm_new(chip->card, "xxx Chip", 0, 1, 1, &pcm)) private_data = chip; //置pcm->private_data为芯片特定数据
9 strcpy(pcm->name, "xxx Chip");
10 chip->pcm = pcm;
11 ...
12 return 0;
13 }
2、设置PCM操作
void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops);
第1个参数是snd_pcm的指针,第2个参数是SNDRV_PCM_STREAM_PLAYBACK或SNDRV_PCM_STREAM_CAPTURE,而第3个参数是PCM操作结构体snd_pcm_ops,这个结构体的定义如代码清单17.8。
代码清单17.8 snd_pcm_ops结构体
1 struct snd_pcm_ops
2 {
3 int (*open)(struct snd_pcm_substream *substream);//打开
4 int (*close)(struct snd_pcm_substream *substream);//关闭
5 int (*ioctl)(struct snd_pcm_substream * substream,
6 unsigned int cmd, void *arg);//io控制
7 int (*hw_params)(struct snd_pcm_substream *substream,
8 struct snd_pcm_hw_params *params);//硬件参数
9 int (*hw_free)(struct snd_pcm_substream *substream); //资源释放
10 int (*prepare)(struct snd_pcm_substream *substream);//准备
11 //在PCM被开始、停止或暂停时调用
12 int (*trigger)(struct snd_pcm_substream *substream, int cmd);
13 snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);// 当前缓冲区的硬件位置
14 //缓冲区拷贝
15 int (*copy)(struct snd_pcm_substream *substream, int channel,
16 snd_pcm_uframes_t pos,
17 void __user *buf, snd_pcm_uframes_t count);
18 int (*silence)(struct snd_pcm_substream *substream, int channel,
19 snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
20 struct page *(*page)(struct snd_pcm_substream *substream,
21 unsigned long offset);
22 int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
23 int (*ack)(struct snd_pcm_substream *substream);
24 };
snd_pcm_ops中的所有操作都需事先通过snd_pcm_substream_chip()获得xxxchip指针,例如:
int xxx()
{
struct xxxchip *chip = snd_pcm_substream_chip(substream);
...
}
当1个PCM子流被打开时,snd_pcm_ops中的open()函数将被调用,在这个函数中,至少需要初始化runtime->hw字段,代码清单17.9给出了open()函数的范例。
代码清单17.9 snd_pcm_ops结构体中open()函数
1 static int snd_xxx_open(struct snd_pcm_substream *substream)
2 {
3 //从子流获得xxxchip指针
4 struct xxxchip *chip = snd_pcm_substream_chip(substream);
5 //获得PCM运行时信息指针
6 struct snd_pcm_runtime *runtime = substream->runtime;
7 ...
8 //初始化runtime->hw
9&