15.4 接口

  pcm核心与声音驱动程序之间的接口以术语 内核对象的叫法来定义。

  声音驱动程序通常提供两种主要的接口: CHANNEL以及 MIXERAC97

  AC97是一个很小的硬件访问(寄存器读/写) 接口,由驱动程序为带AC97编码解码器的硬件来实现。这种情况下,实际的 MIXER接口由pcm中共享的AC97代码提供。

15.4.1 CHANNEL接口

15.4.1.1 函数参数的通常注意事项

  声音驱动程序通常用一个私有数据结构来描述他们的设备,驱动 程序所支持的播放和录音数据通道各有一个。

  对于所有的CHANNEL接口函数,第一个参数是一个不透明的指针。

  第二个参数是指向私有的通道数据结构的指针, channel_init()是个例外,它的指针指向私有 设备结构(并返回由pcm以后使用的通道指针)。

15.4.1.2 数据传输操作概览

  对于声音数据传输,pcm核心与声音驱动 程序是通过一个由struct snd_dbuf描述的 共享内存区域进行通信的。

  struct snd_dbufpcm私有的,声音驱动程序通过调用访问者 函数(sndbuf_getxxx())来获得感兴趣的值。

  共享内存区域的大小等于 sndbuf_getsize(),并被分割为大小固定,且等于 sndbuf_getblksz()字节的很多块。

  当播放时,常规的传输机制如下(将意思反过来就是录音):

  • pcm开始时填充缓冲区,然后以 参数PCMTRIG_START调用声音驱动程序的 xxxchannel_trigger()

  • 声音驱动程序接着安排以 sndbuf_getblksz()字节大小为块,重复将 整个内存区域(sndbuf_getbuf()sndbuf_getsize())传输到设备。对于每个 传输块回调pcm函数 chn_intr()(这通常在中断时间发生)。

  • chn_intr()安排将新数据拷贝到那些 数据已传输到设备(现在空闲)的区域,并对 snd_dbuf结构进行适当的更新。

15.4.1.3 channel_init

  调用xxxchannel_init()来初始化每个播放 和录音通道。这个调用从声音驱动程序的连接例程中发起。(参看 探测和连接一节)。

          static void *
          xxxchannel_init(kobj_t obj, void *data, 
             struct snd_dbuf *b, struct pcm_channel *c, int dir)(1)
          {
              struct xxx_info *sc = data;
              struct xxx_chinfo *ch;
               ...
              return ch;(2)
           }
(1)
b为通道 struct snd_dbuf的地址。它应当在 函数中通过调用sndbuf_alloc()来初始化。 所用的缓冲区大小通常是设备'典型'传输大小的一个较小的倍数。

cpcm通道控制结构的指针。这是个不透明 指针。函数应当将它保存到局部通道结构中,在后面调用 pcm函数(例如: chn_intr(c))时会使用它。

dir指示通道方向 (PCMDIR_PLAYPCMDIR_REC)。

(2)
函数应当返回一个指针,此指针指向用于控制此通道的私有 区域。它将作为参数被传递到对其他通道接口的调用。

15.4.1.4 channel_setformat

  xxxchannel_setformat()应当按特定通道, 特定声音格式设置硬件。

          static int
          xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)(1)
          {
              struct xxx_chinfo *ch = data;
               ...
              return 0;
           }
(1)
formatAFMT_XXX value值之一 (soundcard.h)。

15.4.1.5 channel_setspeed

  xxxchannel_setspeed()按指定的取样速度 设置通道硬件,并返回返回可能调整过的速度。

          static int
          xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
          {
              struct xxx_chinfo *ch = data;
               ...
              return speed;
           }

15.4.1.6 channel_setblocksize

  xxxchannel_setblocksize()设置块大小, 这是pcm与声音驱动程序,以及声音驱动 程序与设备之间的传输单位的大小。传输期间,每次传输这样大小的 数据后,声音驱动程序都应当调用pcmchn_intr()

  大多数驱动程序只注意这儿的块大小,因为当实际传输开始时应该 使用这个值。

          static int
          xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
          {
              struct xxx_chinfo *ch = data;
                ...
              return blocksize;(1)
           }
(1)
函数返回可能调整过的块大小。如果块大小真的变化了, 这种情况下应当调用sndbuf_resize()调整 缓冲区的大小。

15.4.1.7 channel_trigger

  xxxchannel_trigger()pcm来控制驱动程序中的实际传输操作。

          static int
          xxxchannel_trigger(kobj_t obj, void *data, int go)(1)
          {
              struct xxx_chinfo *ch = data;
               ...
              return 0;
           }
