![第2課1.節(jié)和圖片源碼聲卡uda1341驅(qū)動分析alsa_第1頁](http://file4.renrendoc.com/view/3db31896da3855e94c744fa0e9c9d45b/3db31896da3855e94c744fa0e9c9d45b1.gif)
![第2課1.節(jié)和圖片源碼聲卡uda1341驅(qū)動分析alsa_第2頁](http://file4.renrendoc.com/view/3db31896da3855e94c744fa0e9c9d45b/3db31896da3855e94c744fa0e9c9d45b2.gif)
![第2課1.節(jié)和圖片源碼聲卡uda1341驅(qū)動分析alsa_第3頁](http://file4.renrendoc.com/view/3db31896da3855e94c744fa0e9c9d45b/3db31896da3855e94c744fa0e9c9d45b3.gif)
![第2課1.節(jié)和圖片源碼聲卡uda1341驅(qū)動分析alsa_第4頁](http://file4.renrendoc.com/view/3db31896da3855e94c744fa0e9c9d45b/3db31896da3855e94c744fa0e9c9d45b4.gif)
![第2課1.節(jié)和圖片源碼聲卡uda1341驅(qū)動分析alsa_第5頁](http://file4.renrendoc.com/view/3db31896da3855e94c744fa0e9c9d45b/3db31896da3855e94c744fa0e9c9d45b5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、UDA1341 驅(qū)動分析(1)_標準 ALSA1.snd_card 可以說是整個 ALSA 音頻驅(qū)動最頂層的一個結(jié)構(gòu),整個聲卡的邏輯結(jié)構(gòu)開始于該結(jié)構(gòu),幾乎所有與聲音相關(guān)的邏輯設(shè)備都是在 snd_card snd_card 結(jié)構(gòu)體。聲卡的邏輯結(jié)構(gòu)如下圖所示:的管理之下,聲卡驅(qū)動的第一個動作通常就是創(chuàng)建一個標準的 alsa 驅(qū)動結(jié)構(gòu)體關(guān)系:上圖的展開:(1).卡(snd_card)的創(chuàng)建:struct snd_card *card;/ snd_card 是聲卡的總部,任何聲卡都必須創(chuàng)建該結(jié)構(gòu)體card = snd_card_new(-1, id, THIS_MODULE, sizeof(struc
2、t sa11xx_uda1341);/ 創(chuàng)建 snd_card注意:創(chuàng)建 snd_card,新版本的內(nèi)核用 snd_card_create()。snd_card 結(jié)構(gòu)體的關(guān)鍵成員:struct snd_card struct list_head devi; /* devi*/struct list_head controls; /* all controls for this card */void *private_data;/* private data for soundcard */struct list_head devistruct list_head controlsvoid *
3、private_data該聲卡下所有邏輯設(shè)備的鏈表 該聲卡下所有的控制單元的鏈表聲卡的私有數(shù)據(jù),可以在創(chuàng)建聲卡時通過參數(shù)指定數(shù)據(jù)的大小(2).創(chuàng)建聲卡的功能(邏輯設(shè)備),例如 PCM,Mixer,MIDI 等:還記得上面提到的snd_card 結(jié)構(gòu)體的devi來生成一個 snd_device 實例,并把該實例字段嗎?每一種的創(chuàng)建最終會調(diào)用snd_device_new()鏈表中。通常,alsa-driver 的已經(jīng)提供到 snd_card 的 devi了一些常用的功能創(chuàng)建 PCM創(chuàng)建RAWMIDI創(chuàng)建 CONTROL的創(chuàng)建接口函數(shù),而不必直接調(diào)用 snd_device_new(),比如: snd
4、_pcm_new()snd_rawmidi_new()snd_ctl_create()創(chuàng)建 TIMERsnd_timer_new()創(chuàng)建 INFOsnd_card_proc_new()創(chuàng)建 JACKsnd_jack_new()注意:創(chuàng)建 PCM( snd_pcm() )是常用的(其次是 CONTROL):a. snd_pcm() 是掛在 snd_card 下面的一個 snd_device , 每一種的創(chuàng)建最終會調(diào)用snd_device_new()來生成一個 snd_device 實例(一般不會直接調(diào)用該函數(shù),而是通過常用的功能的創(chuàng)建接口函數(shù)(如 snd_pcm_new()來間接調(diào)用該函數(shù)),并
5、把該實例到 snd_card 的devi鏈表中;b. snd_pcm 中的字段( struct snd_pcm_str streams2 ),該數(shù)組中的兩個元素指向兩個 snd_pcm_str 結(jié)構(gòu),分別代表 playback stream 和 capture stream;c. snd_pcm_str 中的( struct snd_pcm_substream *substream )字段,指向 snd_pcm_substream 結(jié)構(gòu);d. snd_pcm_substream 是pcm 中間層的,絕大部分任務都是在 substream 中處理,尤其是他的 ops(struct snd_pcm
6、_ops *ops )字段,許多 user 空間的應用程序通過 alsa-lib 對驅(qū)動程序的請求都是由該結(jié)構(gòu)中的函數(shù)處理。它的( struct snd_pcm_runtime *runtime )字段則指向 snd_pcm_runtime 結(jié)構(gòu),snd_pcm_runtime這 substream 的一些重要的總結(jié):硬件運行環(huán)境和參數(shù);一個 pcm 實例(snd_pcm)由一個 playback stream 和一個 capture stream 組成,這兩個 stream 又分別由一個或多個 substreams 組成(一般是一個)。2.snd_pcm_substream 是 pcm 中間
7、層的,絕大部分任務都是在 substream 中處理,尤其是他的 ops(struct snd_pcm_ops *ops )字段,許多 user 空間的應用程序通過 alsa-lib 對驅(qū)動程序的請求都是由該結(jié)構(gòu)中的函數(shù)處理。它的( struct snd_pcm_runtime *runtime )字段則指向 snd_pcm_runtime 結(jié)構(gòu),snd_pcm_runtime這 substream 的一些重要的硬件運行環(huán)境和參數(shù)。當 PCM 子流被打開后,PCM 運行時實例(定義為結(jié)構(gòu)體 snd_pcm_runtime)將被分配給這個子流,這個指針通過 substream-runtime 獲
8、得。運行時指針包含各種各樣的信息:hw_params 及 sw_params 配置的拷貝、緩沖區(qū)指針、mmap的所有控制信息均能從中取得。struct snd_pcm_ops (*open)(struct snd_pcm_substream *substream); (*close)(struct snd_pcm_substream *substream);、自旋鎖等,幾乎 PCM(*ioctl)(struct snd_pcm_substream * substream, unsignedcmd, void *arg);(*hw_params)(struct snd_pcm_substream
9、 *substream, struct snd_pcm_hw_params *params); (*hw_free)(struct snd_pcm_substream *substream);(*prepare)(struct snd_pcm_substream *substream);(*trigger)(struct snd_pcm_substream *substream,cmd);snd_pcm_uframes_t (*poer)(struct snd_pcm_substream *substream);(*copy)(struct snd_pcm_substream *substre
10、am,channel, snd_pcm_uframes_t,void user *buf, snd_pcm_uframes_t count);(*silence)(struct snd_pcm_substream *substream,channel, snd_pcm_uframes_t,snd_pcm_uframes_t count); struct page *(*page)(struct snd_pcm_substream *substream, unsigned long offset);(*mmap)(struct snd_pcm_substream *substream, stru
11、ct vm_area_struct *vma);(*ack)(struct snd_pcm_substream *substream);3.設(shè)備文件的建立 ALSA 聲卡驅(qū)動程序框架:(sound/core/sound.c)注意:sound.c 在聲卡驅(qū)動中扮演的角色和 inp在輸入子系統(tǒng)中扮演的角色一樣!sic const struct file_operationd_fops =.owner = THIS_MODULE,.open =snd_open;sic init alsa_sound_init(void)if (register_chrdev(major, alsa, &snd_fo
12、ps)/ 該major 和創(chuàng)建pcm 設(shè)備時的device_create 時的major/ 是同一個=app:open (應用程序使用 open 函數(shù),內(nèi)核就創(chuàng)建一個 struct file 結(jié)構(gòu),并初始化 f_op = input_fops,等).open = snd_open (最終會調(diào)用到驅(qū)動程序 sound.c 中 open 函數(shù))=問:當看上面的 file_operations 結(jié)構(gòu)體的時候, 發(fā)現(xiàn)里面只有一個 open 函數(shù)? 那是怎么來實現(xiàn)一系列的其他的操作的呢(讀,寫.)?答:可以猜測出,一定是在這個 open 函數(shù)里面做了一些設(shè)置,然后在新的設(shè)置里面來進行相關(guān)的操作。sics
13、nd_open(struct inode *inode, struct file *file)unsignedminor = iminor(inode);/ 獲得次設(shè)備號mptr = snd_minorsminor;/ 以次設(shè)備號為下標,獲得 snd_minor 結(jié)構(gòu)體file-f_op = fops_get(mptr-f_ops);/重新初始化struct file 結(jié)構(gòu)中的成員f_op,讓它指向新的f_ops! if (file-f_op-open) err = file-f_op-open(inode, file);/ 如果新的 f_ops 中有 open 函數(shù),則調(diào)用 open 函數(shù)問
14、:從分析以上 open 函數(shù)時,發(fā)現(xiàn)會從一個 snd_minors 數(shù)組中來獲取一個 snd_minor 結(jié)構(gòu)體,進而獲取他的成員 fops(即新的 file_operations 結(jié)構(gòu)體),從而構(gòu)建出了一個新的 file_operations 結(jié)構(gòu)體,那么上述 snd_minors 數(shù)組是由設(shè)置的呢?答:發(fā)現(xiàn) snd_minors 是一個靜態(tài)變量,所以它只能被本程序中的某一個函數(shù)來設(shè)置,經(jīng)收索最終發(fā)現(xiàn),它在驅(qū)動函數(shù)中的 snd_register_device_for_dev()函數(shù)中被設(shè)置!具體分析如下:snd_register_device_for_dev(type, struct snd
15、_card *card,dev, const struct file_operations *f_ops,void *private_data, const char *name, struct device *device)/* 1.分配并初始化一個 snd_minor 結(jié)構(gòu)中的各字段 */ struct snd_minor *preg;preg = kmalloc(sizeof *preg, GFP_KERNEL);preg-type = type;/ 即為 SNDRV_DEVICE_TYPE_PCM_PLAYBACK 等preg-card = card ? card-number : -
16、1;/ card 的,大多數(shù)情況為 0preg-device = dev;preg-f_ops = f_ops;/ pcm 實例的/ snd_pcm_f_opspreg-private_data = private_data;/ 指向該 pcm 的實例minor = snd_kernel_minor(type, card, dev);/ 找到一個符合要求的次設(shè)備號/* 2.根據(jù)type,card 和pcm 的,確定數(shù)組的索引值 minor,minor 也作為 pcm 設(shè)備的次設(shè)備號*/#ifdef CONFIG_SND_DYNAMIC_MINORSminor = snd_find_free_m
17、inor(); #elseminor = snd_kernel_minor(type, card, dev); if (minor = 0 & snd_minorsminor)minor = -EBUSY;#endif/* 3.把上面分配和設(shè)置好的 snd_minor 結(jié)構(gòu)的地址放入全局數(shù)組 snd_minorsminor中 */snd_minorsminor = preg;/ 以次設(shè)備號為下標,填充該 snd_minors 數(shù)組/* 4.創(chuàng)建設(shè)備節(jié)點:pcmC%iD%ip、pcmC%iD%ic */preg-dev = device_create(sound_class, device, M
18、KDEV(major, minor),private_data, %s, name);/ 在類下面創(chuàng)建設(shè)備節(jié)點,從而產(chǎn)生“pcmCxDxi(c/p)兩”問:經(jīng)過以上的分析,snd_register_device_for_dev()函數(shù)會去設(shè)置 snd_minors 數(shù)組,那么這個函數(shù)又由誰來調(diào)用呢?即它的參數(shù)由傳入?答:snd_pcm_dev_register()函數(shù)會調(diào)用到該函數(shù)!具體如下:sicsnd_pcm_dev_register(struct snd_device *device)struct snd_pcm *pcm;/ 定義一個 snd_pcm 結(jié)構(gòu)體指針 pcm = devic
19、e-device_data;/ 獲得 snd_pcm 結(jié)構(gòu)體 err = snd_pcm_add(pcm);/ 把 pcm 放入鏈表 ?for (cidx = 0; cidx card-number, pcm-device); devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;break;case SNDRV_PCM_STREAM_CAPTURE:sprf(str, pcmC%iD%ic, pcm-card-number, pcm-device); devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;break;/* registcm
20、 */err = snd_register_device_for_dev(devtype, pcm-card, pcm-device,&snd_pcm_f_opscidx, pcm, str, dev);注意:到這里為止,上述驅(qū)動程序已經(jīng)為創(chuàng)建了一個而標準的與用戶空間交互的 file_operations 結(jié)構(gòu)體數(shù)組 snd_pcm_f_opscidx,那么以后用戶空間對驅(qū)動進行 open、read、write 等操作的時候,最終都會調(diào)用到 snd_pcm_f_opscidx數(shù)組中的 file_operations 結(jié)構(gòu)體中的接口函數(shù),具體的在后面會進行分析!后面接下來的分析,可以理解為創(chuàng)建聲
21、卡的功能和傳遞創(chuàng)建設(shè)備節(jié)點需要的參數(shù)的過程。(邏輯設(shè)備)的過程(例如 PCM,Mixer,MIDI 等)問:snd_pcm_dev_register()函數(shù)被誰調(diào)用?即 snd_device 參數(shù)由誰傳入?答:經(jīng)搜索發(fā)現(xiàn),snd_pcm_dev_register()函數(shù)會被自己寫的聲卡驅(qū)動來調(diào)用!具體分析,參考后面的驅(qū)動函數(shù)的過程 snd_card_register();snd_card_register(struct snd_card *card)/熟悉的卡的函數(shù):snd_card_register()/*1.創(chuàng)建 sysfs 下的設(shè)備:sound_class 是在/sound/sound_
22、core.c 中創(chuàng)建的。*/if (!card-card_dev) card-card_dev = device_create(sound_class, card-dev, MKDEV(0, 0), card,card%i, card-number);/*2.通過 snd_device_register_all()實際上是通過 snd_card 的deviregister()來實現(xiàn)各自設(shè)備的*/ snd_device_register_all()所有掛在該聲卡(snd_card)下的邏輯設(shè)備,snd_device_register_all()鏈表,遍歷所有的 snd_device,并且調(diào)用 s
23、nd_device 的 ops-dev_。/*通過 snd_card 的devi鏈表,遍歷所有的 snd_device,并且調(diào)用 snd_device 的 ops-dev_register()來實現(xiàn)各自設(shè)備(如 PCM、CONTROL 等)的*/list_for_each_entry(dev, &card-devi, list) err = dev-ops-dev_register(dev);/1.PCM 設(shè)備的,即 snd_pcm_dev_register 函數(shù)/2.CONTROL 設(shè)備的,即 snd_ctl_dev_register 函數(shù)問:dev-ops-dev_register()這個
24、過程的初始化是在哪里發(fā)生的?答:在創(chuàng)建聲卡的功能等函數(shù)。(邏輯設(shè)備)的接口函數(shù)實現(xiàn)過程中被設(shè)置,如 snd_pcm_new()、snd_ctl_create()以 PCM 的建立過程為例,具體實現(xiàn)過程如下:struct snd_pcm *pcm;ret = snd_pcm_new(card, PXA2xx-PCM, 0, 1, 1, &pcm);參數(shù) 0:card,表示該過程創(chuàng)建的 pcm 將掛載到哪個聲卡(snd_card)中去;參數(shù) 1:id,是一個字符串,表示該 pcm 的標識符;參數(shù) 2:device,表示目前創(chuàng)建的是該聲卡下的第幾個 pcm,第一個 pcm 設(shè)備從 0 開始;參數(shù) 3
25、:playback_count,表示該 pcm 將會有幾個 playback substream;參數(shù) 4:capture_count,表示該 pcm 將會有幾個 capture substream;參數(shù) 5:rpcm,表示要創(chuàng)建的 pcm(snd_pcm);snd_pcm_new(struct snd_card *card, const char *id,device,playback_count,capture_count,struct snd_pcm * rpcm)struct snd_pcm *pcm;/ 定義一個 snd_pcm 結(jié)構(gòu)體指針sic struct snd_device_
26、ops ops = .dev_free = snd_pcm_dev_free,.dev_register =snd_pcm_dev_register,/ 這便是前面調(diào)用到的函數(shù).dev_disconnect = snd_pcm_dev_disconnect,;pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);/ 分配一個 snd_pcm 結(jié)構(gòu)體if (err = snd_pcm_new_streif (err = snd_pcm_new_strecm, SNDRV_PCM_STREAM_PLAYBACK, playback_count) 0)/ ?cm, SNDR
27、V_PCM_STREAM_CAPTURE, capture_count) 0)/ ?if (err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops) card = card;dev-type = type;dev-se = SNDRV_DEV_BUILD;dev-device_data = device_data;dev-ops = ops;list_add(&dev-list, &card-devi/ 會在聲卡的); /* 把該實例階段(snd_card_register)被調(diào)用到 snd_card 的devi鏈表中 */前面提到過,當應用程序
28、對驅(qū)動進行 open、read、write 等操作的時候,最終都會調(diào)用到 snd_pcm_f_opscidx數(shù)組中的 file_operations 結(jié)構(gòu)體(由 snd_pcm_dev_register()函數(shù)傳入),該數(shù)組是系統(tǒng)為好的,具體如下:設(shè)置const struct file_operationd_pcm_f_ops2 = / 用于.owner =.write =.aio_write =.open =.release =.llseek =.poll =的!THIS_MODULE,snd_pcm_write,snd_pcm_aio_write, snd_pcm_playback_ope
29、n,snd_pcm_release, no_llseek,snd_pcm_playback_poll,.unlocked_ioctl =.compat_ioctl =.mmap =snd_pcm_playback_ioctl,pat,snd_pcm_mmap,.fasync =snd_pcm_fasync,.get_unmapped_area = snd_pcm_get_unmapped_area,/ 用于.owner =.read =.aio_read =.open =.release =.llseek =.poll =的!THIS_MODULE,snd_pcm_read, snd_pcm_
30、aio_read, snd_pcm_capture_open,snd_pcm_release, no_llseek,snd_pcm_capture_poll,.unlocked_ioctl =.compat_ioctl =.mmap =snd_pcm_capture_ioctl,pat,snd_pcm_mmap,.fasync =snd_pcm_fasync,.get_unmapped_area = snd_pcm_get_unmapped_area,;總結(jié):(以應用程序調(diào)用 open 函數(shù)為例) app:open.open = snd_open (最終會調(diào)用到驅(qū)動程序 sound.c 中 o
31、pen 函數(shù),這里只是給 f_ops 重新賦值,見上文).open = snd_pcm_playback_open (經(jīng)過上面的重新賦值以后,最終會用到 snd_pcm_f_ops2中的 ops)具體實現(xiàn)如下:sicsnd_pcm_playback_open(struct inode *inode, struct file *file)return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);sicsnd_pcm_open(struct file *file, struct snd_pcm *pcm,stream)while (1) e
32、rr = snd_pcm_open_file(file, pcm, stream, &pcm_file);sicsnd_pcm_open_file(struct file *file, struct snd_pcm *pcm,stream,struct snd_pcm_file *rpcm_file)err = snd_pcm_open_substrecm, stream, file, &substream);snd_pcm_open_substream(struct snd_pcm *pcm,stream, struct file *file,struct snd_pcm_substream
33、 *rsubstream)err = substream-ops-open(substream);問:經(jīng)過上面的總結(jié)分析,發(fā)現(xiàn) open 的過程,最終會調(diào)用到 snd_pcm_substream 結(jié)構(gòu)體中的 ops 中的 open函數(shù),那么該 snd_pcm_substream 結(jié)構(gòu)體中的成員是在哪里被設(shè)置和初始化的呢?答:該過程目前沒有跟通,大體推測如下:函數(shù) 1:snd_pcm_new_stre函數(shù) 2:snd_pcm_new_strecm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)cm, SNDRV_PCM_STREAM_CAPTURE, ca
34、pture_count)函數(shù) 1、函數(shù) 2 應該是完成 snd_pcm 結(jié)構(gòu)體下的 snd_pcm_str 結(jié)構(gòu)體(即 streams2)的分配和設(shè)置相關(guān)成員,并且會重點分配和設(shè)置 snd_pcm_substream 結(jié)構(gòu)體(不會設(shè)置 ops)。那么 ops 在哪里設(shè)置呢?在 snd_pcm_set_ops()函數(shù)中設(shè)置了,詳情如下:void snd_pcm_set_ops(struct snd_pcm *pcm,direction, struct snd_pcm_ops *ops)struct snd_pcm_str *stream = &pcm-streamsdirection; struct snd_pcm_substream *substream;for (substre
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 美食行業(yè)廚師助理工作總結(jié)
- 質(zhì)量管理在研發(fā)流程中的作用培訓
- 藥店衛(wèi)生整頓要領(lǐng)
- 部編初中歷史八下第17課外交事業(yè)的發(fā)展教案
- 2025年全球及中國商用儲水式熱水器行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025年全球及中國推拉式酸洗線行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025-2030全球第三人稱射擊游戲行業(yè)調(diào)研及趨勢分析報告
- 2025年全球及中國新能源汽車隱形門把手行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025-2030全球基于人工智能的傷口護理軟件行業(yè)調(diào)研及趨勢分析報告
- 2025年全球及中國高舉裝載機行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 長江委水文局2025年校園招聘17人歷年高頻重點提升(共500題)附帶答案詳解
- 2025年湖南韶山干部學院公開招聘15人歷年高頻重點提升(共500題)附帶答案詳解
- 智研咨詢發(fā)布:2024年中國MVR蒸汽機械行業(yè)市場全景調(diào)查及投資前景預測報告
- IF鋼物理冶金原理與關(guān)鍵工藝技術(shù)1
- JGJ46-2024 建筑與市政工程施工現(xiàn)場臨時用電安全技術(shù)標準
- 煙花爆竹重大危險源辨識AQ 4131-2023知識培訓
- 銷售提成對賭協(xié)議書范本 3篇
- EPC項目階段劃分及工作結(jié)構(gòu)分解方案
- 《跨學科實踐活動4 基于特定需求設(shè)計和制作簡易供氧器》教學設(shè)計
- 2024-2030年汽車啟停電池市場運行態(tài)勢分析及競爭格局展望報告
- 術(shù)后病人燙傷不良事件PDCA循環(huán)分析
評論
0/150
提交評論