大运天成赖搏击

进步最重要

导航

alsa驱动分析(1)

0.       ALSA驱动分析

a)         重要数据结构

                         i.              snd_minors 维护了所有声音主设备的次设备信息,次设备号是下标

1.         信息包括类型,文件操作,私有数据等

b)         重要概念

                         i.              alsa逻辑设备包括:controlCxx,pcmCxDxp,pcmCxDxc,timer,seq

1.         controlCxx用于直接读写codec寄存器,打开关闭开关,调节滑块如音量等

2.         pcmCxDxp用于播放,就是playback,关键接口是writeioctl

3.         pcmCxDxc 用于录制,就是capture,关键接口是readioctl

4.         timerseq作用不明显

                       ii.              alsa框架基于字符设备,上边提到的都是alsa逻辑设备,也就是说是同一个主设备下的次设备,共享同一个驱动入口

1.         alsa_sound_init(Sound.c)注册了主设备号为major(CONFIG_SND_MAJOR)的字符设备文件,文件操作是snd_fopssnd_open接口比较重要,snd_open接口通过文件节点inode得到了次设备号,通过snd_minors数组得到对应的声音逻辑设备的文件操作,调用对应的open接口,并调用fops_put替换成了对应的逻辑设备的文件操作(snd_minors里维护).

                      iii.              Alsa声音设备驱动probe流程

1.         参考atmel_abdac_probe (abdac.c)接口流程

2.         snd_card_create – 创建声卡

a)         接口里,会自动调用snd_ctl_create创建control逻辑设备

3.         snd_ctl_create 创建control逻辑设备

a)         调用snd_device_new,传递snd_device_ops ops,这个ops很关键

                                                                   i.              snd_device_new接口把control逻辑设备放在了card->devices

b)         ops中的snd_ctl_dev_register接口,实际会被下边的snd_card_register接口调用到,snd_ctl_dev_register接口调用snd_register_device,传递snd_ctl_f_ops这个ops就是实际使用到的control设备的文件操作.

4.         snd_pcm_new创建pcm逻辑设备

a)         _snd_pcm_new创建

                                                                   i.              调用snd_device_new,传递snd_device_ops ops,类似control设备,

                                                                 ii.              ops里的snd_pcm_dev_register接口,会被snd_card_register调用,调用snd_register_device_for_dev传递snd_pcm_f_ops,这个ops就是实际pcm逻辑设备使用到的文件操作,这个接口里还调用snd_pcm_timer_init创建了timer设备

                                                                iii.              调用snd_pcm_new_stream两次,分别建立了playbackcapture连个substream.

                                                                iv.              注意,每个pcm逻辑设备包括了两个substreamPLAYBACKCAPTUREsnd_pcm_f_ops有对应的两类ops.

5.         snd_pcm_set_ops接口用来设备pcm设备,流的操作,流的操作会被pcm逻辑设备的文件操作所回调.

6.         snd_card_register注册声卡

a)         调用device_create创建设备

b)         调用snd_device_register_all注册声卡所有的逻辑设备,调用了之前注册的card->devices里的所有逻辑设备的dev->ops->dev_register接口.

c)         至此,逻辑设备节点就建立了.

                      iv.              逻辑设备打开

1.         上边分析,所有音频设备都是声卡的次设备,主设备相同,共snd_open接口,snd_open接口里会调用对应逻辑设备的open,并替换文件操作为逻辑设备的文件操作.

2.         Control设备

a)         snd_ctl_f_ops中的snd_ctl_opencontrol逻辑设备打开时本snd_open调用.

b)         snd_ctl_open

                                                                   i.              snd_minors中存储的control逻辑设备的私有数据是snd_card *card

                                                                 ii.              创建一个snd_ctl_file *ctl,同时设备card数据

                                                                iii.              snd_ctl_file *ctl作为这个file private_data,以备后用

3.         Pcm设备

a)         snd_pcm_f_ops中的snd_pcm_playback_opensnd_pcm_capture_open分别对应pcmXXXppcmXXXc逻辑设备的打开.

b)         snd_pcm_playback_open

                                                                   i.              调用snd_lookup_minor_data拿到snd_minors保存的私有数据,是snd_pcm *pcm

                                                                 ii.              接着调用snd_pcm_open

1.         snd_pcm_open调用snd_pcm_open_filesnd_pcm_open_file调用snd_pcm_open_substream打开substreamsubstream被填充赋值.

2.         之后snd_pcm_open_filesubstream填充了snd_pcm_file *pcm_file,作为filefile->private_data.

c)         snd_pcm_capture_open

                                                                   i.              snd_pcm_playback_open几乎相同.

                       v.              Pcm逻辑设备文件操作分析

1.         snd_pcm_f_ops结构包括了playbackcapture两个流,对应pcmXXXppcmXXXc两个逻辑设备的文件操作.

2.         pcm操作过程中,pcm逻辑设备的文件操作不停的被调用,alsa实现了pcm逻辑设备的操作,而alsa允许真正的设备相关的操作是留给上层驱动的接口,也就是substreamops,所有的substream ops都会在适当的时机被调用.Asocalsa驱动的有一层封装,Asoc正是封装了substream的接口以此来提供Asoc逻辑层的machine/platform/codec/dai的逻辑操作.

3.         Playback

                                                                   i.              .open =                       snd_pcm_playback_open,

