Chinaunix首页 | 论坛 | 博客
  • 博客访问: 530640
  • 博文数量: 237
  • 博客积分: 2175
  • 博客等级: 大尉
  • 技术积分: 2563
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-05 22:02
个人简介

目前在一家公司担任软件总监,主要涉及智能手机,笔记本电脑的开发

文章分类

全部博文(237)

文章存档

2024年(18)

2023年(68)

2022年(13)

2021年(7)

2020年(11)

2019年(3)

2018年(10)

2017年(8)

2012年(7)

2011年(4)

2010年(32)

2009年(41)

2008年(6)

2007年(9)

分类: LINUX

2009-02-26 21:10:02

{BANNED}中国第一章 : 文件结构
 
概要
  ALSA驱动以两种方式提供:
  一种是从ALSA的ftp站点以一个压缩包或者通过cvs得到的目录树.另一种是在2.6(或者更新的)linux内核中的目录.为了同步这两者,alsa驱动分成2个不同的目录:alsa-kernel 和alsa-driver .前者包含完全的代码给linux 2.6(或者更新的)目录,该目录只是设计为在2.6或更新的版本上编译.后者,alsa-driver,包含很多精细的文件,为了在linux内核目录之外的编译,包装给2.2和2.4内核的函数,适应{BANNED}最佳新的内核API,以及另外的还在开发或者测试中的驱动.这些在alsa-driver目录中的驱动,当他们完成并且确认工作很好后,将会移入alsa-kernel(并{BANNED}最佳终到2.6内核目录).
  ALSA驱动的文件目录结构在下面描述.alsa内核和alsa驱动有几乎相同的文件结构,除了"core"目录,它在alsa驱动中并命名为"acore".
例1.1 ALSA 文件目录结构

sound
                /core
                        /oss
                        /seq
                                /oss
                                /instr
                /ioctl32
                /include
                /drivers
                        /mpu401
                        /opl3
                /i2c
                        /l3
                /synth
                        /emux
                /pci
                        /(cards)
                /isa
                        /(cards)
                /arm
                /ppc
                /sparc
                /usb
                /pcmcia /(cards)
                /oss

core目录

这个目录包含了中间层,它是alsa驱动的核心.在这个目录中保存了原始的alsa模块.它的子目录包含了不同的模块并依赖于内核的配置.

core/oss

这个目录保存了PCM和混音器的OSS模拟.rawmidi的OSS模拟在alsa的rawmidi代码中,因为它相当小.音序器的代码在core/seq/oss 目录中(见 下面).

core/ioctl32

这个目录包含了32位 ioctrl封给64位架构比如x86-64, ppc64 和sparc64. 对于32位和 alpha架构,他们不会被编译.

core/seq

这个目录和它的子目录是为alsa音序器. 这个目录包含了音序器代码和主要的音序器模块比如snd-seq-midi, snd-seq-virmidi,等等.他们只有CONFIG_SND_SEQUENCER在内核配置中设置时才被编译.

core/seq/oss

这个目录包含了OSS 音序器模拟代码.

core/seq/instr

这个目录包含了音序器的乐器层.

include directory

这是alsa驱动的公公的头文件的地方,他们输出给用户空间,或者在不同目录的几个文件所引用。基本上,私有的头文件不要放在这个目录,但你也许仍然发现私有的头文件在这里,由于历史的原因:)

drivers目录

这个目录包含了代码,他们被在不同的架构下的不同驱动所共享.他们应次假使不是特定架构的。例如,dummy pcm驱动和串行的MIDI驱动在这个目录可以找到.在它的子目录,是与总线和cpu架构无关的模块代码.

drivers/mpu401

MPU401和MPU401-UART 模块放在这里.

drivers/opl3 and opl4

OPL3和OPL4 FM-合成器资料放在这里.

i2c 目录

这个目录包含了ALSA i2c模块.

尽管在linux中有一个标准的i2c层,ALSA对于一些卡有自己的i2c代码,因为这个声卡之需要一些简单的操作而标准的i2c API对于此目的太复杂了.

i2c/l3

这是一个子目录给ARM L3 i2c.

synth 目录

这个目录包含了合成器的中间层模块.

目前,只有Emu8000/Emu10k1合成器去冬在synth/emux子目录下.

pci 目录

这个目录和它的子目录保留了{BANNED}最佳高层的PCI声卡的卡模块,这些代码是为PCI总线特定的.

单个文件编译的驱动直接放在pci目录下,而需要多个源文件编译的驱动放在他们自己的子目录下(例如. emu10k1, ice1712).  

isa 目录

这个目录和它的子目录保留了{BANNED}最佳高层的ISA声卡的卡模块.

arm, ppc, 和sparc 目录

他们是给特定的这些架构中的一个的{BANNED}最佳高层的声卡模块。

usb 目录

这个目录包含了USB-audio驱动.在{BANNED}最佳新的版本中,USB MIDI驱动集成在usb-audio驱动中.

pcmcia 目录

PCMCIA, 特定的PCCard驱动在这里。 卡总线驱动将在pci目录中,因为他们的API和标准的PCI卡一样.

oss 目录

在linux2.6(或者更新的)目录中,OSS/Lite源文件放在这里.在ALSA去冬压缩包中,这个目录当然是空的:)


第2章.基本的PCI驱动流程

。。。。

第3章 卡和模块的管理

卡实体

对于每一个声卡,一个“卡”记录必须被分配。

