linux audio程序,Linux audio(OSS)子系统分析

简介

在linux声卡的驱动中存在两种架构,一种是OSS(开放声音系统),一种是ALSA(先

进Linux声音架构)。OSS是一个商业声卡驱动程序,需要花钱购买。一般我们现在使用的

是ALSA的声音架构。

OOS(Open Sound System),官网:www.opensound.com

在这里主要介绍两个设备,DSP与MIXER.

DSP: 用来采样和播放的文件,对该设备写操作就是播放,对该设备读就是录音操作。

这个设备可以有多个。对该设备操作时应注意一次写入数据块的大小,如果数据块过大会引

起设备的block操作。属于应用范畴的内容不在此介绍了。

MIXER:  应用程序对混音器的软件接口。混音器电路通常由两个部分组成:input mixer

和ouput mixer.  该设备的大部分操作都是由ioctl实现的, mixer设备允许同时多个用

户同时访问。 主要设备的参数有Rate ,Channel, Format. Volume, Standby等

主要参数

Oss系统的主要文件:

sound/sound_core.c

include/linux/sound.h

sound/sound_core.h

sound/sound_core.c

include/linux/sound.h

sound/sound_core.h

Oss系统的主要结构介绍:

structsound_unit

{

intunit_minor;

conststructfile_operations *unit_fops;

structsound_unit *next;

charname[32];

};

structsound_unit

{

int unit_minor;

const struct file_operations *unit_fops;

struct sound_unit *next;

char name[32];

};

每个sound设备都会对应这样一个结构,unit_minor对应子设备号, unit_fops对应操作

函数,这个是由各厂商应现,在注册设备的时候传入。Next指向下一个同类形设备,name

就不需多说了。

sound_class              /sys/class/sound类

staticstructsound_unit*chains[SOUND_STEP];

/*整个OSS系统的链表数组,数组的每一项代表一种声卡设备,如下表所示:*/

*       0       *16            Mixers

*     1       *8              Sequencers

*     2       *16            Midi

*     3       *16            DSP

*     4       *16            SunDSP

*     5       *16            DSP16

*     6       --                sndstat (obsolete)

*     7       *16            unused

*     8       --                alternate sequencer (see above)

*     9       *16            raw synthesizer access

*     10     *16            unused

*     11     *16            unused

*     12     *16            unused

*     13     *16            unused

*     14     *16            unused

*     15     *16            unused

sound_class /sys/class/sound类

static struct sound_unit*chains[SOUND_STEP];

/*整个OSS系统的链表数组,数组的每一项代表一种声卡设备,如下表所示:*/

* 0 *16 Mixers

* 1 *8 Sequencers

* 2 *16 Midi

* 3 *16 DSP

* 4 *16 SunDSP

* 5 *16 DSP16

* 6 -- sndstat (obsolete)

* 7 *16 unused

* 8 -- alternate sequencer (see above)

* 9 *16 raw synthesizer access

* 10 *16 unused

* 11 *16 unused

* 12 *16 unused

* 13 *16 unused

* 14 *16 unused

* 15 *16 unused

OSS系统的注册过程:

本节描述soundclass的注册过程,与及实例说明dsp与mixer设备的注册过程,用户层

是如何通过设备节点访问到各厂商提供设备的操作函数的。

staticint__init init_soundcore(void)

{

intrc;

rc= init_oss_soundcore();

if(rc)

returnrc;

/*注意这里的sound_class是全局函数,用于保存sound类*/

sound_class= class_create(THIS_MODULE,"sound");//注册/sys/class/sound类

if(IS_ERR(sound_class)) {

cleanup_oss_soundcore();

returnPTR_ERR(sound_class);

}

sound_class->devnode= sound_devnode;

return0;

}

static int __init init_soundcore(void)

{

intrc;

rc= init_oss_soundcore();

if(rc)

returnrc;

/*注意这里的sound_class是全局函数,用于保存sound类*/

sound_class= class_create(THIS_MODULE, "sound"); //注册/sys/class/sound类

if(IS_ERR(sound_class)) {

cleanup_oss_soundcore();

returnPTR_ERR(sound_class);

}

sound_class->devnode= sound_devnode;

return0;

}

