在分析snd_soc_codec_driver的结构体时,发现有些芯片的驱动中定义了字段reg_word_size, reg_cache_size, reg_cache_default,但没有定义read/write,如wm8993:

static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
.probe = wm8993_probe,
.remove = wm8993_remove,
.suspend = wm8993_suspend,
.resume = wm8993_resume,
.set_bias_level = wm8993_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8993_reg_defaults,
.volatile_register = wm8993_volatile,
};

而另外的一些芯片驱动中,则定义了字段read, write,如wm8400和cx20442:

static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
.probe = wm8400_codec_probe,
.remove = wm8400_codec_remove,
.suspend = wm8400_suspend,
.resume = wm8400_resume,
.read = wm8400_read,
.write = wm8400_write,
.set_bias_level = wm8400_set_bias_level,
};
static struct snd_soc_codec_driver cx20442_codec_dev = {
.probe = cx20442_codec_probe,
.remove = cx20442_codec_remove,
.reg_cache_default = &cx20442_reg,
.reg_cache_size = ,
.reg_word_size = sizeof(u8),
.read = cx20442_read_reg_cache,
.write = cx20442_write,
.dapm_widgets = cx20442_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
.dapm_routes = cx20442_audio_map,
.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
};

猜测read/write应该和snd_soc_read/write有关,在soc_core.c中注意到snd_soc_read的源码:

unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
{
unsigned int ret; ret = codec->read(codec, reg);
dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
trace_snd_soc_reg_read(codec, reg, ret); return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_read);

因此,要想使用snd_soc_read,必须要设置codec->read回调函数,当我们提供了read/write函数时,在snd_soc_register_codec函数中会设置codec->read

int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
...
codec->write = codec_drv->write;
codec->read = codec_drv->read;
codec->volatile_register = codec_drv->volatile_register;

OK,这里和我们soc_codec_dev_wm8400以及cx20442_codec_dev都对应的上,snd_soc_read最终会调用我们提供的回调函数。

问题来了,soc_codec_dev_wm8993中并没有提供回调函数,snd_soc_read是如何工作的呢?刚开始百思不得其解,肯定会有什么地方设置了codec->read!继续找代码,终于在soc_cache.c中找到了一个神奇的函数:snd_soc_codec_set_cache_io,看看代码片段:

int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control)
{
... codec->write = io_types[i].write;
codec->read = io_types[i].read;
codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;

果然,它设置了codec->read!而在wm8993的probe函数中,有如下的调用:

ret = snd_soc_codec_set_cache_io(codec, , , SND_SOC_I2C);

它设置了I2C的地址宽度为8位,寄存器宽度为16位,I2C通信方式,如果根据这些参数继续追踪io_types[i].read,则会发现它最终调用了I2C的标准读函数:

static unsigned int do_i2c_read(struct snd_soc_codec *codec,
void *reg, int reglen,
void *data, int datalen)
{
struct i2c_msg xfer[];
int ret;
struct i2c_client *client = codec->control_data; /* Write register */
xfer[].addr = client->addr;
xfer[].flags = ;
xfer[].len = reglen;
xfer[].buf = reg;
xfer[].scl_rate = * ; /* Read data */
xfer[].addr = client->addr;
xfer[].flags = I2C_M_RD;
xfer[].len = datalen;
xfer[].buf = data; ret = i2c_transfer(client->adapter, xfer, );
if (ret == )
return ;
else if (ret < )
return ret;
else
return -EIO;
}

至此,想起之前在调试WM8741的时候,有一次不小心把snd_soc_codec_set_cache_io给注释掉了,结果导致snd_soc_read/write完全失效,就是这个原因。

分析至此,结论就很明确了,如果我们使用的是标准的I2C通信,则可以不提供read/write回调,让soc使用默认的do_i2c_read/write。如果我们使用了非标准的通信方式,如GPIO模拟串口,或者其它非标准的I2C通信,则需要提供自定义的回调函数。

Alsa驱动snd_soc_read的底层实现的更多相关文章

  1. arm linux利用alsa驱动并使用usb音频设备

    一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...

  2. LINUX驱动、系统底层

    就业模拟测试题-LINUX驱动.系统底层工程师职位 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:143921试卷录 ...

  3. Android 开发之 ---- 底层驱动开发(一) 【转】

    转自:http://blog.csdn.net/jmq_0000/article/details/7372783 版权声明:本文为博主原创文章,未经博主允许不得转载. 驱动概述 说到 Android ...

  4. Android 开发之 ---- 底层驱动开发(一)

    驱动概述 说到 android 驱动是离不开 Linux 驱动的.Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码).但 Andro ...

  5. Linux ALSA声卡驱动之五:移动设备中的ALSA(ASoC)

    转自http://blog.csdn.net/droidphone/article/details/7165482 1.  ASoC的由来 ASoC--ALSA System on Chip ,是建立 ...

  6. Linux ALSA声卡驱动之一:ALSA架构简介

    声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢! 一.  概述 ALSA是Advanced Linux Sound Architecture ...

  7. Linux&nbsp;ALSA声卡驱动之一:ALS…

    声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢! 一.  概述 ALSA是Advanced Linux Sound Architecture ...

  8. Linux ALSA声卡驱动之一:ALSA架构简介【转】

    本文转载自:http://blog.csdn.net/droidphone/article/details/6271122 声明:本博内容均由http://blog.csdn.net/droidpho ...

  9. Linux设备驱动模型底层架构及组织方式

    1.什么是设备驱动模型? 设备驱动模型,说实话这个概念真的不好解释,他是一个比较抽象的概念,我在网上也是没有找到关于设备驱动模型的一个定义,那么今天就我所学.所了解 到的,我对设备驱动模型的一个理解: ...