1.         snd_lookup_minor_data查找逻辑设备数据

2.         snd_pcm_open打开pcm播放流

a)         snd_pcm_open_file

                                                                                                             i.              snd_pcm_open_substream创建substream

a)         snd_pcm_attach_substream

b)         snd_pcm_hw_constraints_init 初始化常量

c)         snd_pcm_hw_constraints_complete初始常量

                                                                                                           ii.              file->private_data = pcm_file;设置file的私有数据

                                                                                                          iii.              设置了substreamruntime数据

3.         打开完成.

                                                                 ii.              .write =             snd_pcm_write,

1.         取出file私有数据pcm_file

2.         取出pcm_filesubstream

3.         取出substreamruntime

4.         调用snd_pcm_lib_write

a)         调用snd_pcm_lib_writ传递snd_pcm_lib_write_transfer接口

                                                                                                             i.              snd_pcm_lib_write_transfer接口被调用传递数据.

                                                                                                           ii.              写到了runtime->dma_area区域

                                                                                                          iii.              判断是prepared状态,并且snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold,调用snd_pcm_start接口

a)         实际会调用到snd_pcm_action_start里的接口substream->ops->trigger最后后被调用到.

b)         这样就开始了dma传送数据的过程.

                                                                iii.              .aio_write =               snd_pcm_aio_write,

1.         TODO

                                                                iv.              .release =                   snd_pcm_release,

1.         TODO

                                                                 v.              .llseek =             no_llseek,

1.         TODO

                                                                vi.              .poll =                          snd_pcm_playback_poll,

1.         TODO

                                                              vii.              .unlocked_ioctl =      snd_pcm_playback_ioctl,

1.         snd_pcm_playback_ioctl1

a)         判断命令动作类型,包括很多

                                                                                                             i.              SNDRV_PCM_IOCTL_WRITEI_FRAMES 写数据

                                                                                                           ii.              SNDRV_PCM_IOCTL_HW_PARAMS 设置参数

                                                                                                          iii.              SNDRV_PCM_IOCTL_PREPARE 准备流

                                                                                                          iv.              SNDRV_PCM_IOCTL_START 开始流

                                                             viii.              .compat_ioctl =       snd_pcm_ioctl_compat,

1.         TODO

                                                                ix.              .mmap =                     snd_pcm_mmap,

1.         TODO

                                                                 x.              .fasync =           snd_pcm_fasync,

1.         TODO

                                                                xi.              .get_unmapped_area = snd_pcm_get_unmapped_area,

1.         TODO

4.         Capture

                                                            i.              .open =                            snd_pcm_capture_open,

1.         类似snd_pcm_playback_open

                                                          ii.              .read =                   snd_pcm_read,

1.         snd_pcm_write的流程是相反的

                                                         iii.              .aio_read =           snd_pcm_aio_read,

1.         TODO

                                                         iv.              .release =              snd_pcm_release,

1.         TODO

                                                          v.              .llseek =                 no_llseek,

1.         TODO

                                                         vi.              .poll =                     snd_pcm_capture_poll,

1.         TODO

                                                       vii.              .unlocked_ioctl = snd_pcm_capture_ioctl,

1.         类似snd_pcm_playback_ioctl

                                                      viii.              .compat_ioctl = snd_pcm_ioctl_compat,

1.         TODO

                                                         ix.              .mmap =                         snd_pcm_mmap,

1.         TODO

                                                          x.              .fasync =                snd_pcm_fasync,

1.         TODO

                                                         xi.              .get_unmapped_area =       snd_pcm_get_unmapped_area,

1.         TODO

                      vi.              Control逻辑设备文件操作分析

1.         snd_control_f_ops结构包括了control逻辑设备的文件操作

2.         类似pcm设备,alsa实现了control逻辑设备的文件操作,alsa留给上层驱动的接口是kcontrolkcontrolinfoputget接口被调用.Asoccontrol设备的封装体现在dapm控件以及提供了一些方便实用的宏.

3.         control的控件由驱动实现者类添加,实现.

4.         如下

a)         .open =              snd_ctl_open,

                                                                   i.              TODO

b)         .read =               snd_ctl_read,

                                                                   i.              TODO

c)         .release =         snd_ctl_release,

                                                                   i.              TODO

d)         .llseek =   no_llseek,

                                                                   i.              TODO

e)         .poll =                 snd_ctl_poll,

                                                                   i.              TODO

f)          .unlocked_ioctl =      snd_ctl_ioctl,

                                                                   i.              根据不同的动作,不同的操作,动作由alsa-lib调用

1.         SNDRV_CTL_IOCTL_ELEM_LIST获取所有控件列表

2.         SNDRV_CTL_IOCTL_ELEM_INFO获取指定控件信息

3.         SNDRV_CTL_IOCTL_ELEM_READ读操作

a)         snd_ctl_elem_read_user

                                                                                                             i.              snd_ctl_elem_read

A.        snd_ctl_find_id获取kctl

B.        kctl->get接口被调用

4.         SNDRV_CTL_IOCTL_ELEM_WRITE

a)         类似SNDRV_CTL_IOCTL_ELEM_READ,最终kctl->put被调用

g)         .compat_ioctl =        snd_ctl_ioctl_compat,

h)         .fasync = snd_ctl_fasync,

posted on 2013-04-08 13:11  linucos  阅读(3882)  评论(1编辑  收藏  举报