一个卡是一个声卡的总部。它管理着声卡上的整个设备(组件)列表,比如PCM,mixer,MIDI,音序器,等等。卡纪录也保持这个声卡的ID和名字字符串,管理proc文件的根,和控制电源管理状态和热插拔断开。卡纪录上的组件列表被用来管理在销毁时正确的资源释放。

如上所述,为了创建一个卡实体,调用snd_card_create().

 struct snd_card *card;
  int err;
  err = snd_card_create(index, id, module, extra_size, &card);
这个函数有5个参数,卡的索引,id字符串,模块指针(通常是THIS_MODULE),额外的数据空间大小和返回的卡实体的指针. 额外的数据空间大小参数用来分配card->private_data给芯片特定的数据.注意这些数据空间在snd_card_create()中分配.
(注:应该用snd_card_new来创建一个卡实例)
组件
		

在卡实例创建后,你可以挂载组件(设备)到卡实例上。在ALSA驱动中,一个组件是以一个

结构snd_device对象来表示。一个组件可以是一个PCM实例,一个控制实例,一个原MIDI接口 ,等等。每个这样的实例有一个组件入口 。一个组件可以通过snd_device_new()函数创建。

  snd_device_new(card, SNDRV_DEV_XXX, chip, &ops);
它以卡指针,设备级别 (SNDRV_DEV_XXX), 数据指针,和回调函数指针(&ops).设备级别定义了组件的类型以及注册,撤销的顺序。对于大多数组件,设备级别已经定义好了。对于一个用户定义的组件,你可以用SNDRV_DEV_LOWLEVEL. 
  这个函数本身不分配数据空间。数据必须之前手动分配,并且其指针作为一个参数传入。指针(在上例中chip指示符)指向实例。

每个以前定义的ALSA组件比如ac97和pcm在它的构造函数中调用snd_device_new().每个组件的析构函数定义在回调函数指针中。因此,你不需要关心为这个组件调用析构函数。

如果你想创建自己的组件,你需要设置析构函数指针在ops的dev_free回调函数中,这样它可以自动释放通过snd_card_free().下一个例子将展示一个芯片特定数据的实现.



芯片特定的数据

芯片特定的信息,例如.I/O口的地址,资源指针,或者irq号,存在芯片特定的记录中

  struct mychip {
          ....
  };
         


通常,有两种方法分配芯片的记录.

1. 分配通过snd_card_create().

如上所述,你可以传递一个额外数据长度给snd_card_create()函数中的第4个参数,比如 err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(struct mychip), &card);

结构mychip是芯片记录的类型.

反过来,已分配的记录可以这样被访问:

  struct mychip *chip = card->private_data;
通过这种方法,你不需要分配两次。记录将和卡实例一起释放。
2. 分配一个额外的设备
 通过snd_card_create分配一个卡实例后(第4个参数为0),调用kzalloc(). 
  struct snd_card *card;
  struct mychip *chip;
  err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
  .....
  chip = kzalloc(sizeof(*chip), GFP_KERNEL);

芯片记录应当有一项,至少保持有卡指针, 
  struct mychip {
          struct snd_card *card;
          ....
  };

然后,在返回的芯片实例设置卡指针            


  chip->card = card;
下一步,初始化芯片记录的项,寄存器 ,作为一个带有特定的ops的low-level设备,
  static struct snd_device_ops ops = {
          .dev_free =        snd_mychip_dev_free,
  };
  ....
  snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);

            

snd_mychip_dev_free()是一个设备析构函数,它将调用实际的析构函数.


  static int snd_mychip_dev_free(struct snd_device *device)
  {
          return snd_mychip_free(device->device_data);
  }

这里 , snd_mychip_free()是实际的析构函数. 
 
		

注册和释放

在所有的组件都赋值后,通过调用snd_card_register()来注册卡.在这点开始,可以访问设备文件了.也就是说,在snd_card_register()被调用之前,组件不可以被外界安全访问.如果这个调用失败,在用snd_card_free()释放卡后退出探测函数。

对于释放卡实例,你可以简单地调用snd_card_free().如前面所述,所有的组件通过这个调用自动地释放.

进一步说明,对于析构函数(snd_mychip_dev_free和snd_mychip_free)不能被定义为

__devexit前缀,因为他们也许在构造函数中调用,在false路径.

对于一个允许热插拔的设备,你可以用 snd_card_free_when_closed. 这个函数将推迟析构直到所有的设备关闭后.


第4章.PCI资源管理

。。。。。。


第5章.PCM接口

概要

  ALSA PCM中间层非常强大,驱动只需要实现底层的函数以访问硬件。

为了访问PCM层,你需要先include .此外, 如果你访问一些和hw_param相关的函数,也许需要.

每个卡{BANNED}最佳多可以有4个PCM实例。一个pcm实例对应一个pcm设备文件。实例数目的限制来源于 Linux设备数目的可用位大小,一旦当64位设备号码被使用,我们可以得到更多的pcm实例。

pcm实例包括pcm回放和录音流,并且每个pcm流包括一个或者多个pcm子流.一些声卡支持多个回放函数.例如, emu10k1有一个32个立体声子流的PCM回放.在这种情况下,每一次打开 ,一个空闲的子流自动被选择并被打开。同时,当只有一个子流并且该子流已经被打开的时候,接下来的打开要么被阻塞,要么根据文件打开模式返回EAGAIN错误.但是你没必要在你的驱动中关心这些细节。PCM中间层将负责这些工作.


完整代码的例子

下面的例子代码没有包括任何的硬件访问的例程,只是展示它的架构,怎么去建立PCM接口.

例子5.1. PCM例子代码

。。。。。。





阅读(2314) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~