(1)
go定义当前调用的动作。可能的值为:
  • PCMTRIG_START:驱动程序应当 启动从/到通道缓冲区的数据传输。如果需要,应当通过 sndbuf_getbuf()sndbuf_getsize()检取缓冲区的 基地址和大小。

  • PCMTRIG_EMLDMAWR / PCMTRIG_EMLDMARD:告诉驱动程序, 输入或输出缓冲区可能已被更新过了。大多数驱动程序只是 忽略这些调用。

  • PCMTRIG_STOP / PCMTRIG_ABORT:驱动程序应当停止当前 的传输。

注意: 如果驱动程序使用ISA DMA,则应当在设备上执行动作前 调用sndbuf_isadma(),并处理DMA芯片一方的 事情。

15.4.1.8 channel_getptr

  xxxchannel_getptr()返回传输缓冲区中 当前的缓冲。它通常由chn_intr()调用,而且 这也是为什么pcm知道它应当往哪儿传送 新数据。

15.4.1.9 channel_free

  调用xxxchannel_free()来释放通道资源, 例如当驱动程序卸载时,并且如果通道数据结构是动态分配的,或者 如果不使用sndbuf_alloc()进行缓冲区分配, 则应当实现这个函数。

15.4.1.10 channel_getcaps

          struct pcmchan_caps *
          xxxchannel_getcaps(kobj_t obj, void *data)
          {
              return &xxx_caps;(1)
           }
(1)
这个例程返回指向(通常静态定义的) pcmchan_caps结构的指针(在 sound/pcm/channel.h中定义)。这个结构 保存着最小和最大采样频率和被接受的声音格式。任何声音驱动 程序都可以作为一个范例。

15.4.1.11 更多函数

  channel_reset(), channel_resetdone()channel_notify()用于特殊目的,未与权威人士 (Cameron Grant )进行探讨之前不应当在驱动程序中实现它。

  不赞成使用channel_setdir().

15.4.2 MIXER接口

15.4.2.1 mixer_init

  xxxmixer_init()初始化硬件,并告诉 pcm什么混音器设备可用来播放和录音。

          static int
          xxxmixer_init(struct snd_mixer *m)
          {
              struct xxx_info   *sc = mix_getdevinfo(m);
              u_int32_t v;

              [初始化硬件]

              [为播放混音器设置v中适当的位](1)
              mix_setdevs(m, v);
              [为录音混音器设置v中适当的位]
              mix_setrecdevs(m, v)

              return 0;              
          }
(1)
设置一个整数值中的位,并调用 mix_setdevs()mix_setrecdevs()来告诉 pcm存在什么设备。

  混音器的位定义可以在soundcard.h中 找到。(SOUND_MASK_XXX值和 SOUND_MIXER_XXX移位)。

15.4.2.2 mixer_set

  xxxmixer_set()为混音器设备设置音量级别 (level)。

          static int
          xxxmixer_set(struct snd_mixer *m, unsigned dev, 
                           unsigned left, unsigned right)(1)
          {
              struct sc_info *sc = mix_getdevinfo(m);
              [设置音量级别(level)]
              return left | (right << 8);(2)
          }
(1)
设备被指定为 SOUND_MIXER_XXX

在范围[0-100]之间指定音量值。零值应当让设备静音。

(2)
由于硬件(音量)级别(level)可能不匹配输入比例,会出现 某些圆整,例程返回如上面所示的实际级别值(范围0-100内)。

15.4.2.3 mixer_setrecsrc

  xxxmixer_setrecsrc()设定录音源设备。

          static int
          xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)(1)
          {
              struct xxx_info *sc = mix_getdevinfo(m);

              [查看src中的非零位, 设置硬件]

              [更新src反映实际动作]
              return src;(2)
           }
(1)
期望的录音设备由一个位域指定.
(2)
返回设置用来录音的实际设备。一些驱动程序只能设置一个 录音设备。如果出现错误,函数应当返回-1。

15.4.2.4 mixer_uninit, mixer_reinit

  xxxmixer_uninit()应当确保不会发出任何 声音,并且如果可能则应当让混音器硬件断电。

  xxxmixer_reinit()应当确保混音器硬件 加电,并且恢复所有不受mixer_set()mixer_setrecsrc()控制的设置。

15.4.3 AC97接口

  AC97由带有AC97编码解码器的驱动程序实现。 它只有三个方法:

  The AC97接口由 pcm中的AC97代码来执行高层操作。参看 sound/pci/maestro3.csound/pci/下很多其他内容作为范例。

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.