在系统启动阶段,kernel会调用到module_init,进入init_soundcore,初始化

init_oss_soundcore, 并注册sound类,这样在/sys/class/下就有了sound类了, sound_devnode()

也决定了相应的设备节点也将会出现在/dev/snd/下面。

staticvoid__exit cleanup_soundcore(void)

{

cleanup_oss_soundcore();

class_destroy(sound_class);

}

module_init(init_soundcore);

module_exit(cleanup_soundcore);

static void __exit cleanup_soundcore(void)

{

cleanup_oss_soundcore();

class_destroy(sound_class);

}

module_init(init_soundcore);

module_exit(cleanup_soundcore);

cleanup_soundcore函数对应于init_soundcore,主要用于清除oss_soundcore, 并销毁

sound_class类。

下面主要介绍一下,mixer与dsp设备的注册过程, 其它设备雷同:

intregister_sound_dsp(conststructfile_operations *fops,intdev)

{

returnsound_insert_unit(&chains[3], fops, dev, 3, 131,

"dsp", S_IWUSR | S_IRUSR, NULL);

}

EXPORT_SYMBOL(register_sound_dsp); 

int register_sound_dsp(const structfile_operations *fops, int dev)

{

returnsound_insert_unit(&chains[3], fops, dev, 3, 131,

"dsp", S_IWUSR | S_IRUSR, NULL);

}

EXPORT_SYMBOL(register_sound_dsp); 

register_sound_dsp是注册dsp设备的函数,需要传入dsp设备的fops, 就是dsp设备的

具体操作方法实现。register_sound_dsp调用sound_insert_unit函数实现注册, 这时传入

的chains[3]就是在声卡数组链表的3上注册dsp设备,如果注册mixer设备就是chains[0]了。

staticintsound_insert_unit(structsound_unit **list,conststructfile_operations

*fops,intindex,intlow,inttop,constchar*name, umode_t mode,structdevice *dev)

