Linux soc声卡构架分析

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_devsoc-coredevice结构。对应驱动的名称也应该是"soc-audio"330行是问题的关键,s3c24xx_uda134x_snd_device注册并与soc-core驱动进行匹配。相关的内容在linux/sound/soc/soc-core.c文件中。

Soc-core的入口是module_initsnd_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_drivers3c24xx_uda134x_snd_device的名称匹配,满足mach的基本条件。后面会调用soc_driverprobe方法进行驱动的进一步枚举。

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,接下来进入数字音频接口的匹配也就是daidigitalaudio 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指的是cpui2s接口,与刚注册的相同。所以接口匹配,注意snd_soc_instantiate_card879行是关于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行如果cardprobe方法,则直接调用。这里没有提供也就跳过了。

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行是设置I2SGPIO功能,使之支持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_devprobe方法的调用,codec_dev是相对cpu_dev的软解码设备,这个probe方法后面分析,接下来把snd_soc_instantiate_card分析完。函数的最后就是platformprobe方法的调用,最后是初始化一个延时等待队列。一切工作完成以后card->instantiated= 1;完成卡的instantial工作。

目光转向codec_devprobe方法

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。当然471socdev也就是指向staticstruct snd_soc_device s3c24xx_uda134x_snd_devdata = {

.card = &snd_soc_s3c24xx_uda134x,

.codec_dev = &soc_codec_dev_uda134x,

.codec_data = &s3c24xx_uda134x,

};

这里474codec_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,
},
};

L3pinuda134x控制数据接口,后面用到了再详细分析。

499-503行是为soc_codec分配空间。

510kmemdupkmalloc的一个变种,他不仅实现内存的分配,同时能为其赋值,这里uda134x_reg是内部寄存器缓存的情况,最终复制到reg_codec中。

524525行是读写uda134x寄存器的方法,但是read只是对寄存器缓存变量的读取,具体的函数实现后面谈到的时候在详细分析。

537uda134x_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_resetuda134x_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引脚包含clkdatamode引脚。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函数中….

540snd_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	}

1431snd_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寻找自己的坐标,这里重点关注220snd_ctl_createsnd_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_newSnd_device_new会重新分配一个snd_device结构,并初始化后链接到snd_card的链表中来。

回到snd_card_create中来225snd_info_card_createprocfs等相关的处理。接着回到snd_soc_new_pcms

1446soc_new_pcm是建立cpucodecdai接口的核心。内容如下:

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行分别代表了设备具有的播放和录音功能。

1099snd_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]分别用于playbackcapture,具体后面再说。

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函数的731snd_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来管理了,具体的内容相对比较简单不在详细分析。

最后的最后567snd_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	}

重点关注1498snd_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最终通过调用其注册函数,在这里主要有两个设备注册进来了,分别是devicecontrolpcmdevice。首先来看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的设备创建工作,这里所用的classsound_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	}  

660register_chrdev注册字符型设备。这就是整个声卡设备初始化的过程,接下来就是他具体的使用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值