文件:sound/soc/s3c24xx/s3c24xx_uda134x.c static int __init s3c24xx_uda134x_init(void) { return platform_driver_register(&s3c24xx_uda134x_driver); // 驱动arch/arm/mach-xx下注册的名为"s3c24xx_uda134x"的设备. } static struct platform_driver s3c24xx_uda134x_driver = { .probe = s3c24xx_uda134x_probe, // 执行该probe进一步创建 .remove = s3c24xx_uda134x_remove, .driver = { .name = "s3c24xx_uda134x", .owner = THIS_MODULE, }, }; 下面是s3c24xx_uda134x_probe的具体实现代码: static int s3c24xx_uda134x_probe(struct platform_device *pdev) { int ret; printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; // 由platform设备传进来的l3的3个控制io口 if (s3c24xx_uda134x_l3_pins == NULL) { printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " "unable to find platform data\n"); return -ENODEV; } s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, // 调用gpio_request申请io "data") < 0) return -EBUSY; if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, // 调用gpio_request申请io "clk") < 0) { gpio_free(s3c24xx_uda134x_l3_pins->l3_data); return -EBUSY; } if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, // 调用gpio_request申请io "mode") < 0) { gpio_free(s3c24xx_uda134x_l3_pins->l3_data); gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); return -EBUSY; } s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); // 申请名为"soc-audio"设备 if (!s3c24xx_uda134x_snd_device) { // 该设备将由soc_driver声卡驱动管理 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " "Unable to register\n"); return -ENOMEM; } platform_set_drvdata(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x_snd_devdata); // s3c24xx_uda134x_snd_devdata声卡驱动soc_driver使用到的结构体 s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; ret = platform_device_add(s3c24xx_uda134x_snd_device); // 将申请的"soc-audio"设备注册到 if (ret) { // platform总线,由soc_driver声卡驱动进一步管理 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); platform_device_put(s3c24xx_uda134x_snd_device); } return ret; } // 下面是soc_driver声卡驱动将要使用到的结构体定义 static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { .card = &snd_soc_s3c24xx_uda134x, // 定义的card声卡 .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, }; struct snd_soc_codec_device soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, .remove = uda134x_soc_remove, .suspend = uda134x_soc_suspend, .resume = uda134x_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); static struct uda134x_platform_data s3c24xx_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, }, }; static struct snd_soc_card snd_soc_s3c24xx_uda134x = {// card声卡的结构体 .name = "S3C24XX_UDA134X", .platform = &s3c24xx_soc_platform, // 使用s3c24xx_soc_platform平台 .dai_link = &s3c24xx_uda134x_dai_link, // 使用s3c24xx_uda134x_dai_link中的cpu_dai和codec_dai解码流通道,他们将生成一个pcm实例,然后对声音流数据 进行发送和接收处理. .num_links = 1, }; static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .name = "UDA134X", // 一个pcm实例将要对应的所有CPU <-> DAI信息. .stream_name = "UDA134X", .codec_dai = &uda134x_dai, // codec芯片接口控制结构体 .cpu_dai = &s3c24xx_i2s_dai, // cpu内置的音频控制单元 .ops = &s3c24xx_uda134x_ops, // pcm实例使用到自定义操作方法集 }; struct snd_soc_dai uda134x_dai = { // codec芯片接口音频控制结构体 .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, }; EXPORT_SYMBOL(uda134x_dai); static int __init uda134x_init(void) { return snd_soc_register_dai(&uda134x_dai); // 注册codec芯片音频驱动模块codec_dai到dai_list链表上[luther.gliethttp]. } module_init(uda134x_init); struct snd_soc_dai s3c24xx_i2s_dai = { // cpu内置的音频控制单元 .name = "s3c24xx-i2s", .id = 0, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, .playback = { // cpu对放音通道的控制 .channels_min = 2, .channels_max = 2, .rates = S3C24XX_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { // cpu对录音通道的控制 .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, }; static int __init s3c24xx_i2s_init(void) { return snd_soc_register_dai(&s3c24xx_i2s_dai); // 注册cpun内部音频驱动模块cpu_dai到dai_list链表上[luther.gliethttp]. } module_init(s3c24xx_i2s_init); static int __init s3c24xx_soc_platform_init(void) { return snd_soc_register_platform(&s3c24xx_soc_platform); // 登记注册24xx的声卡设备到声卡驱动专用的platform_list链表上 } module_init(s3c24xx_soc_platform_init); struct snd_soc_platform s3c24xx_soc_platform = { .name = "s3c24xx-audio", .pcm_ops = &s3c24xx_pcm_ops, // 本platform平台提供的pcm操作方法 .pcm_new = s3c24xx_pcm_new, .pcm_free = s3c24xx_pcm_free_dma_buffers, }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); 文件:sound/soc/soc-core.c // 上面s3c24xx_uda134x_probe==>platform_device_add(s3c24xx_uda134x_snd_device);将直接触发 // 此处soc_probe检测函数的进一步执行[luther.gliethttp]. /* ASoC platform driver */ static struct platform_driver soc_driver = { .driver = { .name = "soc-audio", .owner = THIS_MODULE, }, .probe = soc_probe, .remove = soc_remove, .suspend = soc_suspend, .resume = soc_resume, }; /* probes a new socdev */ static int soc_probe(struct platform_device *pdev) { int ret = 0; struct snd_soc_device *socdev = platform_get_drvdata(pdev); // 对应上面的s3c24xx_uda134x_snd_devdata结构体[luther.gliethttp]. struct snd_soc_card *card = socdev->card; // 对应上面的snd_soc_s3c24xx_uda134x /* Bodge while we push things out of socdev */ card->socdev = socdev; /* Bodge while we unpick instantiation */ card->dev = &pdev->dev; ret = snd_soc_register_card(card); // 注册生成声卡 if (ret != 0) { dev_err(&pdev->dev, "Failed to register card\n"); return ret; } return 0; } static int snd_soc_register_card(struct snd_soc_card *card) // 注册生成声卡 { if (!card->name || !card->dev) return -EINVAL; INIT_LIST_HEAD(&card->list); card->instantiated = 0; // 标识未初始化该声卡,因为该函数只在soc_probe中调用,所以可以保证确实是第1次创建 mutex_lock(&client_mutex); list_add(&card->list, &card_list); // 所有注册的声卡都要添加到声卡设备链表card_list[luther.gliethttp]. snd_soc_instantiate_cards(); // 对声卡进行实例化,生成pcm. mutex_unlock(&client_mutex); dev_dbg(card->dev, "Registered card '%s'\n", card->name); return 0; } static void snd_soc_instantiate_cards(void) // 对声卡进行实例化,生成pcm. { struct snd_soc_card *card; list_for_each_entry(card, &card_list, list) // 遍历声卡链表card_list上所有声卡,如果该声卡的instantiated等于0,那么将被执行实例化,生成该声卡描述的所有pcm流通道. snd_soc_instantiate_card(card); // 实例化声卡内部所有stream流通道为pcm. } static void snd_soc_instantiate_card(struct snd_soc_card *card) // 作声卡实例化 { struct platform_device *pdev = container_of(card->dev, struct platform_device, dev); struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; struct snd_soc_platform *platform; struct snd_soc_dai *dai; int i, found, ret, ac97; if (card->instantiated) // 该card声卡已经完成实例化,简单的返回[luther.gliethttp]. return; found = 0; list_for_each_entry(platform, &platform_list, list) // 搜索platform_list上登记的s3c24xx_soc_platform平台驱动, if (card->platform == platform) { // 因为s3c24xx_soc_platform在module_init(s3c24xx_soc_platform_init);中 found = 1; // 被登记,所以这就有一个模块加载顺序问题,s3c24xx_soc_platform_init必须先 break; // 先执行先被添加到platform_list链表中才能保证[luther.gliethttp]. } // 但是从arch_initcall(customize_machine);可以发现,如果声卡built-in进内核 // 的话,MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")可能存在潜在危险. // #define arch_initcall(fn) __define_initcall("3",fn,3) // #define device_initcall(fn) __define_initcall("6",fn,6) // #define __initcall(fn) device_initcall(fn) // #define module_init(x) __initcall(x); ac97 = 0; for (i = 0; i < card->num_links; i++) { found = 0; list_for_each_entry(dai, &dai_list, list) // 检查dai_list是否已经注册登记了.cpu_dai引用到的驱动模块[luther.gliethttp]. if (card->dai_link[i].cpu_dai == dai) { // 这里就是s3c24xx_uda134x_dai_link中的.cpu_dai = &s3c24xx_i2s_dai found = 1; // 他在s3c24xx_i2s_init中完成注册登记. break; } if (!found) { dev_dbg(card->dev, "DAI %s not registered\n", card->dai_link[i].cpu_dai->name); return; } if (card->dai_link[i].cpu_dai->ac97_control) ac97 = 1; } if (!ac97) // 如果不是ac97设备 for (i = 0; i < card->num_links; i++) { found = 0; list_for_each_entry(dai, &dai_list, list) if (card->dai_link[i].codec_dai == dai) { // 检查dai_list是否已经注册登记了.codec_dai引用到的驱动模块[luther.gliethttp]. found = 1; // 这里就是s3c24xx_uda134x_dai_link中的.codec_dai = &uda134x_dai break; // 他在uda134x_init中完成注册登记. } if (!found) { dev_dbg(card->dev, "DAI %s not registered\n", card->dai_link[i].codec_dai->name); return; } } /* Found everything, bring it up */ // ok,所以依赖的模块都已经就位,那么下面开始创建card声卡. if (card->probe) { ret = card->probe(pdev); // 对于snd_soc_s3c24xx_uda134x没有定义probe if (ret < 0) return; } for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->probe) { ret = cpu_dai->probe(pdev, cpu_dai); // cpu集成的音频控制单元probe初始化,s3c24xx_i2s_dai.s3c24xx_i2s_probe if (ret < 0) // 主要完成i2s控制器时钟启动和s3c24xx的i2s对应的io口配置初始化[luther.gliethttp]. goto cpu_dai_err; } } // 这里将完成设备节点'/dev/dsp'和alsa节点的所有创建工作[luther.gliethttp]. if (codec_dev->probe) { // soc_codec_dev_uda134x.soc_codec_dev_uda134x.uda134x_soc_probe初始化 ret = codec_dev->probe(pdev); // 将执行snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) // 生成声卡内存结构体和创建所有pcms流通道,最后调用snd_soc_init_card(socdev); goto cpu_dai_err; // 根据dsp_map[]索引号选择一个默认pcm流通道生成"/dev/dsp"节点和alsa节点[luther.gliethttp]. } if (platform->probe) { // s3c24xx_soc_platform没有提供probe来初始化 ret = platform->probe(pdev); if (ret < 0) goto platform_err; } /* DAPM stream work */ INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work); #ifdef CONFIG_PM /* deferred resume work */ INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif card->instantiated = 1; return; } |
|