随机推荐

  1. jQuery Mobile + HTML5

    最近项目需要,需要构建一个适合手持设备访问的站点,作者从网上查阅了一些资料,本文就是基于此而来. 首先下载jQuery Mobile http://jquerymobile.com/,选择稳定版即可. ...

  2. 移动开发下Xamarin VS PhoneGap

    跨平台开发 移动应用开发对很多开发人员来说是一种令人恐惧的事情.许多企业希望能够通过开发移动应用程序,来提升企业业务水平,开发原生App时往往又缺少专业的Objective C 或 Java 移动开发 ...

  3. C++ 重载操作符与转换

    <C++ Primer 4th>读书笔记 重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号. Sales_item operator+(const Sales ...

  4. 访问IIS元数据库失败解决方法

    问题:访问元数据失败 详细信息 访问 IIS 元数据库失败. 说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信 ...

  5. Atitit org.eclipse.jdt 的ast 架构 Eclipse JDT API spec

    Atitit org.eclipse.jdt 的ast 架构 Eclipse JDT API spec 继承树1 Expression的子类1 获取子类2 继承树 Astnode>express ...

  6. iOS开发---分类和扩展(Categories和Extensions)

      1.分类能够做到的事情主要是:即使在你不知道一个类的源码情况下,向这个类添加扩展的方法.   此外,分类能够保证你的实现类和其他的文件区分开.   1 #import “UIViewControl ...

  7. Leetcode 7 Reverse Integer 数论

    题意:将整数倒置,该题简单但是需要注意数据的范围,难得的好题. 如果出现1000000003或者-2000000003,倒置后的数超过int的范围,因此返回0,出现这种情况可以使用long long, ...

  8. Android动画及图片的缩放和旋转

    Android动画有2种,一种是Tween Animation,另一种是Frame Animation,先说说Tween动画吧. Tween动画是对视图对象中的内容进行一系列简单的转换,比如位置的移动 ...

  9. unity 读取excel表 生成asset资源文件

    做unity 项目也有一段时间了,从unity项目开发和学习中也遇到了很多坑,并且也从中学习到了很多曾经未接触的领域.项目中的很多功能模块,从今天开始把自己的思路和代码奉上给学渣们作为一份学习的资料. ...

  10. time

    http://blog.csdn.net/JGood/archive/2010/04/07/5457284.aspx    Python提供了多个内置模块用于操作日期时间,像calendar,time ...