Linux声卡驱动分析.doc_第1页
Linux声卡驱动分析.doc_第2页
Linux声卡驱动分析.doc_第3页
Linux声卡驱动分析.doc_第4页
Linux声卡驱动分析.doc_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux soc声卡构架分析(DMA)以S3C2440为例进行分析,对应的文件linux-/sound/soc/s3c24xx/s3c24xx_uda134x.c其中module_init入口内容为:357static int _init s3c24xx_uda134x_init(void)358359return platform_driver_register(&s3c24xx_uda134x_driver);360359行是一个平台驱动的注册函数,注册的驱动是s3c24xx_uda134x_driver。内容如下:348static struct platform_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方法。290static int s3c24xx_uda134x_probe(struct platform_device *pdev)291292int ret;293294printk(KERN_INFO S3C24XX_UDA134X SoC Audio drivern);295296s3c24xx_uda134x_l3_pins = pdev-dev.platform_data;297if (s3c24xx_uda134x_l3_pins = NULL) 298printk(KERN_ERR S3C24XX_UDA134X SoC Audio: 299 unable to find platform datan);300return -ENODEV;301302s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins-power;303s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins-model;304305if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins-l3_data,306 data) l3_clk,309 clk) l3_data);311return -EBUSY;312313if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins-l3_mode,314 mode) l3_data);316gpio_free(s3c24xx_uda134x_l3_pins-l3_clk);317return -EBUSY;318319320s3c24xx_uda134x_snd_device = platform_device_alloc(soc-audio, -1);321if (!s3c24xx_uda134x_snd_device) 322printk(KERN_ERR S3C24XX_UDA134X SoC Audio: 323 Unable to registern);324return -ENOMEM;325326327platform_set_drvdata(s3c24xx_uda134x_snd_device,328 &s3c24xx_uda134x_snd_devdata);329s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device-dev;330ret = platform_device_add(s3c24xx_uda134x_snd_device);331if (ret) 332printk(KERN_ERR S3C24XX_UDA134X SoC Audio: Unable to addn);333platform_device_put(s3c24xx_uda134x_snd_device);334335336return ret;337305-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)。2546static int _init snd_soc_init(void)25472548#ifdef CONFIG_DEBUG_FS2549debugfs_root = debugfs_create_dir(asoc, NULL);2550if (IS_ERR(debugfs_root) | !debugfs_root) 2551printk(KERN_WARNING2552 ASoC: Failed to create debugfs directoryn);2553debugfs_root = NULL;25542555#endif25562557return platform_driver_register(&soc_driver);25582557行是soc-core驱动注册的核心,soc_driver的内容如下:1057/* ASoC platform driver */1058static struct 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 a new socdev */979static int soc_probe(struct platform_device *pdev)980981int ret = 0;982struct snd_soc_device *socdev = platform_get_drvdata(pdev);983struct snd_soc_card *card = socdev-card;984985/* Bodge while we push things out of socdev */986card-socdev = socdev;987988/* Bodge while we unpick instantiation */989card-dev = &pdev-dev;990ret = snd_soc_register_card(card);991if (ret != 0) 992dev_err(&pdev-dev, Failed to register cardn);993return ret;994995996return 0;997928行是获取平台驱动数据,这里就是前面设置的:platform_set_drvdata(s3c24xx_uda134x_snd_device,&s3c24xx_uda134x_snd_devdata);s3c24xx_uda134x_snd_devdata的数据类型为struct snd_soc_devicestatic struct snd_soc_device s3c24xx_uda134x_snd_devdata = .card = &snd_soc_s3c24xx_uda134x,.codec_dev = &soc_codec_dev_uda134x,.codec_data = &s3c24xx_uda134x,;Struct snd_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;首先主要关注struct snd_soc_card *card;这个数据结构,后面的内容就是这张声卡实例化。475struct snd_soc_card 476char *name;477struct device *dev;478479struct list_head list;480481int instantiated;482483int (*probe)(struct platform_device *pdev);484int (*remove)(struct platform_device *pdev);485486/* the pre and post PM functions are used to do any PM work before and487 * after the codec and DAIs do any PM work. */488int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);489int (*suspend_post)(struct platform_device *pdev, pm_message_t state);490int (*resume_pre)(struct platform_device *pdev);491int (*resume_post)(struct platform_device *pdev);492493/* callbacks */494int (*set_bias_level)(struct snd_soc_card *,495496497/* CPU Codec DAI links */498struct snd_soc_dai_link *dai_link;499int num_links;500501struct snd_soc_device *socdev;502503struct snd_soc_codec *codec;504505struct snd_soc_platform *platform;506struct delayed_work delayed_work;507struct work_struct deferred_resume_work;508;接下来进入到snd_soc_register_card(card);函数,这事soc_probe的核心。2302static int snd_soc_register_card(struct snd_soc_card *card)23032304if (!card-name | !card-dev)2305return -EINVAL;23062307INIT_LIST_HEAD(&card-list);2308card-instantiated = 0;23092310mutex_lock(&client_mutex);2311list_add(&card-list, &card_list);2312snd_soc_instantiate_cards();2313mutex_unlock(&client_mutex);23142315dev_dbg(card-dev, Registered card %sn, card-name);23162317return 0;2318函数首先初始化一个list头,并将当前card加入到card_list全局的一张soc声卡链表中。然后就调用snd_soc_instantiate_cards();来具体实例化一张声卡。971static void snd_soc_instantiate_cards(void)972973struct snd_soc_card *card;974list_for_each_entry(card, &card_list, list)975snd_soc_instantiate_card(card);976974行遍历card_list然后调用snd_soc_instantiate_card实例化。840static void snd_soc_instantiate_card(struct snd_soc_card *card)841842struct platform_device *pdev = container_of(card-dev,843 struct platform_device,844 dev);845struct snd_soc_codec_device *codec_dev = card-socdev-codec_dev;846struct snd_soc_platform *platform;847struct snd_soc_dai *dai;848int i, found, ret, ac97;849850if (card-instantiated)851return;852853found = 0;854list_for_each_entry(platform, &platform_list, list)855if (card-platform = platform) 856found = 1;857break;858859if (!found) 860dev_dbg(card-dev, Platform %s not registeredn,861card-platform-name);862return;863864865ac97 = 0;866for (i = 0; i num_links; i+) 867found = 0;868list_for_each_entry(dai, &dai_list, list)869if (card-dai_linki.cpu_dai = dai) 870found = 1;871break;872873if (!found) 874dev_dbg(card-dev, DAI %s not registeredn,875card-dai_linki.cpu_dai-name);876return;877878879if (card-dai_linki.cpu_dai-ac97_control)880ac97 = 1;881882883for (i = 0; i num_links; i+) 884if (!card-dai_linki.codec_dai-ops)885card-dai_linki.codec_dai-ops = &null_dai_ops;886887888/* If we have AC97 in the system then dont wait for the889 * codec. This will need revisiting if we have to handle890 * systems with mixed AC97 and non-AC97 parts. Only check for891 * DAIs currently; we cant do this per link since some AC97892 * codecs have non-AC97 DAIs.893 */894if (!ac97)895for (i = 0; i num_links; i+) 896found = 0;897list_for_each_entry(dai, &dai_list, list)898if (card-dai_linki.codec_dai = dai) 899found = 1;900break;901902if (!found) 903dev_dbg(card-dev, DAI %s not registeredn,904card-dai_linki.codec_dai-name);905return;906907908909/* Note that we do not current check for codec components */910911dev_dbg(card-dev, All components present, instantiatingn);912913/* Found everything, bring it up */914if (card-probe) 915ret = card-probe(pdev);916if (ret 0)917return;918919920for (i = 0; i num_links; i+) 921struct snd_soc_dai *cpu_dai = card-dai_linki.cpu_dai;922if (cpu_dai-probe) 923ret = cpu_dai-probe(pdev, cpu_dai);924if (ret probe) 930ret = codec_dev-probe(pdev);931if (ret probe) 936ret = platform-probe(pdev);937if (ret delayed_work, close_delayed_work);943#ifdef CONFIG_PM944/* deferred resume work */945INIT_WORK(&card-deferred_resume_work, soc_resume_deferred);946#endif947948card-instantiated = 1;949950return;951952platform_err:953if (codec_dev-remove)954codec_dev-remove(pdev);955956cpu_dai_err:957for (i-; i = 0; i-) 958struct snd_soc_dai *cpu_dai = card-dai_linki.cpu_dai;959if (cpu_dai-remove)960cpu_dai-remove(pdev, cpu_dai);961962963if (card-remove)964card-remove(pdev);965850行如果声卡已经是实例化了的就直接返回。854行遍历platform_list链表,这个platform_list是个全局变量初始化是通过linux/sound/soc/s3c24xx/s3c24xx-pcm.c中的初始化完成的,内容如下:static int _init s3c24xx_soc_platform_init(void)return snd_soc_register_platform(&s3c24xx_soc_platform);module_init(s3c24xx_soc_platform_init);snd_soc_register_platform目标是注册一个soc_platform结构到platform_list链表中供后文使用。这里对应得平台是s3c24xx_soc_platform,如下:459struct snd_soc_platform s3c24xx_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。具体代码如下:2431int snd_soc_register_platform(struct snd_soc_platform *platform)24322433if (!platform-name)2434return -EINVAL;24352436INIT_LIST_HEAD(&platform-list);24372438mutex_lock(&client_mutex);2439list_add(&platform-list, &platform_list);2440snd_soc_instantiate_cards();2441mutex_unlock(&client_mutex);24422443pr_debug(Registered platform %sn, platform-name);24442445return 0;24462440行重新回到了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_device s3c24xx_uda134x_snd_devdata = .card = &snd_soc_s3c24xx_uda134x,.codec_dev = &soc_codec_dev_uda134x,.codec_data = &s3c24xx_uda134x,;static struct snd_soc_card snd_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(digital audio interface),整个dai匹配的过程与platform的匹配过程相似的,dai_list注册的内容如下:/linux/sound/soc/s3c24xx/s3c24xx-i2s.cstatic int _init s3c24xx_i2s_init(void)return snd_soc_register_dai(&s3c24xx_i2s_dai);module_init(s3c24xx_i2s_init);snd_soc_register_dai注册数字接口的内容如下:2345int snd_soc_register_dai(struct snd_soc_dai *dai)23462347if (!dai-name)2348return -EINVAL;23492350/* The device should become mandatory over time */2351if (!dai-dev)2352printk(KERN_WARNING No device for DAI %sn, dai-name);23532354if (!dai-ops)2355dai-ops = &null_dai_ops;23562357INIT_LIST_HEAD(&dai-list);23582359mutex_lock(&client_mutex);2360list_add(&dai-list, &dai_list);2361snd_soc_instantiate_cards();2362mutex_unlock(&client_mutex);23632364pr_debug(Registered DAI %sn, dai-name);23652366return 0;23672354-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。另外需要注意的是struct snd_soc_card结构中的struct snd_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 if symmetry is being enforced */unsigned int rate;/* DAI pcm */struct snd_pcm *pcm;很明显struct snd_soc_dai *codec_dai;和struct snd_soc_dai *cpu_dai;分别指向了不同的音频接口,这里card-dai_linki.cpu_dai= &s3c24xx_i2s_dai指的是cpu的i2s接口,与刚注册的相同。所以接口匹配,注意snd_soc_instantiate_card中879行是关于AC97声卡的配置,这里略过。883-886行是关于数字编解码接口的相关信息,card-dai_linki.codec_dai-ops内容如下:static struct snd_soc_dai_link s3c24xx_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)return snd_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,内容如下:389static int s3c24xx_i2s_probe(struct platform_device *pdev,390 struct snd_soc_dai *dai)391392pr_debug(Entered %sn, _func_);393394s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);395if (s3c24xx_i2s.regs = NULL)396return -ENXIO;397398s3c24xx_i2s.iis_clk = clk_get(&pdev-dev, iis);399if (s3c24xx_i2s.iis_clk = NULL) 400pr_err(failed to get iis_clockn);401iounmap(s3c24xx_i2s.regs);402return -ENODEV;403404clk_enable(s3c24xx_i2s.iis_clk);405406/* Configure the I2S pins in correct mode */407s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);408s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);409s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);410s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);411s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);412413writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);414415s3c24xx_snd_txctrl(0);416s3c24xx_snd_rxctrl(0);417418return 0;419这个函数主要是针对s3c2440 I2S内部寄存器的配置。394行重映射内部寄存器,398-404行是设置系统时钟。407-412行是设置I2S的GPIO功能,使之支持I2S413行使能I2S功能415行函数实现如下:76static void s3c24xx_snd_txctrl(int on)7778u32 iisfcon;79u32 iiscon;80u32 iismod;8182pr_debug(Entered %sn, _func_);8384iisfcon = readl(s3c24xx_i2s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论