Alsa驱动snd_soc_read的底层实现
在分析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的底层实现的更多相关文章
- arm linux利用alsa驱动并使用usb音频设备
一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...
- LINUX驱动、系统底层
就业模拟测试题-LINUX驱动.系统底层工程师职位 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:143921试卷录 ...
- Android 开发之 ---- 底层驱动开发(一) 【转】
转自:http://blog.csdn.net/jmq_0000/article/details/7372783 版权声明:本文为博主原创文章,未经博主允许不得转载. 驱动概述 说到 Android ...
- Android 开发之 ---- 底层驱动开发(一)
驱动概述 说到 android 驱动是离不开 Linux 驱动的.Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码).但 Andro ...
- Linux ALSA声卡驱动之五:移动设备中的ALSA(ASoC)
转自http://blog.csdn.net/droidphone/article/details/7165482 1. ASoC的由来 ASoC--ALSA System on Chip ,是建立 ...
- Linux ALSA声卡驱动之一:ALSA架构简介
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢! 一. 概述 ALSA是Advanced Linux Sound Architecture ...
- Linux ALSA声卡驱动之一:ALS…
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢! 一. 概述 ALSA是Advanced Linux Sound Architecture ...
- Linux ALSA声卡驱动之一:ALSA架构简介【转】
本文转载自:http://blog.csdn.net/droidphone/article/details/6271122 声明:本博内容均由http://blog.csdn.net/droidpho ...
- Linux设备驱动模型底层架构及组织方式
1.什么是设备驱动模型? 设备驱动模型,说实话这个概念真的不好解释,他是一个比较抽象的概念,我在网上也是没有找到关于设备驱动模型的一个定义,那么今天就我所学.所了解 到的,我对设备驱动模型的一个理解: ...
随机推荐
- [安卓] 3、EditText使用小程序
这里比较简单,看下面代码就能知道了:在按钮的点击事件时用String str = et.getText().toString();获取文本内容. public class MainActivity e ...
- [ACM_数学] Taxi Fare [新旧出租车费差 水 分段函数]
Description Last September, Hangzhou raised the taxi fares. The original flag-down fare in Hangzhou ...
- 如何真正重写window对象的方法
重写window对象的方法不是一件新奇的事,比如我们可能需要改变默认alert的行为,如何安全的重写呢? 小菜看到某知名IT网站是这样的写法: window.alert = function(){}; ...
- C#与数据库访问技术总结(十六)之 DataSet对象
DataSet对象 DataSet对象可以用来存储从数据库查询到的数据结果,由于它在获得数据或更新数据后立即与数据库断开,所以程序员能用此高效地访问和操作数据库. 并且,由于DataSet对象具有离线 ...
- Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725
Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725 1. DSL主要分为三类:外部DSL.内部DSL,以及语言工作台. 1 2. DSL ...
- paip.python3 的类使用跟python2 的不同之处
paip.python3 的类使用跟python2 的不同之处 #------python3的写法而且使用.. #class syllable(BaseClassA, BaseClassB): cla ...
- javaweb学习总结(二十三)——jsp自定义标签开发入门
一.自定义标签的作用 自定义标签主要用于移除Jsp页面中的java代码. 二.自定义标签开发和使用 2.1.自定义标签开发步骤 1.编写一个实现Tag接口的Java类(标签处理器类) 1 packag ...
- Android显示等宽图片的问题
安卓开发常遇到一个问题,就是在listView里面,在不知道图片宽高的前提下,另图片布满屏幕(图片宽度等于屏幕宽度,高度自适应).在listView中,只是设置scaleType,imageView. ...
- SoapUI Pro Project Solution Collection-DataSource(jdbc,excel)
here give a solution for excel file change the excel configuration these: Set Excel file path in cur ...
- 声色贴生成图片总结 Imagick
2014-08-24 都是按以前的程序进行了,但去年8月都可以用Imagick正常生成CMYK的图片,但今天就是不行. 经过一切测试方法及思路,解决方法如下. 问题主要出现在: 生成的二维码是RGB格 ...