内核加载驱动:
module_init(snd_soc_init);
加载完成之后进入:snd_soc_init() 初始化函数
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
printk(KERN_WARNING
"ASoC: Failed to create debugfs directory\n");
snd_soc_debugfs_root = NULL;
}
if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
&codec_list_fops))
pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
&dai_list_fops))
pr_warn("ASoC: Failed to create DAI list debugfs file\n");
if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
&platform_list_fops))
pr_warn("ASoC: Failed to create platform list debugfs file\n");
#endif
snd_soc_util_init();
return platform_driver_register(&soc_driver);
}
soc_driver原型如下:
/* ASoC platform driver */
static struct platform_driver soc_driver = {
.driver = {
.name = "soc-audio",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
},
.probe = soc_probe,
.remove = soc_remove,
};
在执行platform_driver_register(&soc_driver); 这条语句之后 进入 soc_probe
该函数原型如下:
/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
int ret = 0;
/*
* no card, so machine driver should be registering card
* we should not be here in that case so ret error
*/
if (!card)
return -EINVAL;
/* 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;
}
调用该函数之后执行:ret = snd_soc_register_card(card)->snd_soc_instantiate_cards();->snd_soc_instantiate_card(card);
->ret = snd_soc_init_codec_cache(codec, compress_type);->ret = snd_soc_cache_init(codec);
执行到ret = snd_soc_cache_init(codec);函数之后会做一些处理 , 该函数原型如下
int snd_soc_cache_init(struct snd_soc_codec *codec)
{
int i;
for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
if (cache_types[i].id == codec->compress_type)
break;
/* Fall back to flat compression */
if (i == ARRAY_SIZE(cache_types)) {
dev_warn(codec->dev, "Could not match compress type: %d\n",
codec->compress_type);
i = 0;
}
mutex_init(&codec->cache_rw_mutex);
codec->cache_ops = &cache_types[i];
if (codec->cache_ops->init) {
if (codec->cache_ops->name)
dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
codec->cache_ops->name, codec->name);
return codec->cache_ops->init(codec);
}
return -ENOSYS;
}
codec->cache_ops = &cache_types[i]; 这句就是赋初始值 cache_types的定义如下
static const struct snd_soc_cache_ops cache_types[] = {
/* Flat *must* be the first entry for fallback */
{
.id = SND_SOC_FLAT_COMPRESSION,
.name = "flat",
.init = snd_soc_flat_cache_init,
.exit = snd_soc_flat_cache_exit,
.read = snd_soc_flat_cache_read,
.write = snd_soc_flat_cache_write,
.sync = snd_soc_flat_cache_sync
},
#ifdef CONFIG_SND_SOC_CACHE_LZO
{
.id = SND_SOC_LZO_COMPRESSION,
.name = "LZO",
.init = snd_soc_lzo_cache_init,
.exit = snd_soc_lzo_cache_exit,
.read = snd_soc_lzo_cache_read,
.write = snd_soc_lzo_cache_write,
.sync = snd_soc_lzo_cache_sync
},
#endif
{
.id = SND_SOC_RBTREE_COMPRESSION,
.name = "rbtree",
.init = snd_soc_rbtree_cache_init,
.exit = snd_soc_rbtree_cache_exit,
.read = snd_soc_rbtree_cache_read,
.write = snd_soc_rbtree_cache_write,
.sync = snd_soc_rbtree_cache_sync
}
};
根据上下文, 我们使用的是SND_SOC_FLAT_COMPRESSION 这个
这个结构体里面的函数 所有原型如下
init函数
static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
{
const struct snd_soc_codec_driver *codec_drv;
codec_drv = codec->driver;
if (codec->reg_def_copy)
codec->reg_cache = kmemdup(codec->reg_def_copy,
codec->reg_size, GFP_KERNEL);
else
codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
if (!codec->reg_cache)
return -ENOMEM;
return 0;
}
如果def_copy有初始值, 那么就赋值给reg_cache (寄存器缓存值) 这个函数主要是 给寄存器的cache赋初始值
read函数
static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value)
{
*value = snd_soc_get_cache_val(codec->reg_cache, reg,
codec->driver->reg_word_size);
return 0;
}
static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
unsigned int word_size)
{
if (!base)
return -1;
switch (word_size) {
case 1: {
const u8 *cache = base;
return cache[idx];
}
case 2: {
const u16 *cache = base;
return cache[idx];
}
default:
BUG();
}
/* unreachable */
return -1;
}
从代码中可以看到, read函数,是直接从codec->reg_cache 中读取de , 通过查找init的代码 得知 如果codec->reg_def_copy有值,那么 codec->reg_cache 是从codec->reg_def_copy拷贝来的, 不然codec->reg_cache的值默认为0
上面是soc_sound ,read的流程。
write函数
static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
snd_soc_set_cache_val(codec->reg_cache, reg, value,
codec->driver->reg_word_size);
return 0;
}
static bool snd_soc_set_cache_val(void *base, unsigned int idx,
unsigned int val, unsigned int word_size)
{
switch (word_size) {
case 1: {
u8 *cache = base;
if (cache[idx] == val)
return true;
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
if (cache[idx] == val)
return true;
cache[idx] = val;
break;
}
default:
BUG();
}
return false;
}
从代码中可以看到,read , write都是操作reg_cache缓存中都写数据 , 具体往寄存器中写入数值 继续往下看
wm8960为例子 , 写寄存器函数为:
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
dev_printk(KERN_DEBUG,codec->dev, "write %x = %x\n", reg, val);
trace_snd_soc_reg_write(codec, reg, val);
return codec->write(codec, reg, val);
}
codec->write(codec, reg, val); 调用的是这个函数。
在wm8960.c的wm8960_i2c_probe->snd_soc_register_codec函数中有如下赋值:
codec->write = codec_drv->write;
codec->read = codec_drv->read;
所以如果找到了
codec->write
codec->read
这二个函数, 那么操作读写也能找到。 继续看
wm8960.c中 初始化执行wm8960_probe之后调用了一个函数ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); 该函数原型为
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control)
{
int i;
for (i = 0; i < ARRAY_SIZE(io_types); i++)
if (io_types[i].addr_bits == addr_bits &&
io_types[i].data_bits == data_bits)
break;
if (i == ARRAY_SIZE(io_types)) {
printk(KERN_ERR
"No I/O functions for %d bit address %d bit data\n",
addr_bits, data_bits);
return -EINVAL;
}
codec->write = io_types[i].write;
codec->read = io_types[i].read;
codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
switch (control) {
case SND_SOC_I2C:
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
codec->hw_write = (hw_write_t)i2c_master_send;
#endif
if (io_types[i].i2c_read)
codec->hw_read = io_types[i].i2c_read;
codec->control_data = container_of(codec->dev,
struct i2c_client,
dev);
break;
case SND_SOC_SPI:
#ifdef CONFIG_SPI_MASTER
codec->hw_write = do_spi_write;
#endif
codec->control_data = container_of(codec->dev,
struct spi_device,
dev);
break;
}
return 0;
}
代码中对write和read进行了赋值
codec->write = io_types[i].write;
codec->read = io_types[i].read;
而io_types的原型如下
static struct {
int addr_bits;
int data_bits;
int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
{
.addr_bits = 4, .data_bits = 12,
.write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
},
{
.addr_bits = 7, .data_bits = 9,
.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
},
{
.addr_bits = 8, .data_bits = 8,
.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
.i2c_read = snd_soc_8_8_read_i2c,
},
{
.addr_bits = 8, .data_bits = 16,
.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
.i2c_read = snd_soc_8_16_read_i2c,
},
{
.addr_bits = 16, .data_bits = 8,
.write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
.i2c_read = snd_soc_16_8_read_i2c,
},
{
.addr_bits = 16, .data_bits = 16,
.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
.i2c_read = snd_soc_16_16_read_i2c,
},
};
通过ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); 这句话得知, 我们使用的是7,9
7_9的读写函数如下
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
return do_hw_write(codec, reg, value, data, 2);
}
static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value, const void *data, int len)
{
int ret;
if (!snd_soc_codec_volatile_register(codec, reg) &&
reg < codec->driver->reg_cache_size &&
!codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
}
if (codec->cache_only) {
codec->cache_sync = 1;
return 0;
}
ret = codec->hw_write(codec->control_data, data, len);
if (ret == len)
return 0;
if (ret < 0)
return ret;
else
return -EIO;
}
int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
int ret;
mutex_lock(&codec->cache_rw_mutex);
if (codec->cache_ops && codec->cache_ops->write) {
ret = codec->cache_ops->write(codec, reg, value);
mutex_unlock(&codec->cache_rw_mutex);
return ret;
}
mutex_unlock(&codec->cache_rw_mutex);
return -ENOSYS;
}
可以看到, 写函数主要操作了二个部分, 一个是 ret = snd_soc_cache_write(codec, reg, value); 另一个是 ret = codec->hw_write(codec->control_data, data, len);
snd_soc_cache_write的原型如下
int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
int ret;
mutex_lock(&codec->cache_rw_mutex);
if (codec->cache_ops && codec->cache_ops->write) {
ret = codec->cache_ops->write(codec, reg, value);
mutex_unlock(&codec->cache_rw_mutex);
return ret;
}
mutex_unlock(&codec->cache_rw_mutex);
return -ENOSYS;
}
从代码可以看到 写缓存调用的是 ret = codec->cache_ops->write(codec, reg, value); 这个在上文中已经提到。 cache_ops->write的调用函数
ret = codec->hw_write(codec->control_data, data, len); 这个函数调用的原型在snd_soc_codec_set_cache_io函数中也有赋值
switch (control) {
case SND_SOC_I2C:
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
codec->hw_write = (hw_write_t)i2c_master_send;
#endif
if (io_types[i].i2c_read)
codec->hw_read = io_types[i].i2c_read;
codec->control_data = container_of(codec->dev,
struct i2c_client,
dev);
break;
case SND_SOC_SPI:
#ifdef CONFIG_SPI_MASTER
codec->hw_write = do_spi_write;
#endif
codec->control_data = container_of(codec->dev,
struct spi_device,
dev);
break;
}
我们使用的是I2C 所以执行i2c_master_send
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
int ret;
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
还有一个问题没交代清楚, 就是codec->reg_def_copy 的数值, 在wm8960.c中赋值的。
在wm8960.c中 i2c初始化 wm8960_i2c_probe函数中调用了
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8960, &wm8960_dai, 1);
该函数中有一段代码
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)
{
...
/* allocate CODEC register cache */
if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
codec->reg_size = reg_size;
/* it is necessary to make a copy of the default register cache
* because in the case of using a compression type that requires
* the default register cache to be marked as __devinitconst the
* kernel might have freed the array by the time we initialize
* the cache.
*/
if (codec_drv->reg_cache_default) {
codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
reg_size, GFP_KERNEL);
if (!codec->reg_def_copy) {
ret = -ENOMEM;
goto fail;
}
}
}
如果codec_drv->reg_cache_default有值, 则cade->reg_def_copy就拷贝过来。 code->der是传进来的参数 为soc_codec_dev_wm8960
soc_codec_dev_wm8960的原型为
static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
.probe = wm8960_probe,
.remove = wm8960_remove,
.suspend = wm8960_suspend,
.resume = wm8960_resume,
.set_bias_level = wm8960_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8960_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8960_reg,
};
所以code_dev->reg_cache_default 指向的为wm8960_reg数组。
/*
* wm8960 register cache
* We can't read the WM8960 register space when we are
* using 2 wire for device control, so we cache them instead.
*/
static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
0x0097, 0x0097, 0x0000, 0x0000,
0x0000, 0x0008, 0x0000, 0x000a,
0x01c0, 0x0000, 0x00ff, 0x00ff,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x007b, 0x0100, 0x0032,
0x0000, 0x00c3, 0x00c3, 0x01c0,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0100, 0x0100, 0x0050, 0x0050,
0x0050, 0x0050, 0x0000, 0x0000,
0x0000, 0x0000, 0x0040, 0x0000,
0x0000, 0x0050, 0x0050, 0x0000,
0x0002, 0x0037, 0x004d, 0x0080,
0x0008, 0x0031, 0x0026, 0x00e9,
};
综上, soc在进行读的时候, 完全是操作wm8960这个数组,而在写的时候, 会先把数值写进数组, 在进行寄存器操作
新手:接触linux一个星期, 不知道分析的对不对。 希望大家多多指点。