zoukankan      html  css  js  c++  java
  • 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,

  • 相关阅读:
    HTML 标签元素的 align 属性
    JS计算时间差值
    ICPC Southeastern Europe Contest 2019 BDFIJ
    ICPC Latin American Regional Contests 2019 EGIKLM
    UCF Local Programming Contest 2017 ABCDEFGHI
    Codeforces #631 Dreamoon Likes Coloring
    Problem Palindrome
    Problem Toki’s function
    UCF “Practice” Local Contest — Aug 25, 2018 Boots Exchange 水题
    UCF “Practice” Local Contest — Aug 25, 2018 Rummy Score
  • 原文地址:https://www.cnblogs.com/linucos/p/3007226.html
Copyright © 2011-2022 走看看