Linux soc声卡构架分析.docx
《Linux soc声卡构架分析.docx》由会员分享,可在线阅读,更多相关《Linux soc声卡构架分析.docx(60页珍藏版)》请在冰点文库上搜索。
Linuxsoc声卡构架分析
Linuxsoc声卡构架分析(DMA)
以S3C2440为例进行分析,对应的文件linux-2.6.32.2/sound/soc/s3c24xx/s3c24xx_uda134x.c
其中module_init入口内容为:
357staticint__inits3c24xx_uda134x_init(void)
358{
359returnplatform_driver_register(&s3c24xx_uda134x_driver);
360}
359行是一个平台驱动的注册函数,注册的驱动是s3c24xx_uda134x_driver。
内容如下:
348staticstructplatform_drivers3c24xx_uda134x_driver={
349.probe=s3c24xx_uda134x_probe,
350.remove=s3c24xx_uda134x_remove,
351.driver={
352.name="s3c24xx_uda134x",
353.owner=THIS_MODULE,
354},
355};
由上面的name="s3c24xx_uda134x"可知,这个驱动对应的平台设备早在系统启动时在dev_init中注册进来了,所以接下来的事情就是直接调用probe方法。
290staticints3c24xx_uda134x_probe(structplatform_device*pdev)
291{
292intret;
293
294printk(KERN_INFO"S3C24XX_UDA134XSoCAudiodriver\n");
295
296s3c24xx_uda134x_l3_pins=pdev->dev.platform_data;
297if(s3c24xx_uda134x_l3_pins==NULL){
298printk(KERN_ERR"S3C24XX_UDA134XSoCAudio:
"
299"unabletofindplatformdata\n");
300return-ENODEV;
301}
302s3c24xx_uda134x.power=s3c24xx_uda134x_l3_pins->power;
303s3c24xx_uda134x.model=s3c24xx_uda134x_l3_pins->model;
304
305if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
306"data")<0)
307return-EBUSY;
308if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
309"clk")<0){
310gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
311return-EBUSY;
312}
313if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
314"mode")<0){
315gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
316gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
317return-EBUSY;
318}
319
320s3c24xx_uda134x_snd_device=platform_device_alloc("soc-audio",-1);
321if(!
s3c24xx_uda134x_snd_device){
322printk(KERN_ERR"S3C24XX_UDA134XSoCAudio:
"
323"Unabletoregister\n");
324return-ENOMEM;
325}
326
327platform_set_drvdata(s3c24xx_uda134x_snd_device,
328&s3c24xx_uda134x_snd_devdata);
329s3c24xx_uda134x_snd_devdata.dev=&s3c24xx_uda134x_snd_device->dev;
330ret=platform_device_add(s3c24xx_uda134x_snd_device);
331if(ret){
332printk(KERN_ERR"S3C24XX_UDA134XSoCAudio:
Unabletoadd\n");
333platform_device_put(s3c24xx_uda134x_snd_device);
334}
335
336returnret;
337}
305-318行就是设置udal34x要用的gpio引脚的功能。
320-334行是融入soc-core的关键,320行申请的platform_dev是soc-core的device结构。
对应驱动的名称也应该是"soc-audio"。
330行是问题的关键,s3c24xx_uda134x_snd_device注册并与soc-core驱动进行匹配。
相关的内容在linux/sound/soc/soc-core.c文件中。
Soc-core的入口是module_init(snd_soc_init)。
2546staticint__initsnd_soc_init(void)
2547{
2548#ifdefCONFIG_DEBUG_FS
2549debugfs_root=debugfs_create_dir("asoc",NULL);
2550if(IS_ERR(debugfs_root)||!
debugfs_root){
2551printk(KERN_WARNING
2552"ASoC:
Failedtocreatedebugfsdirectory\n");
2553debugfs_root=NULL;
2554}
2555#endif
2556
2557returnplatform_driver_register(&soc_driver);
2558}
2557行是soc-core驱动注册的核心,soc_driver的内容如下:
1057/*ASoCplatformdriver*/
1058staticstructplatform_driversoc_driver={
1059.driver={
1060.name="soc-audio",
1061.owner=THIS_MODULE,
1062.pm=&soc_pm_ops,
1063},
1064.probe=soc_probe,
1065.remove=soc_remove,
1066};
Soc_driver和s3c24xx_uda134x_snd_device的名称匹配,满足mach的基本条件。
后面会调用soc_driver的probe方法进行驱动的进一步枚举。
978/*probesanewsocdev*/
979staticintsoc_probe(structplatform_device*pdev)
980{
981intret=0;
982structsnd_soc_device*socdev=platform_get_drvdata(pdev);
983structsnd_soc_card*card=socdev->card;
984
985/*Bodgewhilewepushthingsoutofsocdev*/
986card->socdev=socdev;
987
988/*Bodgewhileweunpickinstantiation*/
989card->dev=&pdev->dev;
990ret=snd_soc_register_card(card);
991if(ret!
=0){
992dev_err(&pdev->dev,"Failedtoregistercard\n");
993returnret;
994}
995
996return0;
997}
928行是获取平台驱动数据,这里就是前面设置的:
platform_set_drvdata(s3c24xx_uda134x_snd_device,&s3c24xx_uda134x_snd_devdata);
s3c24xx_uda134x_snd_devdata的数据类型为structsnd_soc_device
staticstructsnd_soc_devices3c24xx_uda134x_snd_devdata={
.card=&snd_soc_s3c24xx_uda134x,
.codec_dev=&soc_codec_dev_uda134x,
.codec_data=&s3c24xx_uda134x,
};
Structsnd_soc_device描述了一个soc子系统中的soc设备其成员如下:
structsnd_soc_device{
structdevice*dev;
structsnd_soc_card*card;
structsnd_soc_codec_device*codec_dev;
void*codec_data;
};
首先主要关注structsnd_soc_card*card;这个数据结构,后面的内容就是这张声卡实例化。
475structsnd_soc_card{
476char*name;
477structdevice*dev;
478
479structlist_headlist;
480
481intinstantiated;
482
483int(*probe)(structplatform_device*pdev);
484int(*remove)(structplatform_device*pdev);
485
486/*thepreandpostPMfunctionsareusedtodoanyPMworkbeforeand
487*afterthecodecandDAI'sdoanyPMwork.*/
488int(*suspend_pre)(structplatform_device*pdev,pm_message_tstate);
489int(*suspend_post)(structplatform_device*pdev,pm_message_tstate);
490int(*resume_pre)(structplatform_device*pdev);
491int(*resume_post)(structplatform_device*pdev);
492
493/*callbacks*/
494int(*set_bias_level)(structsnd_soc_card*,
495
496
497/*CPU<-->CodecDAIlinks*/
498structsnd_soc_dai_link*dai_link;
499intnum_links;
500
501structsnd_soc_device*socdev;
502
503structsnd_soc_codec*codec;
504
505structsnd_soc_platform*platform;
506structdelayed_workdelayed_work;
507structwork_structdeferred_resume_work;
508};
接下来进入到snd_soc_register_card(card);函数,这事soc_probe的核心。
2302staticintsnd_soc_register_card(structsnd_soc_card*card)
2303{
2304if(!
card->name||!
card->dev)
2305return-EINVAL;
2306
2307INIT_LIST_HEAD(&card->list);
2308card->instantiated=0;
2309
2310mutex_lock(&client_mutex);
2311list_add(&card->list,&card_list);
2312snd_soc_instantiate_cards();
2313mutex_unlock(&client_mutex);
2314
2315dev_dbg(card->dev,"Registeredcard'%s'\n",card->name);
2316
2317return0;
2318}
函数首先初始化一个list头,并将当前card加入到card_list全局的一张soc声卡链表中。
然后就调用snd_soc_instantiate_cards();来具体实例化一张声卡。
971staticvoidsnd_soc_instantiate_cards(void)
972{
973structsnd_soc_card*card;
974list_for_each_entry(card,&card_list,list)
975snd_soc_instantiate_card(card);
976}
974行遍历card_list然后调用snd_soc_instantiate_card实例化。
840staticvoidsnd_soc_instantiate_card(structsnd_soc_card*card)
841{
842structplatform_device*pdev=container_of(card->dev,
843structplatform_device,
844dev);
845structsnd_soc_codec_device*codec_dev=card->socdev->codec_dev;
846structsnd_soc_platform*platform;
847structsnd_soc_dai*dai;
848inti,found,ret,ac97;
849
850if(card->instantiated)
851return;
852
853found=0;
854list_for_each_entry(platform,&platform_list,list)
855if(card->platform==platform){
856found=1;
857break;
858}
859if(!
found){
860dev_dbg(card->dev,"Platform%snotregistered\n",
861card->platform->name);
862return;
863}
864
865ac97=0;
866for(i=0;inum_links;i++){
867found=0;
868list_for_each_entry(dai,&dai_list,list)
869if(card->dai_link[i].cpu_dai==dai){
870found=1;
871break;
872}
873if(!
found){
874dev_dbg(card->dev,"DAI%snotregistered\n",
875card->dai_link[i].cpu_dai->name);
876return;
877}
878
879if(card->dai_link[i].cpu_dai->ac97_control)
880ac97=1;
881}
882
883for(i=0;inum_links;i++){
884if(!
card->dai_link[i].codec_dai->ops)
885card->dai_link[i].codec_dai->ops=&null_dai_ops;
886}
887
888/*IfwehaveAC97inthesystemthendon'twaitforthe
889*codec.Thiswillneedrevisitingifwehavetohandle
890*systemswithmixedAC97andnon-AC97parts.Onlycheckfor
891*DAIscurrently;wecan'tdothisperlinksincesomeAC97
892*codecshavenon-AC97DAIs.
893*/
894if(!
ac97)
895for(i=0;inum_links;i++){
896found=0;
897list_for_each_entry(dai,&dai_list,list)
898if(card->dai_link[i].codec_dai==dai){
899found=1;
900break;
901}
902if(!
found){
903dev_dbg(card->dev,"DAI%snotregistered\n",
904card->dai_link[i].codec_dai->name);
905return;
906}
907}
908
909/*Notethatwedonotcurrentcheckforcodeccomponents*/
910
911dev_dbg(card->dev,"Allcomponentspresent,instantiating\n");
912
913/*Foundeverything,bringitup*/
914if(card->probe){
915ret=card->probe(pdev);
916if(ret<0)
917return;
918}
919
920for(i=0;inum_links;i++){
921structsnd_soc_dai*cpu_dai=card->dai_link[i].cpu_dai;
922if(cpu_dai->probe){
923ret=cpu_dai->probe(pdev,cpu_dai);
924if(ret<0)
925gotocpu_dai_err;
926}
927}
928
929if(codec_dev->probe){
930ret=codec_dev->probe(pdev);
931if(ret<0)
932gotocpu_dai_err;
933}
934
935if(platform->probe){
936ret=platform->probe(pdev);
937if(ret<0)
938gotoplatform_err;
939}
940
941/*DAPMstreamwork*/
942INIT_DELAYED_WORK(