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注册字符型设备。这就是整个声卡设备初始化的过程,接下来就是他具体的使用了。