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,


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM