Linux soc声卡构架分析(DMA)从豆丁上看到的,分析soc声卡初始化过程的。分析的很详细
以S3C2440为例进行分析,对应的文件linux-2.6.32.2/sound/soc/s3c24xx/s3c24xx_uda134x.c
其中module_init入口内容为:
357 static int__init s3c24xx_uda134x_init(void) 358 { 359 returnplatform_driver_register(&s3c24xx_uda134x_driver); 360 }
359行是一个平台驱动的注册函数,注册的驱动是s3c24xx_uda134x_driver。内容如下:
348 static structplatform_driver s3c24xx_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方法。
290 static ints3c24xx_uda134x_probe(struct platform_device *pdev) 291 { 292 int ret; 293 294 printk(KERN_INFO"S3C24XX_UDA134X SoC Audio driver\n"); 295 296 s3c24xx_uda134x_l3_pins= pdev->dev.platform_data; 297 if(s3c24xx_uda134x_l3_pins == NULL) { 298 printk(KERN_ERR"S3C24XX_UDA134X SoC Audio: " 299 "unable to find platform data\n"); 300 return-ENODEV; 301 } 302 s3c24xx_uda134x.power= s3c24xx_uda134x_l3_pins->power; 303 s3c24xx_uda134x.model= s3c24xx_uda134x_l3_pins->model; 304 305 if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, 306 "data") < 0) 307 return-EBUSY; 308 if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, 309 "clk") < 0) { 310 gpio_free(s3c24xx_uda134x_l3_pins->l3_data); 311 return-EBUSY; 312 } 313 if(s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, 314 "mode") < 0) { 315 gpio_free(s3c24xx_uda134x_l3_pins->l3_data); 316 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); 317 return-EBUSY; 318 } 319 320 s3c24xx_uda134x_snd_device= platform_device_alloc("soc-audio", -1); 321 if(!s3c24xx_uda134x_snd_device) { 322 printk(KERN_ERR"S3C24XX_UDA134X SoC Audio: " 323 "Unable to register\n"); 324 return-ENOMEM; 325 } 326 327 platform_set_drvdata(s3c24xx_uda134x_snd_device, 328 &s3c24xx_uda134x_snd_devdata); 329 s3c24xx_uda134x_snd_devdata.dev= &s3c24xx_uda134x_snd_device->dev; 330 ret =platform_device_add(s3c24xx_uda134x_snd_device); 331 if (ret){ 332 printk(KERN_ERR"S3C24XX_UDA134X SoC Audio: Unable to add\n"); 333 platform_device_put(s3c24xx_uda134x_snd_device); 334 } 335 336 returnret; 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)。
2546 static int__init snd_soc_init(void) 2547 { 2548 #ifdefCONFIG_DEBUG_FS 2549 debugfs_root= debugfs_create_dir("asoc", NULL); 2550 if(IS_ERR(debugfs_root) || !debugfs_root) { 2551 printk(KERN_WARNING 2552 "ASoC: Failed to create debugfs directory\n"); 2553 debugfs_root= NULL; 2554 } 2555 #endif 2556 2557 returnplatform_driver_register(&soc_driver); 2558 }
2557行是soc-core驱动注册的核心,soc_driver的内容如下:
1057 /* ASoCplatform driver */ 1058 staticstruct platform_driver soc_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 /* probes anew socdev */ 979 static intsoc_probe(struct platform_device *pdev) 980 { 981 int ret =0; 982 structsnd_soc_device *socdev = platform_get_drvdata(pdev); 983 structsnd_soc_card *card = socdev->card; 984 985 /* Bodgewhile we push things out of socdev */ 986 card->socdev= socdev; 987 988 /* Bodgewhile we unpick instantiation */ 989 card->dev= &pdev->dev; 990 ret =snd_soc_register_card(card); 991 if (ret !=0) { 992 dev_err(&pdev->dev,"Failed to register card\n"); 993 return ret; 994 } 995 996 return 0; 997 }
928行是获取平台驱动数据,这里就是前面设置的:
platform_set_drvdata(s3c24xx_uda134x_snd_device,&s3c24xx_uda134x_snd_devdata);
s3c24xx_uda134x_snd_devdata的数据类型为structsnd_soc_device
static struct snd_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设备其成员如下:
struct snd_soc_device { struct device *dev; struct snd_soc_card *card; struct snd_soc_codec_device*codec_dev; void *codec_data; };
首先主要关注structsnd_soc_card *card;这个数据结构,后面的内容就是这张声卡实例化。
475 structsnd_soc_card { 476 char *name; 477 structdevice *dev; 478 479 structlist_head list; 480 481 intinstantiated; 482 483 int(*probe)(struct platform_device *pdev); 484 int(*remove)(struct platform_device *pdev); 485 486 /* the preand post PM functions are used to do any PM work before and 487 * after thecodec and DAI's do any PM work. */ 488 int(*suspend_pre)(struct platform_device *pdev, pm_message_t state); 489 int(*suspend_post)(struct platform_device *pdev, pm_message_t state); 490 int(*resume_pre)(struct platform_device *pdev); 491 int(*resume_post)(struct platform_device *pdev); 492 493 /* callbacks*/ 494 int(*set_bias_level)(struct snd_soc_card *, 495 496 497 /* CPU <-->Codec DAI links */ 498 structsnd_soc_dai_link *dai_link; 499 intnum_links; 500 501 structsnd_soc_device *socdev; 502 503 structsnd_soc_codec *codec; 504 505 structsnd_soc_platform *platform; 506 structdelayed_work delayed_work; 507 structwork_struct deferred_resume_work; 508 };
接下来进入到snd_soc_register_card(card);函数,这事soc_probe的核心。
2302 static intsnd_soc_register_card(struct snd_soc_card *card) 2303 { 2304 if(!card->name || !card->dev) 2305 return-EINVAL; 2306 2307 INIT_LIST_HEAD(&card->list); 2308 card->instantiated= 0; 2309 2310 mutex_lock(&client_mutex); 2311 list_add(&card->list,&card_list); 2312 snd_soc_instantiate_cards(); 2313 mutex_unlock(&client_mutex); 2314 2315 dev_dbg(card->dev,"Registered card '%s'\n", card->name); 2316 2317 return 0; 2318 }函数首先初始化一个 list头,并将当前 card加入到 card_list全局的一张 soc声卡链表中。然后就调用 snd_soc_instantiate_cards();来具体实例化一张声卡。
971 static voidsnd_soc_instantiate_cards(void) 972 { 973 structsnd_soc_card *card; 974 list_for_each_entry(card,&card_list, list) 975 snd_soc_instantiate_card(card); 976 }
974行遍历card_list然后调用snd_soc_instantiate_card实例化。
840 static voidsnd_soc_instantiate_card(struct snd_soc_card *card) 841 { 842 structplatform_device *pdev = container_of(card->dev, 843 struct platform_device, 844 dev); 845 structsnd_soc_codec_device *codec_dev = card->socdev->codec_dev; 846 structsnd_soc_platform *platform; 847 structsnd_soc_dai *dai; 848 int i,found, ret, ac97; 849 850 if(card->instantiated) 851 return; 852 853 found =0; 854 list_for_each_entry(platform,&platform_list, list) 855 if(card->platform == platform) { 856 found =1; 857 break; 858 } 859 if (!found){ 860 dev_dbg(card->dev,"Platform %s not registered\n", 861 card->platform->name); 862 return; 863 } 864 865 ac97 =0; 866 for (i = 0;i < card->num_links; i++) { 867 found =0; 868 list_for_each_entry(dai,&dai_list, list) 869 if(card->dai_link[i].cpu_dai == dai) { 870 found =1; 871 break; 872 } 873 if (!found){ 874 dev_dbg(card->dev,"DAI %s not registered\n", 875 card->dai_link[i].cpu_dai->name); 876 return; 877 } 878 879 if(card->dai_link[i].cpu_dai->ac97_control) 880 ac97 =1; 881 } 882 883 for (i = 0;i < card->num_links; i++) { 884 if(!card->dai_link[i].codec_dai->ops) 885 card->dai_link[i].codec_dai->ops= &null_dai_ops; 886 } 887 888 /* If wehave AC97 in the system then don't wait for the 889 * codec. This will need revisiting if we have to handle 890 * systemswith mixed AC97 and non-AC97 parts. Only check for 891 * DAIscurrently; we can't do this per link since some AC97 892 * codecshave non-AC97 DAIs. 893 */ 894 if(!ac97) 895 for (i = 0;i < card->num_links; i++) { 896 found =0; 897 list_for_each_entry(dai,&dai_list, list) 898 if(card->dai_link[i].codec_dai == dai) { 899 found =1; 900 break; 901 } 902 if(!found) { 903 dev_dbg(card->dev,"DAI %s not registered\n", 904 card->dai_link[i].codec_dai->name); 905 return; 906 } 907 } 908 909 /* Note thatwe do not current check for codec components */ 910 911 dev_dbg(card->dev,"All components present, instantiating\n"); 912 913 /* Foundeverything, bring it up */ 914 if(card->probe) { 915 ret =card->probe(pdev); 916 if (ret <0) 917 return; 918 } 919 920 for (i = 0;i < card->num_links; i++) { 921 structsnd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; 922 if(cpu_dai->probe) { 923 ret =cpu_dai->probe(pdev, cpu_dai); 924 if (ret <0) 925 gotocpu_dai_err; 926 } 927 } 928 929 if(codec_dev->probe) { 930 ret =codec_dev->probe(pdev); 931 if (ret <0) 932 gotocpu_dai_err; 933 } 934 935 if(platform->probe) { 936 ret =platform->probe(pdev); 937 if (ret <0) 938 gotoplatform_err; 939 } 940 941 /* DAPMstream work */ 942 INIT_DELAYED_WORK(&card->delayed_work,close_delayed_work); 943 #ifdefCONFIG_PM 944 /* deferredresume work */ 945 INIT_WORK(&card->deferred_resume_work,soc_resume_deferred); 946 #endif 947 948 card->instantiated= 1; 949 950 return; 951 952 platform_err: 953 if(codec_dev->remove) 954 codec_dev->remove(pdev); 955 956 cpu_dai_err: 957 for (i--; i>= 0; i--) { 958 structsnd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; 959 if(cpu_dai->remove) 960 cpu_dai->remove(pdev,cpu_dai); 961 } 962 963 if(card->remove) 964 card->remove(pdev); 965 }
850行如果声卡已经是实例化了的就直接返回。
854行遍历platform_list链表,这个platform_list是个全局变量初始化是通过linux/sound/soc/s3c24xx/s3c24xx-pcm.c中的初始化完成的,内容如下:
static int __inits3c24xx_soc_platform_init(void) { returnsnd_soc_register_platform(&s3c24xx_soc_platform); } module_init(s3c24xx_soc_platform_init);
snd_soc_register_platform目标是注册一个soc_platform结构到platform_list链表中供后文使用。这里对应得平台是s3c24xx_soc_platform,如下:
459 struct snd_soc_platforms3c24xx_soc_platform = { 460 .name = "s3c24xx-audio", 461 .pcm_ops = &s3c24xx_pcm_ops, 462 .pcm_new = s3c24xx_pcm_new, 463 .pcm_free =s3c24xx_pcm_free_dma_buffers, 464 };
snd_soc_register_platform完成的工作主要是将s3c24xx_soc_platform加入到platform_list,同时重新扫描card链,看是否有卡兼容当前soc_platform。具体代码如下:
2431 intsnd_soc_register_platform(struct snd_soc_platform *platform) 2432 { 2433 if(!platform->name) 2434 return-EINVAL; 2435 2436 INIT_LIST_HEAD(&platform->list); 2437 2438 mutex_lock(&client_mutex); 2439 list_add(&platform->list,&platform_list); 2440 snd_soc_instantiate_cards(); 2441 mutex_unlock(&client_mutex); 2442 2443 pr_debug("Registeredplatform '%s'\n", platform->name); 2444 2445 return0; 2446 }
2440行重新回到了snd_soc_instantiate_cards()中,解释清楚platform_list以后继续会爱到snd_soc_instantiate_cards函数。
855行匹配两个平台是否一致。一路走来
card->platform实际上就是s3c24xx_uda134x_snd_devdata中的snd_soc_s3c24xx_uda134x指向的platform。
static struct snd_soc_devices3c24xx_uda134x_snd_devdata = { .card = &snd_soc_s3c24xx_uda134x, .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, }; static struct snd_soc_cardsnd_soc_s3c24xx_uda134x = { .name = "S3C24XX_UDA134X", .platform = &s3c24xx_soc_platform, .dai_link = &s3c24xx_uda134x_dai_link, .num_links = 1, };
从上面的结构不难看出card->platform=&s3c24xx_soc_platform,与之前注册的一至,found=1,跳出搜索,反之如果没有找到匹配的目标,表示platform还尚未注册进来,一直等到platform注册再次调用instantial_card来实现平台的匹配。
找完platform,接下来进入数字音频接口的匹配也就是dai(digitalaudio interface),整个dai匹配的过程与platform的匹配过程相似的,dai_list注册的内容如下:
/linux/sound/soc/s3c24xx/s3c24xx-i2s.c static int __inits3c24xx_i2s_init(void) { returnsnd_soc_register_dai(&s3c24xx_i2s_dai); } module_init(s3c24xx_i2s_init);
snd_soc_register_dai注册数字接口的内容如下:
2345 intsnd_soc_register_dai(struct snd_soc_dai *dai) 2346 { 2347 if(!dai->name) 2348 return-EINVAL; 2349 2350 /* Thedevice should become mandatory over time */ 2351 if(!dai->dev) 2352 printk(KERN_WARNING"No device for DAI %s\n", dai->name); 2353 2354 if(!dai->ops) 2355 dai->ops= &null_dai_ops; 2356 2357 INIT_LIST_HEAD(&dai->list); 2358 2359 mutex_lock(&client_mutex); 2360 list_add(&dai->list,&dai_list); 2361 snd_soc_instantiate_cards(); 2362 mutex_unlock(&client_mutex); 2363 2364 pr_debug("RegisteredDAI '%s'\n", dai->name); 2365 2366 return 0; 2367 }
2354-2355行是如果dai没有注册操作方法,那么就使用默认的dai设置方法。这里注册的dai接口内容如下:
struct snd_soc_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, .playback = { .channels_min = 2, .channels_max = 2, .rates = S3C24XX_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S8 |SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 2, .channels_max = 2, .rates = S3C24XX_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S8 |SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &s3c24xx_i2s_dai_ops, };
和snd_soc_register_platform一样,snd_soc_register_dai同样调用了snd_soc_instantiate_cards()来重新实例化card。
另外需要注意的是structsnd_soc_card结构中的structsnd_soc_dai_link实际上关联链接的是cpu音频接口与codec编解码接口。内容如下:
struct snd_soc_dai_link { char *name; /* Codec name */ char *stream_name; /* Stream name */ /* DAI */ struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai; /* machine stream operations */ struct snd_soc_ops *ops; /* codec/machine specific init - e.g.add machine controls */ int (*init)(struct snd_soc_codec*codec); /* Symmetry requirements */ unsigned int symmetric_rates:1; /* Symmetry data - only valid ifsymmetry is being enforced */ unsigned int rate; /* DAI pcm */ struct snd_pcm *pcm; };
很明显structsnd_soc_dai *codec_dai;和structsnd_soc_dai *cpu_dai;分别指向了不同的音频接口,这里card->dai_link[i].cpu_dai=&s3c24xx_i2s_dai指的是cpu的i2s接口,与刚注册的相同。所以接口匹配,注意snd_soc_instantiate_card中879行是关于AC97声卡的配置,这里略过。
883-886行是关于数字编解码接口的相关信息,card->dai_link[i].codec_dai->ops内容如下:
static struct snd_soc_dai_links3c24xx_uda134x_dai_link = { .name = "UDA134X", .stream_name = "UDA134X", .codec_dai = &uda134x_dai, .cpu_dai = &s3c24xx_i2s_dai, .ops = &s3c24xx_uda134x_ops, }; struct snd_soc_dai uda134x_dai = { .name = "UDA134X", /* playback capabilities */ .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = UDA134X_RATES, .formats = UDA134X_FORMATS, }, /* capture capabilities */ .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = UDA134X_RATES, .formats = UDA134X_FORMATS, }, /* pcm operations */ .ops = &uda134x_dai_ops, };
894-907行是不支持AC97标准的的codec相关的处理,这里还是使用了dai_list链表。Codec的注册在/sound/soc/codecs/uda134x.c中的module_init(uda134x_init);
static int __init uda134x_init(void) { returnsnd_soc_register_dai(&uda134x_dai); }
codec_dai的内容如下:
struct snd_soc_dai uda134x_dai = { .name = "UDA134X", /* playback capabilities */ .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = UDA134X_RATES, .formats = UDA134X_FORMATS, }, /* capture capabilities */ .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = UDA134X_RATES, .formats = UDA134X_FORMATS, }, /* pcm operations */ .ops = &uda134x_dai_ops, };
911行开始,是真正instantiating的过程,下面一一分析:
914行如果card有probe方法,则直接调用。这里没有提供也就跳过了。
920-927行是cpu_dai接口的枚举过程,对应的函数在linux/sound/soc/s3c24xx/s3c24xx-i2s.c中的s2c24xx_i2s_probe,内容如下:
389 static ints3c24xx_i2s_probe(struct platform_device *pdev, 390 struct snd_soc_dai *dai) 391 { 392 pr_debug("Entered%s\n", __func__); 393 394 s3c24xx_i2s.regs= ioremap(S3C2410_PA_IIS, 0x100); 395 if(s3c24xx_i2s.regs == NULL) 396 return-ENXIO; 397 398 s3c24xx_i2s.iis_clk= clk_get(&pdev->dev, "iis"); 399 if(s3c24xx_i2s.iis_clk == NULL) { 400 pr_err("failedto get iis_clock\n"); 401 iounmap(s3c24xx_i2s.regs); 402 return-ENODEV; 403 } 404 clk_enable(s3c24xx_i2s.iis_clk); 405 406 /* Configurethe I2S pins in correct mode */ 407 s3c2410_gpio_cfgpin(S3C2410_GPE0,S3C2410_GPE0_I2SLRCK); 408 s3c2410_gpio_cfgpin(S3C2410_GPE1,S3C2410_GPE1_I2SSCLK); 409 s3c2410_gpio_cfgpin(S3C2410_GPE2,S3C2410_GPE2_CDCLK); 410 s3c2410_gpio_cfgpin(S3C2410_GPE3,S3C2410_GPE3_I2SSDI); 411 s3c2410_gpio_cfgpin(S3C2410_GPE4,S3C2410_GPE4_I2SSDO); 412 413 writel(S3C2410_IISCON_IISEN,s3c24xx_i2s.regs + S3C2410_IISCON); 414 415 s3c24xx_snd_txctrl(0); 416 s3c24xx_snd_rxctrl(0); 417 418 return 0; 419 }
这个函数主要是针对s3c2440I2S内部寄存器的配置。
394行重映射内部寄存器,
398-404行是设置系统时钟。
407-412行是设置I2S的GPIO功能,使之支持I2S
413行使能I2S功能
415行函数实现如下:
76 static voids3c24xx_snd_txctrl(int on) 77 { 78 u32 iisfcon; 79 u32 iiscon; 80 u32 iismod; 81 82 pr_debug("Entered%s\n", __func__); 83 84 iisfcon =readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 85 iiscon =readl(s3c24xx_i2s.regs + S3C2410_IISCON); 86 iismod =readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 87 88 pr_debug("r:IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); 89 90 if (on) { 91 iisfcon |=S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; 92 iiscon |=S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN; 93 iiscon &=~S3C2410_IISCON_TXIDLE; 94 iismod |=S3C2410_IISMOD_TXMODE; 95 96 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 97 writel(iisfcon,s3c24xx_i2s.regs + S3C2410_IISFCON); 98 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); 99 } else { 100 /* note, wehave to disable the FIFOs otherwise bad things 101 * seem tohappen when the DMA stops. According to the 102 * Samsungsupplied kernel, this should allow the DMA 103 * engineand FIFOs to reset. If this isn't allowed, the 104 * DMAengine will simply freeze randomly. 105 */ 106 107 iisfcon &=~S3C2410_IISFCON_TXENABLE; 108 iisfcon &=~S3C2410_IISFCON_TXDMA; 109 iiscon |= S3C2410_IISCON_TXIDLE; 110 iiscon &=~S3C2410_IISCON_TXDMAEN; 111 iismod &=~S3C2410_IISMOD_TXMODE; 112 113 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); 114 writel(iisfcon,s3c24xx_i2s.regs + S3C2410_IISFCON); 115 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 116 } 117 118 pr_debug("w:IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); 119 }
函数是对I2S内部的控制寄存器的设置。
回到snd_soc_instantiate_card函数,接下来是codec_dev的probe方法的调用,codec_dev是相对cpu_dev的软解码设备,这个probe方法后面分析,接下来把snd_soc_instantiate_card分析完。函数的最后就是platform中probe方法的调用,最后是初始化一个延时等待队列。一切工作完成以后card->instantiated= 1;完成卡的instantial工作。
目光转向codec_dev的probe方法
structsnd_soc_codec_device soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, .remove = uda134x_soc_remove, .suspend = uda134x_soc_suspend, .resume = uda134x_soc_resume, };
代码位于linux/sound/soc/codecs/uda134x.c中
469 staticint uda134x_soc_probe(struct platform_device *pdev) 470 { 471 structsnd_soc_device *socdev = platform_get_drvdata(pdev); 472 structsnd_soc_codec *codec; 473 structuda134x_priv *uda134x; 474 void*codec_setup_data = socdev->codec_data; 475 intret = -ENOMEM; 476 structuda134x_platform_data *pd; 477 478 printk(KERN_INFO"UDA134X SoC Audio Codec\n"); 479 480 if(!codec_setup_data) { 481 printk(KERN_ERR"UDA134X SoC codec: " 482 "missing L3 bitbang function\n"); 483 return-ENODEV; 484 } 485 486 pd= codec_setup_data; 487 switch(pd->model) { 488 caseUDA134X_UDA1340: 489 caseUDA134X_UDA1341: 490 caseUDA134X_UDA1344: 491 break; 492 default: 493 printk(KERN_ERR"UDA134X SoC codec: " 494 "unsupported model %d\n", 495 pd->model); 496 return-EINVAL; 497 } 498 499 socdev->card->codec= kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 500 if(socdev->card->codec == NULL) 501 returnret; 502 503 codec= socdev->card->codec; 504 505 uda134x= kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); 506 if(uda134x == NULL) 507 gotopriv_err; 508 codec->private_data= uda134x; 509 510 codec->reg_cache= kmemdup(uda134x_reg, sizeof(uda134x_reg), 511 GFP_KERNEL); 512 if(codec->reg_cache == NULL) 513 gotoreg_err; 514 515 mutex_init(&codec->mutex); 516 517 codec->reg_cache_size= sizeof(uda134x_reg); 518 codec->reg_cache_step= 1; 519 520 codec->name= "UDA134X"; 521 codec->owner= THIS_MODULE; 522 codec->dai= &uda134x_dai; 523 codec->num_dai= 1; 524 codec->read= uda134x_read_reg_cache; 525 codec->write= uda134x_write; 526 #ifdefPOWER_OFF_ON_STANDBY 527 codec->set_bias_level= uda134x_set_bias_level; 528 #endif 529 INIT_LIST_HEAD(&codec->dapm_widgets); 530 INIT_LIST_HEAD(&codec->dapm_paths); 531 532 codec->control_data= codec_setup_data; 533 534 if(pd->power) 535 pd->power(1); 536 537 uda134x_reset(codec); 538 539 /*register pcms */ 540 ret= snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,SNDRV_DEFAULT_STR1); 541 if(ret < 0) { 542 printk(KERN_ERR"UDA134X: failed to register pcms\n"); 543 gotopcm_err; 544 } 545 soc_new_pcms 546 switch(pd->model) { 547 caseUDA134X_UDA1340: 548 caseUDA134X_UDA1344: 549 ret= snd_soc_add_controls(codec, uda1340_snd_controls, 550 ARRAY_SIZE(uda1340_snd_controls)); 551 break; 552 caseUDA134X_UDA1341: 553 ret= snd_soc_add_controls(codec, uda1341_snd_controls, 554 ARRAY_SIZE(uda1341_snd_controls)); 555 break; 556 default: 557 printk(KERN_ERR"%s unkown codec type: %d", 558 __func__,pd->model); 559 return-EINVAL; 560 } 561 562 if(ret < 0) { 563 printk(KERN_ERR"UDA134X: failed to register controls\n"); 564 gotopcm_err; 565 } 566 567 ret= snd_soc_init_card(socdev); 568 if(ret < 0) { 569 printk(KERN_ERR"UDA134X: failed to register card\n"); 570 gotocard_err; 571 } 572 573 return0; 574 575 card_err: 576 snd_soc_free_pcms(socdev); 577 snd_soc_dapm_free(socdev); 578 pcm_err: 579 kfree(codec->reg_cache); 580 reg_err: 581 kfree(codec->private_data); 582 priv_err: 583 kfree(codec); 584 returnret; 585 }
在进入代码分析之前,首先关注一下函数的参数,这里的pdev实际上就是指向S3C24xx-uda134x.c中的&s3c24xx_uda134x_snd_device。当然471行socdev也就是指向staticstruct snd_soc_device s3c24xx_uda134x_snd_devdata = {
.card = &snd_soc_s3c24xx_uda134x,
.codec_dev = &soc_codec_dev_uda134x,
.codec_data = &s3c24xx_uda134x,
};
这里474行codec_setup_data也就是指向s3c24xx_uda134x,其实质是
static struct uda134x_platform_datas3c24xx_uda134x = { .l3 = { .setdat = setdat, .setclk = setclk, .setmode = setmode, .data_hold = 1, .data_setup = 1, .clock_high = 1, .mode_hold = 1, .mode = 1, .mode_setup = 1, }, };
L3pin是uda134x控制数据接口,后面用到了再详细分析。
499-503行是为soc_codec分配空间。
510行kmemdup是kmalloc的一个变种,他不仅实现内存的分配,同时能为其赋值,这里uda134x_reg是内部寄存器缓存的情况,最终复制到reg_codec中。
524和525行是读写uda134x寄存器的方法,但是read只是对寄存器缓存变量的读取,具体的函数实现后面谈到的时候在详细分析。
537行uda134x_reset的过程如下:
146 static inlinevoid uda134x_reset(struct snd_soc_codec *codec) 147 { 148 u8 reset_reg= uda134x_read_reg_cache(codec, UDA134X_STATUS0); 149 uda134x_write(codec,UDA134X_STATUS0, reset_reg | (1<<6)); 150 msleep(1); 151 uda134x_write(codec,UDA134X_STATUS0, reset_reg & ~(1<<6)); 152 }
148行正是前面所说的codec->read。内容如下:
63 /* 64 * The codechas no support for reading its registers except for peak level... 65 */ 66 static inlineunsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, 67 unsigned intreg) 68 { 69 u8 *cache =codec->reg_cache; 70 71 if (reg >=UDA134X_REGS_NUM) 72 return -1; 73 returncache[reg]; 74 }
从代码中我们可以看到,读数据的过程实际上就是从之前uda134x_reg变量中读取的数据,从注释上也不难看出,codec不支持内部寄存器数据的读取。
回到uda134x_reset中uda134x_write也正是前面codec->write提供的方法。在分析具体内容之前不妨从整体上观察一下函数所做的操作,reset首先置位状态寄存器0的第六位,然后延时一段时间后清零该位,完成复位过程。uda134x_write写硬件的过程如下:
93 static intuda134x_write(struct snd_soc_codec *codec, unsigned int reg, 94 unsigned intvalue) 95 { 96 int ret; 97 u8 addr; 98 u8 data =value; 99 structuda134x_platform_data *pd = codec->control_data; 100 101 pr_debug("%sreg: %02X, value:%02X\n", __func__, reg, value); 102 103 if (reg >=UDA134X_REGS_NUM) { 104 printk(KERN_ERR"%s unkown register: reg: %u", 105 __func__, reg); 106 return-EINVAL; 107 } 108 109 uda134x_write_reg_cache(codec,reg, value); 110 111 switch (reg){ 112 caseUDA134X_STATUS0: 113 caseUDA134X_STATUS1: 114 addr =UDA134X_STATUS_ADDR; 115 break; 116 caseUDA134X_DATA000: 117 caseUDA134X_DATA001: 118 caseUDA134X_DATA010: 119 addr =UDA134X_DATA0_ADDR; 120 break; 121 caseUDA134X_DATA1: 122 addr =UDA134X_DATA1_ADDR; 123 break; 124 default: 125 /* It's anextended address register */ 126 addr = (reg | UDA134X_EXTADDR_PREFIX); 127 128 ret =l3_write(&pd->l3, 129 UDA134X_DATA0_ADDR, &addr, 1); 130 if (ret !=1) 131 return-EIO; 132 133 addr =UDA134X_DATA0_ADDR; 134 data =(value | UDA134X_EXTDATA_PREFIX); 135 break; 136 } 137 138 ret =l3_write(&pd->l3, 139 addr, &data, 1); 140 if (ret !=1) 141 return-EIO; 142 143 return 0; 144 }
109行是将改变值写入reg_cache也就是前面读函数缓存的变量。
138行是L3引脚想uda134x写入数据的过程,内容如下:
67 intl3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) 68 { 69 adap->setclk(1); 70 adap->setdat(1); 71 adap->setmode(1); 72 udelay(adap->mode); 73 74 adap->setmode(0); 75 udelay(adap->mode_setup); 76 sendbyte(adap,addr); 77 udelay(adap->mode_hold); 78 79 sendbytes(adap,data, len); 80 81 adap->setclk(1); 82 adap->setdat(1); 83 adap->setmode(0); 84 85 return len; 86 }
很明显这里是对GPIO口按位操作的过程,实际在硬件连接的过程中L3引脚包含clk、data和mode引脚。structl3_pins *adap的内容前面已经贴出来过,这里以setclk为例看看是如何接口的,实际就是对GPIO的操作。
static void setclk(int v) { gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk,v > 0); }
最终s3c24xx_uda134x_l3_pins关联到了
static structs3c24xx_uda134x_platform_data s3c24xx_uda134x_data = { .l3_clk = S3C2410_GPB(4), .l3_data = S3C2410_GPB(3), .l3_mode = S3C2410_GPB(2), .model = UDA134X_UDA1341, };
回到uda134x_probe函数中….
540行snd_soc_new_pcms是重头戏,注册了一个新的基于pcm的声卡。重新回到了soc_core.c文件。
1422 intsnd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char*xid) 1423 { 1424 structsnd_soc_card *card = socdev->card; 1425 structsnd_soc_codec *codec = card->codec; 1426 int ret,i; 1427 1428 mutex_lock(&codec->mutex); 1429 1430 /* registera sound card */ 1431 ret =snd_card_create(idx, xid, codec->owner, 0, &codec->card); 1432 if (ret <0) { 1433 printk(KERN_ERR"asoc: can't create sound card for codec %s\n", 1434 codec->name); 1435 mutex_unlock(&codec->mutex); 1436 returnret; 1437 } 1438 1439 codec->socdev= socdev; 1440 codec->card->dev= socdev->dev; 1441 codec->card->private_data= codec; 1442 strncpy(codec->card->driver,codec->name, sizeof(codec->card->driver)); 1443 1444 /* createthe pcms */ 1445 for (i = 0;i < card->num_links; i++) { 1446 ret =soc_new_pcm(socdev, &card->dai_link[i], i); 1447 if (ret <0) { 1448 printk(KERN_ERR"asoc: can't create pcm %s\n", 1449 card->dai_link[i].stream_name); 1450 mutex_unlock(&codec->mutex); 1451 returnret; 1452 } 1453 } 1454 1455 mutex_unlock(&codec->mutex); 1456 returnret; 1457 }
1431行snd_card_create注册一张声卡,很容易发现,名字中少了soc的字符。这里调用的是sound/core中的函数。
147 intsnd_card_create(int idx, const char *xid, 148 structmodule *module, int extra_size, 149 structsnd_card **card_ret) 150 { 151 structsnd_card *card; 152 int err,idx2; 153 154 if(snd_BUG_ON(!card_ret)) 155 return-EINVAL; 156 *card_ret =NULL; 157 158 if(extra_size < 0) 159 extra_size= 0; 160 card =kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); 161 if (!card) 162 return-ENOMEM; 163 if (xid) 164 strlcpy(card->id,xid, sizeof(card->id)); 165 err = 0; 166 mutex_lock(&snd_card_mutex); 167 if (idx <0) { 168 for (idx2 =0; idx2 < SNDRV_CARDS; idx2++) 169 /* idx ==-1 == 0xffff means: take any free slot */ 170 if(~snd_cards_lock & idx & 1<<idx2) { 171 if(module_slot_match(module, idx2)) { 172 idx =idx2; 173 break; 174 } 175 } 176 } 177 if (idx <0) { 178 for (idx2 =0; idx2 < SNDRV_CARDS; idx2++) 179 /* idx ==-1 == 0xffff means: take any free slot */ 180 if(~snd_cards_lock & idx & 1<<idx2) { 181 if(!slots[idx2] || !*slots[idx2]) { 182 idx =idx2; 183 break; 184 } 185 } 186 } 187 if (idx <0) 188 err =-ENODEV; 189 else if (idx< snd_ecards_limit) { 190 if(snd_cards_lock & (1 << idx)) 191 err =-EBUSY; /* invalid */ 192 } else if(idx >= SNDRV_CARDS) 193 err =-ENODEV; 194 if (err <0) { 195 mutex_unlock(&snd_card_mutex); 196 snd_printk(KERN_ERR"cannot find the slot for index %d (range 0-%i), error: %d\n", 197 idx,snd_ecards_limit - 1, err); 198 goto__error; 199 } 200 snd_cards_lock|= 1 << idx; /* lock it */ 201 if (idx >=snd_ecards_limit) 202 snd_ecards_limit= idx + 1; /* increase the limit */ 203 mutex_unlock(&snd_card_mutex); 204 card->number= idx; 205 card->module= module; 206 INIT_LIST_HEAD(&card->devices); 207 init_rwsem(&card->controls_rwsem); 208 rwlock_init(&card->ctl_files_rwlock); 209 INIT_LIST_HEAD(&card->controls); 210 INIT_LIST_HEAD(&card->ctl_files); 211 spin_lock_init(&card->files_lock); 212 INIT_LIST_HEAD(&card->files_list); 213 init_waitqueue_head(&card->shutdown_sleep); 214 #ifdefCONFIG_PM 215 mutex_init(&card->power_lock); 216 init_waitqueue_head(&card->power_sleep); 217 #endif 218 /* thecontrol interface cannot be accessed from the user space until */ 219 /*snd_cards_bitmask and snd_cards are set with snd_card_register */ 220 err =snd_ctl_create(card); 221 if (err <0) { 222 snd_printk(KERN_ERR"unable to register control minors\n"); 223 goto__error; 224 } 225 err =snd_info_card_create(card); 226 if (err <0) { 227 snd_printk(KERN_ERR"unable to create card info\n"); 228 goto__error_ctl; 229 } 230 if(extra_size > 0) 231 card->private_data= (char *)card + sizeof(struct snd_card); 232 *card_ret =card; 233 return 0; 234 235 __error_ctl: 236 snd_device_free_all(card,SNDRV_DEV_CMD_PRE); 237 __error: 238 kfree(card); 239 returnerr; 240 }
160行分配一个snd_card结构,紧接着的一大段代码都是在为card寻找自己的坐标,这里重点关注220行snd_ctl_create。snd_ctl_create中定义了snddevice的操作方法,如下:
static struct snd_device_ops ops = { .dev_free = snd_ctl_dev_free, .dev_register = snd_ctl_dev_register, .dev_disconnect =snd_ctl_dev_disconnect, };
同时会调用snd_device_new。Snd_device_new会重新分配一个snd_device结构,并初始化后链接到snd_card的链表中来。
回到snd_card_create中来225行snd_info_card_create是procfs等相关的处理。接着回到snd_soc_new_pcms中
1446行soc_new_pcm是建立cpu与codec的dai接口的核心。内容如下:
1069 static intsoc_new_pcm(struct snd_soc_device *socdev, 1070 structsnd_soc_dai_link *dai_link, int num) 1071 { 1072 structsnd_soc_card *card = socdev->card; 1073 structsnd_soc_codec *codec = card->codec; 1074 structsnd_soc_platform *platform = card->platform; 1075 structsnd_soc_dai *codec_dai = dai_link->codec_dai; 1076 structsnd_soc_dai *cpu_dai = dai_link->cpu_dai; 1077 structsnd_soc_pcm_runtime *rtd; 1078 structsnd_pcm *pcm; 1079 charnew_name[64]; 1080 int ret =0, playback = 0, capture = 0; 1081 1082 rtd =kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); 1083 if (rtd ==NULL) 1084 return-ENOMEM; 1085 1086 rtd->dai= dai_link; 1087 rtd->socdev= socdev; 1088 codec_dai->codec= card->codec; 1089 1090 /* checkclient and interface hw capabilities */ 1091 sprintf(new_name,"%s %s-%d", dai_link->stream_name, codec_dai->name, 1092 num); 1093 1094 if(codec_dai->playback.channels_min) 1095 playback =1; 1096 if(codec_dai->capture.channels_min) 1097 capture =1; 1098 1099 ret =snd_pcm_new(codec->card, new_name, codec->pcm_devs++,playback, 1100 capture,&pcm); 1101 if (ret <0) { 1102 printk(KERN_ERR"asoc: can't create pcm for codec %s\n", 1103 codec->name); 1104 kfree(rtd); 1105 returnret; 1106 } 1107 1108 dai_link->pcm= pcm; 1109 pcm->private_data= rtd; 1110 soc_pcm_ops.mmap= platform->pcm_ops->mmap; 1111 soc_pcm_ops.pointer= platform->pcm_ops->pointer; 1112 soc_pcm_ops.ioctl= platform->pcm_ops->ioctl; 1113 soc_pcm_ops.copy= platform->pcm_ops->copy; 1114 soc_pcm_ops.silence= platform->pcm_ops->silence; 1115 soc_pcm_ops.ack= platform->pcm_ops->ack; 1116 soc_pcm_ops.page= platform->pcm_ops->page; 1117 1118 if(playback) 1119 snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); 1120 1121 if(capture) 1122 snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); 1123 1124 ret =platform->pcm_new(codec->card, codec_dai, pcm); 1125 if (ret <0) { 1126 printk(KERN_ERR"asoc: platform pcm constructor failed\n"); 1127 kfree(rtd); 1128 returnret; 1129 } 1130 1131 pcm->private_free= platform->pcm_free; 1132 printk(KERN_INFO"asoc: %s <-> %s mapping ok\n", codec_dai->name, 1133 cpu_dai->name); 1134 returnret; 1135 }
1094-1097行分别代表了设备具有的播放和录音功能。
1099行snd_pcm_new函数的内容如下:
696 intsnd_pcm_new(struct snd_card *card, const char *id, int device, 697 intplayback_count, int capture_count, 698 struct snd_pcm ** rpcm) 699 { 700 structsnd_pcm *pcm; 701 int err; 702 staticstruct snd_device_ops ops = { 703 .dev_free =snd_pcm_dev_free, 704 .dev_register= snd_pcm_dev_register, 705 .dev_disconnect= snd_pcm_dev_disconnect, 706 }; 707 708 if(snd_BUG_ON(!card)) 709 return-ENXIO; 710 if (rpcm) 711 *rpcm =NULL; 712 pcm =kzalloc(sizeof(*pcm), GFP_KERNEL); 713 if (pcm ==NULL) { 714 snd_printk(KERN_ERR"Cannot allocate PCM\n"); 715 return-ENOMEM; 716 } 717 pcm->card= card; 718 pcm->device= device; 719 if (id) 720 strlcpy(pcm->id,id, sizeof(pcm->id)); 721 if((err=snd_pcm_new_stream(pcm,SNDRV_PCM_STREAM_PLAYBACK,playback_count)) < 0) { 722 snd_pcm_free(pcm); 723 returnerr; 724 } 725 if ((err =snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) <0) { 726 snd_pcm_free(pcm); 727 returnerr; 728 } 729 mutex_init(&pcm->open_mutex); 730 init_waitqueue_head(&pcm->open_wait); 731 if ((err =snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { 732 snd_pcm_free(pcm); 733 returnerr; 734 } 735 if (rpcm) 736 *rpcm =pcm; 737 return 0; 738 }
在分析函数之前首先来关注一下structsnd_pcm结构,
struct snd_pcm { struct snd_card *card; struct list_head list; int device; /* device number */ unsigned int info_flags; unsigned short dev_class; unsigned short dev_subclass; char id[64]; char name[80]; struct snd_pcm_str streams[2]; struct mutex open_mutex; wait_queue_head_t open_wait; void *private_data; void (*private_free) (struct snd_pcm*pcm); struct device *dev; /* actual hwdevice this belongs to */ #if defined(CONFIG_SND_PCM_OSS) ||defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif };
其中structsnd_pcm_str streams[2]分别用于playback和capture,具体后面再说。
721行利用函数snd_pcm_new_stream新建一个playback流。
619 intsnd_pcm_new_stream(struct snd_pcm *pcm, int stream, intsubstream_count) 620 { 621 int idx,err; 622 structsnd_pcm_str *pstr = &pcm->streams[stream]; 623 structsnd_pcm_substream *substream, *prev; 624 625 #ifdefined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) 626 mutex_init(&pstr->oss.setup_mutex); 627 #endif 628 pstr->stream= stream; 629 pstr->pcm= pcm; 630 pstr->substream_count= substream_count; 631 if(substream_count > 0) { 632 err =snd_pcm_stream_proc_init(pstr); 633 if (err <0) { 634 snd_printk(KERN_ERR"Error in snd_pcm_stream_proc_init\n"); 635 returnerr; 636 } 637 } 638 prev =NULL; 639 for (idx =0, prev = NULL; idx < substream_count; idx++) { 640 substream =kzalloc(sizeof(*substream), GFP_KERNEL); 641 if(substream == NULL) { 642 snd_printk(KERN_ERR"Cannot allocate PCM substream\n"); 643 return-ENOMEM; 644 } 645 substream->pcm= pcm; 646 substream->pstr= pstr; 647 substream->number= idx; 648 substream->stream= stream; 649 sprintf(substream->name,"subdevice #%i", idx); 650 snprintf(substream->latency_id,sizeof(substream->latency_id), 651"ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device, 652 (stream ?'c' : 'p'), idx); 653 substream->buffer_bytes_max= UINT_MAX; 654 if (prev ==NULL) 655 pstr->substream= substream; 656 else 657 prev->next= substream; 658 err =snd_pcm_substream_proc_init(substream); 659 if (err <0) { 660 snd_printk(KERN_ERR"Error in snd_pcm_stream_proc_init\n"); 661 if (prev== NULL) 662 pstr->substream= NULL; 663 else 664 prev->next= NULL; 665 kfree(substream); 666 returnerr; 667 } 668 substream->group= &substream->self_group; 669 spin_lock_init(&substream->self_group.lock); 670 INIT_LIST_HEAD(&substream->self_group.substreams); 671 list_add_tail(&substream->link_list,&substream->self_group.substreams);
672 atomic_set(&substream->mmap_count,0);
673 prev =substream; 674 } 675 return 0; 676 }
这个函数主要是为structsnd_pcm_strstreams[]建立substream,其中pstr->substream_count记录了substream的数量,pstr->substream建立了一条substream的链表,使得支持playback的数据流链接到链表中来。632,、658行等主要为proc文件夹服务的信息。
回到snd_pcm_new函数的731行snd_device_new,这个函数之前已经见到过了,只是当时新建的snd_device是属于controldevice,而这里建立的是pcmdevice,当然不同的device所使用的操作方法是不一样的。
回到soc_new_pcm函数中
1110-1116行就是为这个soc_pcm_ops赋值了,所赋值的内容如下:
static struct snd_pcm_opss3c24xx_pcm_ops = { .open = s3c24xx_pcm_open, .close = s3c24xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = s3c24xx_pcm_hw_params, .hw_free = s3c24xx_pcm_hw_free, .prepare = s3c24xx_pcm_prepare, .trigger = s3c24xx_pcm_trigger, .pointer = s3c24xx_pcm_pointer, .mmap = s3c24xx_pcm_mmap, };
1118-1122行就是为刚才初始化的substream制定相应的操作方法,也就是使之指向s3c24xx_pcm_ops。
1124行这是新建pcm数据流过程中初始化硬件设置的部分,关联DMA相关的一些类初始化,这个将在后面与硬件构架相关的内容一起分析,这里贴出关联的数据结构。
struct snd_soc_platforms3c24xx_soc_platform = { .name = "s3c24xx-audio", .pcm_ops = &s3c24xx_pcm_ops, .pcm_new = s3c24xx_pcm_new, .pcm_free =s3c24xx_pcm_free_dma_buffers, };
与new相对应的是pcm_free函数。这个工作以后程序重新回到snd_soc_new_pcms,函数中1445行的for(i = 0; i < card->num_links; i++)循环为soc_card所有的连接建立pcm流。接着就返回到了
546-560行是关于card控制信息的注册,pcm是音频数据流的通道,对于像音量等等信息就是由controls来管理了,具体的内容相对比较简单不在详细分析。
最后的最后567行snd_soc_init_card是设备注册过程的大结局,内容如下:
1469 intsnd_soc_init_card(struct snd_soc_device *socdev) 1470 { 1471 structsnd_soc_card *card = socdev->card; 1472 structsnd_soc_codec *codec = card->codec; 1473 int ret =0, i, ac97 = 0, err = 0; 1474 1475 for (i = 0;i < card->num_links; i++) { 1476 if(card->dai_link[i].init) { 1477 err =card->dai_link[i].init(codec); 1478 if (err <0) { 1479 printk(KERN_ERR"asoc: failed to init %s\n", 1480 card->dai_link[i].stream_name); 1481 continue; 1482 } 1483 } 1484 if(card->dai_link[i].codec_dai->ac97_control) { 1485 ac97 =1; 1486 snd_ac97_dev_add_pdata(codec->ac97, 1487 card->dai_link[i].cpu_dai->ac97_pdata); 1488 } 1489 } 1490 snprintf(codec->card->shortname,sizeof(codec->card->shortname), 1491 "%s", card->name); 1492 snprintf(codec->card->longname,sizeof(codec->card->longname), 1493 "%s(%s)", card->name, codec->name); 1494 1495 /* Makesure all DAPM widgets are instantiated */ 1496 snd_soc_dapm_new_widgets(codec); 1497 1498 ret =snd_card_register(codec->card); 1499 if (ret <0) { 1500 printk(KERN_ERR"asoc: failed to register soundcard for %s\n", 1501 codec->name); 1502 gotoout; 1503 } 1504 1505 mutex_lock(&codec->mutex); 1506 #ifdefCONFIG_SND_SOC_AC97_BUS 1507 /* Onlyinstantiate AC97 if not already done by the adaptor 1508 * for thegeneric AC97 subsystem. 1509 */ 1510 if (ac97 &&strcmp(codec->name, "AC97") != 0) { 1511 ret =soc_ac97_dev_register(codec); 1512 if (ret <0) { 1513 printk(KERN_ERR"asoc: AC97 device register failed\n"); 1514 snd_card_free(codec->card); 1515 mutex_unlock(&codec->mutex); 1516 gotoout; 1517 } 1518 } 1519 #endif 1520 1521 err =snd_soc_dapm_sys_add(socdev->dev); 1522 if (err <0) 1523 printk(KERN_WARNING"asoc: failed to add dapm sysfs entries\n"); 1524 1525 err =device_create_file(socdev->dev, &dev_attr_codec_reg); 1526 if (err <0) 1527 printk(KERN_WARNING"asoc: failed to add codec sysfs files\n"); 1528 1529 soc_init_codec_debugfs(codec); 1530 mutex_unlock(&codec->mutex); 1531 1532 out: 1533 returnret; 1534 }
重点关注1498行snd_register_card,最关键的是其中调用了snd_device_register_all,内容如下:
185 intsnd_device_register_all(struct snd_card *card) 186 { 187 structsnd_device *dev; 188 int err; 189 190 if(snd_BUG_ON(!card)) 191 return-ENXIO; 192 list_for_each_entry(dev,&card->devices, list) { 193 if(dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register){ 194 if ((err =dev->ops->dev_register(dev)) < 0) 195 returnerr; 196 dev->state= SNDRV_DEV_REGISTERED; 197 } 198 } 199 return0; 200 }
192行会遍历card中注册的devices最终通过调用其注册函数,在这里主要有两个设备注册进来了,分别是devicecontrol、pcmdevice。首先来看device_control注册是利用snd_ctl_create函数实现的,注册的ops内容如下:
static struct snd_device_ops ops = { .dev_free = snd_ctl_dev_free, .dev_register = snd_ctl_dev_register, .dev_disconnect =snd_ctl_dev_disconnect, };
由此可见snd_ctl_dev_register函数会被调用。
1400 static intsnd_ctl_dev_register(struct snd_device *device) 1401 { 1402 structsnd_card *card = device->device_data; 1403 int err,cardnum; 1404 charname[16]; 1405 1406 if(snd_BUG_ON(!card)) 1407 return-ENXIO; 1408 cardnum =card->number; 1409 if(snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS)) 1410 return-ENXIO; 1411 sprintf(name,"controlC%i", cardnum); 1412 if ((err =snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, 1413 &snd_ctl_f_ops, card, name)) < 0) 1414 returnerr; 1415 return 0; 1416 }
这里主要是关注snd_register_device函数,内容如下:
238 static inlineint snd_register_device(int type, struct snd_card *card, int dev, 239 const struct file_operations *f_ops, 240 void *private_data, 241 const char *name) 242 { 243 returnsnd_register_device_for_dev(type, card, dev, f_ops, 244 private_data, name, 245 snd_card_get_device_link(card)); 246 }
实际调用snd_register_device_for_dev:
249 intsnd_register_device_for_dev(int type, struct snd_card *card, intdev, 250 conststruct file_operations *f_ops, 251 void*private_data, 252 constchar *name, struct device *device) 253 { 254 intminor; 255 structsnd_minor *preg; 256 257 if(snd_BUG_ON(!name)) 258 return-EINVAL; 259 preg =kmalloc(sizeof *preg, GFP_KERNEL); 260 if (preg ==NULL) 261 return-ENOMEM; 262 preg->type= type; 263 preg->card= card ? card->number : -1; 264 preg->device= dev; 265 preg->f_ops= f_ops; 266 preg->private_data= private_data; 267 mutex_lock(&sound_mutex); 268 #ifdefCONFIG_SND_DYNAMIC_MINORS 269 minor =snd_find_free_minor(); 270 #else 271 minor =snd_kernel_minor(type, card, dev); 272 if (minor >=0 && snd_minors[minor]) 273 minor =-EBUSY; 274 #endif 275 if (minor <0) { 276 mutex_unlock(&sound_mutex); 277 kfree(preg); 278 returnminor; 279 } 280 snd_minors[minor]= preg; 281 preg->dev= device_create(sound_class, device, MKDEV(major, minor), 282 private_data, "%s", name); 283 if(IS_ERR(preg->dev)) { 284 snd_minors[minor]= NULL; 285 mutex_unlock(&sound_mutex); 286 minor =PTR_ERR(preg->dev); 287 kfree(preg); 288 returnminor; 289 } 290 291 mutex_unlock(&sound_mutex); 292 return 0; 293 }
280行之前就是为这个device找到一个从设备号,然后281行就调用device_create来创建设备节点。完成control_device的初始化工作。
与之类似的pcmdevice则是通过
static struct snd_device_ops ops = { .dev_free = snd_pcm_dev_free, .dev_register = snd_pcm_dev_register, .dev_disconnect =snd_pcm_dev_disconnect, };
中的snd_pcm_dev_register来创建设备节点。
989行的snd_register_device_for_dev就完成了pcmdevice的设备创建工作,这里所用的class是sound_class,其注册的地方在/linux/sound/sound-core.c中这是声卡初始化的入口module_init(init_soundcore);
39 static int__init init_soundcore(void) 40 { 41 int rc; 42 43 rc =init_oss_soundcore(); 44 if (rc) 45 return rc; 46 47 sound_class =class_create(THIS_MODULE, "sound"); 48 if(IS_ERR(sound_class)) { 49 cleanup_oss_soundcore(); 50 returnPTR_ERR(sound_class); 51 } 52 53 sound_class->devnode= sound_devnode; 54 55 return 0; 56 }
950 static intsnd_pcm_dev_register(struct snd_device *device) 951 { 952 int cidx,err; 953 structsnd_pcm_substream *substream; 954 structsnd_pcm_notify *notify; 955 charstr[16]; 956 structsnd_pcm *pcm; 957 structdevice *dev; 958 959 if(snd_BUG_ON(!device || !device->device_data)) 960 return-ENXIO; 961 pcm =device->device_data; 962 mutex_lock(®ister_mutex); 963 err =snd_pcm_add(pcm); 964 if (err){ 965 mutex_unlock(®ister_mutex); 966 returnerr; 967 } 968 for (cidx =0; cidx < 2; cidx++) { 969 int devtype= -1; 970 if(pcm->streams[cidx].substream == NULL) 971 continue; 972 switch(cidx) { 973 caseSNDRV_PCM_STREAM_PLAYBACK: 974 sprintf(str,"pcmC%iD%ip", pcm->card->number, pcm->device); 975 devtype =SNDRV_DEVICE_TYPE_PCM_PLAYBACK; 976 break; 977 caseSNDRV_PCM_STREAM_CAPTURE: 978 sprintf(str,"pcmC%iD%ic", pcm->card->number, pcm->device); 979 devtype =SNDRV_DEVICE_TYPE_PCM_CAPTURE; 980 break; 981 } 982 /* devicepointer to use, pcm->dev takes precedence if 983 * it isassigned, otherwise fall back to card's device 984 * ifpossible */ 985 dev =pcm->dev; 986 if(!dev) 987 dev =snd_card_get_device_link(pcm->card); 988 /* registerpcm */ 989 err =snd_register_device_for_dev(devtype, pcm->card, 990 pcm->device, 991 &snd_pcm_f_ops[cidx], 992 pcm,str, dev); 993 if (err <0) { 994 list_del(&pcm->list); 995 mutex_unlock(®ister_mutex); 996 returnerr; 997 } 998 snd_add_device_sysfs_file(devtype,pcm->card, pcm->device, 999 &pcm_attrs); 1000 for(substream = pcm->streams[cidx].substream; substream; substream =substream->next) 1001 snd_pcm_timer_init(substream); 1002 } 1003 1004 list_for_each_entry(notify,&snd_pcm_notify_list, list) 1005 notify->n_register(pcm); 1006 1007 mutex_unlock(®ister_mutex); 1008 return0; 1009 }
47行是sound_class的注册,同时43行的init_oss_soundcore注册了字符型设备,内容如下:
657 static int__init init_oss_soundcore(void) 658 { 659 if(preclaim_oss && 660 register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)== -1) { 661 printk(KERN_ERR"soundcore: sound device already in use.\n"); 662 return-EBUSY; 663 } 664 665 return 0; 666 }
660行register_chrdev注册字符型设备。这就是整个声卡设备初始化的过程,接下来就是他具体的使用了。