{

structsound_unit *s =kmalloc(sizeof(*s), GFP_KERNEL);//分配声卡设备内存

intr;

……………………….

r = __sound_insert_unit(s, list, fops,index, low, top);//注册声卡设备到list上

spin_unlock(&sound_loader_lock);

………………………

device_create(sound_class, dev,MKDEV(SOUND_MAJOR, s->unit_minor),

NULL, s->name+6);

//调用device_create广播设备信息到userspace,udev创建

static intsound_insert_unit(struct sound_unit **list, const struct file_operations

*fops,int index, int low, int top, const char *name, umode_t mode, struct device *dev)

{

struct sound_unit *s =kmalloc(sizeof(*s), GFP_KERNEL); //分配声卡设备内存

int r;

……………………….

r = __sound_insert_unit(s, list, fops,index, low, top); //注册声卡设备到list上

spin_unlock(&sound_loader_lock);

………………………

device_create(sound_class, dev,MKDEV(SOUND_MAJOR, s->unit_minor),

NULL, s->name+6);

//调用device_create广播设备信息到userspace,udev创建

现在就进入分析__sound_insert_unit,分析这里就有点技巧了,大家C基本功可得过关,

分得清指针数组和数组指针,指针数组就是存在一个数组,数组里全是指针变量,在32位

arm上,大于约等于max*int, 数组指针就是1个指向数组的指针,在32位arm上就是4byte.

staticint__sound_insert_unit(structsound_unit * s,structsound_unit **list,

conststruct file_operations *fops,intindex,intlow,inttop)

{//传入的参数依次为: s,&chains[3], fops, dev, 3, 131

……………………………..

if(index 

while(*list &&(*list)->unit_minor

list=&((*list)->next);

while(n

{

/* Found a hole ? */

if(*list==NULL ||(*list)->unit_minor>n)//因为第一次注册list为空,跳出

break;

list=&((*list)->next);

n+=SOUND_STEP;

}

if(n>=top)

return-ENOENT;

}else{

……………………………..

}

s->unit_minor=n;//直接赋值退出

s->unit_fops=fops;

s->next=*list;

*list=s;

static int__sound_insert_unit(struct sound_unit * s, struct sound_unit **list,

conststruct file_operations *fops, int index, int low, int top)

{ //传入的参数依次为: s,&chains[3], fops, dev, 3, 131

……………………………..

if (index < 0) { /* first free */ //index 传入为 -1, 故进入此分支

while (*list &&(*list)->unit_minor

list=&((*list)->next);

while(n

{

/* Found a hole ? */

if(*list==NULL ||(*list)->unit_minor>n) //因为第一次注册list为空,跳出

break;

list=&((*list)->next);

n+=SOUND_STEP;

}

if(n>=top)

return -ENOENT;

} else {

……………………………..

}

s->unit_minor=n; //直接赋值退出

s->unit_fops=fops;

s->next=*list;

*list=s;

接下来返回到sound_insert_unit, 通过__register_chrdev将s, 注册到系统上,这

里/dev/snd/下就出现dsp名字了,但奇怪的时,这里传入的fops不是s->fops,而是系统公

用的全局soundcore_fops, 在打开dsp时接着分析。

r = __register_chrdev(SOUND_MAJOR,s->unit_minor, 1, s->name,

&soundcore_fops);

r = __register_chrdev(SOUND_MAJOR,s->unit_minor, 1, s->name,

&soundcore_fops);

打开设备流程

由于注册的时候传入的是soundcore_fops, 故打开设备时会进入soundcore_fops的

open函数。Soundcore_fops结构体如下.

staticconststructfile_operationssoundcore_fops =

{

/*We must have an owner or the module locking fails */

.owner     = THIS_MODULE,

.open        = soundcore_open,

};

static const struct file_operationssoundcore_fops =

{

/*We must have an owner or the module locking fails */

.owner = THIS_MODULE,

.open = soundcore_open,

};

在这里进入soundcore_open函数, 现在我们就跟进去分析。

staticintsoundcore_open(structinode*inode,structfile *file)

{

…………………

if(s)

new_fops= fops_get(s->unit_fops);

/*在这里获得__sound_insert_unit注册的fops, 就是我们在注册dsp时传入的fops. */

if(preclaim_oss && !new_fops) {//这里的new_fops是有值的,所有不会进入此分支

spin_unlock(&sound_loader_lock);

…………..

if(new_fops) {

…………………..

conststruct file_operations *old_fops = file->f_op;

file->f_op= new_fops;//在这里偷天换日,将系统的fops转换为s->fops

spin_unlock(&sound_loader_lock);

if(file->f_op->open)

err= file->f_op->open(inode,file);

if(err) {

fops_put(file->f_op);

file->f_op= fops_get(old_fops);

}

fops_put(old_fops);

unlock_kernel();

returnerr;

}

static int soundcore_open(struct inode*inode, struct file *file)

{

…………………

if(s)

new_fops= fops_get(s->unit_fops);

/*在这里获得__sound_insert_unit注册的fops, 就是我们在注册dsp时传入的fops. */

if(preclaim_oss && !new_fops) { //这里的new_fops是有值的,所有不会进入此分支

spin_unlock(&sound_loader_lock);

…………..

if(new_fops) {

…………………..

conststruct file_operations *old_fops = file->f_op;

file->f_op= new_fops; //在这里偷天换日,将系统的fops转换为s->fops

spin_unlock(&sound_loader_lock);

if(file->f_op->open)

err= file->f_op->open(inode,file);

if(err) {

fops_put(file->f_op);

file->f_op= fops_get(old_fops);

}

fops_put(old_fops);

unlock_kernel();

returnerr;

}

在这里就发现在open设置时,系统将设备的fops转换为dsp注册时的fops, 偷天换

日啊, linux kernel还是蛮神奇的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值