pcm核心与声音驱动程序之间的接口以术语 内核对象的叫法来定义。
声音驱动程序通常提供两种主要的接口: CHANNEL以及 MIXER或AC97。
AC97是一个很小的硬件访问(寄存器读/写) 接口,由驱动程序为带AC97编码解码器的硬件来实现。这种情况下,实际的 MIXER接口由pcm中共享的AC97代码提供。
声音驱动程序通常用一个私有数据结构来描述他们的设备,驱动 程序所支持的播放和录音数据通道各有一个。
对于所有的CHANNEL接口函数,第一个参数是一个不透明的指针。
第二个参数是指向私有的通道数据结构的指针, channel_init()是个例外,它的指针指向私有 设备结构(并返回由pcm以后使用的通道指针)。
对于声音数据传输,pcm核心与声音驱动
程序是通过一个由struct snd_dbuf描述的
共享内存区域进行通信的。
struct snd_dbuf是 pcm私有的,声音驱动程序通过调用访问者 函数(sndbuf_getxxx())来获得感兴趣的值。
共享内存区域的大小等于 sndbuf_getsize(),并被分割为大小固定,且等于 sndbuf_getblksz()字节的很多块。
当播放时,常规的传输机制如下(将意思反过来就是录音):
pcm开始时填充缓冲区,然后以
参数PCMTRIG_START调用声音驱动程序的 xxxchannel_trigger() 。
声音驱动程序接着安排以 sndbuf_getblksz()字节大小为块,重复将 整个内存区域(sndbuf_getbuf(), sndbuf_getsize())传输到设备。对于每个 传输块回调pcm函数 chn_intr()(这通常在中断时间发生)。
chn_intr()安排将新数据拷贝到那些
数据已传输到设备(现在空闲)的区域,并对 snd_dbuf结构进行适当的更新。
调用xxxchannel_init()来初始化每个播放
和录音通道。这个调用从声音驱动程序的连接例程中发起。(参看 探测和连接一节)。
static void *
xxxchannel_init(kobj_t obj, void *data,
struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct xxx_info *sc = data;
struct xxx_chinfo *ch;
...
return ch;
}
xxxchannel_setformat()应当按特定通道,
特定声音格式设置硬件。
static int
xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct xxx_chinfo *ch = data;
...
return 0;
}
xxxchannel_setspeed()按指定的取样速度
设置通道硬件,并返回返回可能调整过的速度。
static int
xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct xxx_chinfo *ch = data;
...
return speed;
}
xxxchannel_setblocksize()设置块大小, 这是pcm与声音驱动程序,以及声音驱动
程序与设备之间的传输单位的大小。传输期间,每次传输这样大小的
数据后,声音驱动程序都应当调用pcm的 chn_intr()。
大多数驱动程序只注意这儿的块大小,因为当实际传输开始时应该 使用这个值。
static int
xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct xxx_chinfo *ch = data;
...
return blocksize;
}
xxxchannel_trigger()由 pcm来控制驱动程序中的实际传输操作。
static int
xxxchannel_trigger(kobj_t obj, void *data, int go)
{
struct xxx_chinfo *ch = data;
...
return 0;
}
注意: 如果驱动程序使用ISA DMA,则应当在设备上执行动作前 调用
sndbuf_isadma(),并处理DMA芯片一方的 事情。
xxxchannel_getptr()返回传输缓冲区中
当前的缓冲。它通常由chn_intr()调用,而且 这也是为什么pcm知道它应当往哪儿传送 新数据。
调用xxxchannel_free()来释放通道资源,
例如当驱动程序卸载时,并且如果通道数据结构是动态分配的,或者 如果不使用sndbuf_alloc()进行缓冲区分配, 则应当实现这个函数。
struct pcmchan_caps *
xxxchannel_getcaps(kobj_t obj, void *data)
{
return &xxx_caps;
}
channel_reset(), channel_resetdone()和 channel_notify()用于特殊目的,未与权威人士 (Cameron Grant <[email protected]>)进行探讨之前不应当在驱动程序中实现它。
不赞成使用channel_setdir().
xxxmixer_init()初始化硬件,并告诉 pcm什么混音器设备可用来播放和录音。
static int
xxxmixer_init(struct snd_mixer *m)
{
struct xxx_info *sc = mix_getdevinfo(m);
u_int32_t v;
[初始化硬件]
[为播放混音器设置v中适当的位]
mix_setdevs(m, v);
[为录音混音器设置v中适当的位]
mix_setrecdevs(m, v)
return 0;
}
混音器的位定义可以在soundcard.h中 找到。(SOUND_MASK_XXX值和 SOUND_MIXER_XXX移位)。
xxxmixer_set()为混音器设备设置音量级别 (level)。
static int
xxxmixer_set(struct snd_mixer *m, unsigned dev,
unsigned left, unsigned right)
{
struct sc_info *sc = mix_getdevinfo(m);
[设置音量级别(level)]
return left | (right << 8);
}
xxxmixer_setrecsrc()设定录音源设备。
static int
xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct xxx_info *sc = mix_getdevinfo(m);
[查看src中的非零位, 设置硬件]
[更新src反映实际动作]
return src;
}
xxxmixer_uninit()应当确保不会发出任何
声音,并且如果可能则应当让混音器硬件断电。
xxxmixer_reinit()应当确保混音器硬件
加电,并且恢复所有不受mixer_set()或 mixer_setrecsrc()控制的设置。
AC97由带有AC97编码解码器的驱动程序实现。 它只有三个方法:
xxxac97_init()返回找到的 ac97编码解码器的数目。
ac97_read()与 ac97_write()读写指定的寄存器。
The AC97接口由 pcm中的AC97代码来执行高层操作。参看 sound/pci/maestro3.c或 sound/pci/下很多其他内容作为范例。
本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<[email protected]>.
关于本文档的问题请发信联系 <[email protected]>.