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,

  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/linucos/p/3007226.html
Copyright © 2011-2022 走看看