1、声卡驱动程序sound.c

(1)入口函数里通过register_chrdev()函数注册file_operations 结构体

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)file_operations 结构体,里面只有open函数,没有发现读写函数,可知open函数是起中转作用的函数,肯定会找到一个新的file_operations 结构体

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(3)调用过程

  • ALSA声卡笔记1---ALSA驱动框架-LMLPHP以minor变量保存传入节点inode结构体的次设备号
  • ALSA声卡笔记1---ALSA驱动框架-LMLPHP以minor为下标在结构体数组中取出一项,让mptr指针指向此项
  • ALSA声卡笔记1---ALSA驱动框架-LMLPHP表示取出mptr结构体指针里的file_operations
    结构体
  • ALSA声卡笔记1---ALSA驱动框架-LMLPHP调用file_operations
    结构体里面的open函数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

2、谁来设置snd_minors[]结构体数组

(1)谁来设置snd_minors[]结构体数组

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

函数里面有数组项snd_minors外,为了mdev或udev能自动创建设备节点,我们有class_create()函数创建类,下面创建设备device_create(),类在Sound_
core.c入口函数里面被创建,sound.c的入口函数里面注册字符设备函数,snd_register_device_for_dev()函数里面创建声卡逻辑设备时有device_create()

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)snd_register_device_for_dev()函数被谁调用(有两路调用)

一路(声卡设备的控制接口)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

另一路(声卡设备的数据接口)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

两路分析之---第一路

3、第一路调用分析

(1)snd_register_device()被谁调用(Core.h)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)创建声卡设备的控制接口函数snd_ctl_dev_register()被谁调用(control.c)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(3)由上面可知函数snd_ctl_create()在init.c程序的

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

中被调用

(4)由ALSA声卡笔记1---ALSA驱动框架-LMLPHP可知创建一个snd_card结构体

两路分析之---第二路

4、第二路调用分析

(1)创建声卡设备的数据接口函数snd_pcm_dev_register()函数被谁调用(Pcm.c)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)创建一个新的PCM设备函数_snd_pcm_new()被谁调用

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(3)snd_pcm_new()被谁调用

某个声卡的驱动程序

5、代码框架重新梳理(第1路)

(1)snd_card_create()函数(Init.c)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

除了创建一个snd_card结构体外,还会调用snd_ctl_create()

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

这表示所有声卡里面,必定会有控制接口

(2)创建控制类的逻辑设备snd_ctl_create()函数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

里snd_device_new()函数可以看出,对于同一个声卡,里面可能有多个逻辑设备,device应该就是逻辑设备的意思(有control、pcm等),参数SNDRV_DEV_CONTROL表示其类别,最终snd_ctl_dev_register()被调用

(3)snd_ctl_dev_register()函数

里面的snd_register_device()函数注册一个file_operations 结构体snd_ctl_f_ops

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(4)snd_register_device()函数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(5)snd_register_device_for_dev()函数

填充结构体数组snd_minors[]

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

6、代码框架重新梳理(第2路)

(1)snd_pcm_new()调用

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)_snd_pcm_new()调用  (创建播放流和录音流)

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

创建声卡的逻辑设备,这个逻辑设备最后会导致snd_pcm_dev_register()函数被调用

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(3)snd_pcm_dev_register()函数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(4)snd_pcm_f_ops结构体数组,第0项表示播放,第1项表示录音,在Pcm.c里

7、创建设备节点的名字的取值(第1路)

(1)snd_register_device_for_dev()函数里的device_create()函数,其中“%s”来源于name,这个name是snd_register_device_for_dev()函数传进来的参数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)snd_register_device_for_dev()函数被 snd_register_device()函数调用,也就是snd_register_device_for_dev()函数里面的name参数是 snd_register_device()函数传过来的

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(3)snd_register_device()函数被 snd_ctl_dev_register()函数调用,由下面可以看出name参数根据ALSA声卡笔记1---ALSA驱动框架-LMLPHP可知为controlC%i,C表示Card声卡,其中i值来源于右边的cardnum,这个cardnum来源于snd_card结构体中的成员。而snd_card结构体来源于snd_device结构体的snd_card结构体。

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

8、创建设备节点的名字的取值(第2路)

(1)snd_register_device_for_dev()函数里的device_create()函数,其中“%s”来源于name,这个name是snd_register_device_for_dev()函数传进来的参数

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

(2)snd_register_device_for_dev()函数被snd_pcm_dev_register()函数调用

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

里面的str参数正是name参数,下面有pcmC%iD%ip和pcmC%iD%ic,C表示Card的意思,%i表示哪一个声卡,D表示哪一个声卡下的哪一个逻辑设备,p表示播放,c表示录音

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

9、总结(如何写alsa声卡驱动)

(1)构造snd_card结构体,snd_card_create()构造snd_card结构体并自动创建控制接口。调用函数snd_ctrl_create

(2)初始化;如snd_pcm_new(),创建逻辑设备(播放设备或录音设备)

(3)注册 snd_card_register

ALSA声卡笔记1---ALSA驱动框架-LMLPHP

转自:http://blog.csdn.net/qingkongyeyue/article/details/52328991

05-12 17:27