文件: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;

}

阅读(1395) | 评论(0) | 转发(0) |

linux内核声卡管理,浅析linux 2.6.30.4内核中uda134x声卡驱动源码 - audio和bluetooth相关推荐

  1. Linux kernel SPI源码分析之SPI设备驱动源码分析(linux kernel 5.18)

    SPI基础支持此处不再赘述,直接分析linux中的SPI驱动源码. 1.SPI设备驱动架构图 2.源码分析 本次分析基于kernel5.18,linux/drivers/spi/spidev.c 设备 ...

  2. 【Linux 内核 内存管理】Linux 内核堆内存管理 ① ( 堆内存管理 | 内存描述符 mm_struct 结构体 | mm_struct 结构体中的 start_brk、brk 成员 )

    文章目录 一.堆内存管理 二.内存描述符 mm_struct 结构体 三.mm_struct 结构体中的 start_brk.brk 成员 一.堆内存管理 Linux 操作系统中的 " 堆内 ...

  3. 在linux内核3.14.43添加自己的驱动源码,linux内核如何加入自己的驱动

    linux添加自己的驱动,内核源码版本:3.14.43 1. 添加自己的文件夹 在驱动里面加入自己的文件夹,例如我在driver/char/文件夹里面加入自己的pwm驱动,我需要在char目录下,新建 ...

  4. [Linux] USB-Storage驱动 源码阅读笔记(一)

    USB-Storage驱动 源码阅读笔记--从USB子系统开始 最近在研究U盘的驱动,遇到很多难以理解的问题,虽然之前也参考过一些很不错的书籍如:<USB那些事>,但最终还是觉得下载一份最 ...

  5. Davinci DM6446开发攻略——LINUX GPIO驱动源码移植

    一.             DM6446 GPIO的介绍 说到LINUX 驱动移植,没有移植过的朋友,或刚刚进入LINUX领域的朋友,最好去看看<LINUX 设备驱动程序>第三版,有个理 ...

  6. (转)Linux设备驱动之HID驱动 源码分析

    //Linux设备驱动之HID驱动 源码分析 http://blog.chinaunix.net/uid-20543183-id-1930836.html HID是Human Interface De ...

  7. linux网卡驱动源码分析(一)

    linux网卡驱动源码分析(一) linux struct linux内核 网络 descriptor resources 转自http://blog.csdn.net/ustc_dylan/arti ...

  8. 米尔科技 Z-turn XC7Z010 Linux驱动源码路径

    米尔科技 Z-turn XC7Z010 Linux驱动源码路径 网址:http://www.myir-tech.com/bbs/thread-6999-1-1.html Z-turn XC7Z010 ...

  9. linux系统安装驱动rtl8188eu,rtl8188eu_USB_linux RTL8188EU驱动源码

    [实例简介] RTL8188EU驱动源码 [实例截图] [核心代码] 8188eu_USB_linux ├── document │   ├── Quick_Start_Guide_for_SoftA ...

最新文章

  1. 7个使用PyTorch的技巧,含在线代码示例!网友:我连第一个都不知道?!
  2. 数据结构:希尔排序(shell sort)
  3. UA MATH567 高维统计 专题0 为什么需要高维统计理论?——高维统计理论的常用假设
  4. 我用 PyTorch 复现了 LeNet-5 神经网络(自定义数据集篇)!
  5. [家里蹲大学数学杂志]第036期泛函分析期末试题
  6. oracle扩容日志文件,ORACLE 加大日志文件
  7. 磁盘分区20191017
  8. bind-html自动换行,如何实现textarea placeholder自动换行?
  9. Linux命令之reset - 终端屏幕混乱的终结者
  10. Nginx+keepalive反向代理
  11. 分布式系统常见的事务处理机制
  12. 使用Pytorch来拟合函数
  13. CnPack实用功能推荐
  14. 云安全七大核心要素解析
  15. cad单位_原来CAD的线条还可以这样加粗!还能修改初始单位!太实用了
  16. .net C# asp.net SMTP 匿名发邮件完整解决方案,有源码.
  17. 嵌入式Qt-做一个秒表
  18. web个人学习笔记(待完善)
  19. CAD等高线转地形高程散点
  20. 强化学习(RL)算法

热门文章

  1. 请各位大虾帮我看看,这句是什么意思?
  2. mysql安装简书_MySQL的安装与配置——详细教程
  3. JSON必知必会 学习笔记
  4. 计算机网络原理--实验二 交换机路由器的基本配置
  5. 2016年3月15日Android实习日记
  6. java file outside of source root - IDEA中的java文件突然出现这样的提示
  7. 软件加密技术和注册机制加密基础(转)
  8. 数电实验(一)利用与非门设计四舍五入判别电路
  9. STM32F103C8T6 ADC输入电流电压特性
  10. MATLAB标定工具箱的使用_camera calibration for matlab