日期:2014-05-16  浏览次数:20711 次

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&