ALSA驱动中snd_soc_write()原理分析及demo

其实底层是调用remap_write()者i2c_transter()来写i2c设备寄存器,自查。
1.Audio Codec查结构体
kernel/include/sound/soc.h
/* SoC Audio Codec device */
<1>.struct snd_soc_codec {
  const struct snd_soc_codec_driver *driver;
  struct snd_soc_component component;
}

<2>./* codec driver */
struct snd_soc_codec_driver {
   int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
};

struct snd_soc_component { 
  struct snd_soc_dai_driver *dai_drv;
  const struct snd_soc_component_driver *driver;
  int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
  struct snd_soc_codec *codec; 
  struct regmap *regmap;
};

******************************************************************************

1.snd_soc_write()用法代码分析
kernel/sound/soc/soc-io.c
int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,  unsigned int val){
  return snd_soc_component_write(&codec->component, reg, val);
}

int snd_soc_component_write(struct snd_soc_component *component,unsigned int reg, unsigned int val){
 if(component->regmap)
   return regmap_write(component->regmap, reg, val);
 else if (component->write)  
   return component->write(component, reg, val);
 else
   return -EIO;
}
继续往下追,其实底层可以调用remap_write()或者i2c_transter()来写i2c设备.
问题:
调用snd_soc_write()函数后,为什么会调用snd_soc_codec_driver结构体里的write的回调函数?
//1.测试数据
struct snd_soc_codec *codec;
snd_soc_write(codec, 0x08, 0x01);

//2.注册回调函数
static int xxx_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val){
  //这里应该是snd_soc_write()传进来的reg = 8,val = 1;
  printk(KERN_ERR “%s, %d, reg = %d, val = %d\n", __func__,__LINE__,reg, val);
}

static const struct snd_soc_codec_driver soc_codec_dev_xxx = {
     .write =   xxx_write,
}; 

//把soc_codec_dev_xxx放到snd_soc_register_codec()里注册到codec上,其他参数先不管.
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_xxx, xxx, xxx);

//2.分析snd_soc_register_codec()函数
kernel/sound/soc/soc-core.c
int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv,…){
  //只看传进来的snd_soc_codec_driver *codec_drv参数。
  //这里判断codec_drv->write为真,又注册了一个回调函数,我们看下snd_soc_codec_drv_write()回调函数的实现。
  if(codec_drv->write)
    codec->component.write = snd_soc_codec_drv_write;    
}

//3.snd_soc_codec_drv_write()回调函数的实现
static int snd_soc_codec_drv_write(struct snd_sic_component *component, unsigned int reg, unsigned int val){
  //使用snd_soc_codec里的snd_sic_component成员变量,获取snd_soc_codec结构体首地址,snd_soc_component_to_codec通过。使用container_of()函数实现,可以自查.
  struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
  //snd_soc_codec调用snd_soc_codec_driver结构体的write回调函数,就是调用了上边在soc_codec_dev_xxx里注册的回调函数。
  return codec->driver->write(codec, reg, val);
}

*********************************************************************************

4.仿照snd_soc_write()函数写了一个回调demo用法.

#include 
/*struct define*/
static struct snd_soc_codec_driver {
    int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
};

static struct snd_soc_component { 
    int (*write)(struct snd_soc_component *com, unsigned int, unsigned int);
};

static struct snd_soc_codec {
    struct snd_soc_codec_driver *driver;
    struct snd_soc_component component;
};

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({				\
	    const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
	    (type *)( (char *)__mptr - offsetof(type,member) );})

struct snd_soc_codec *codec = NULL;

//callback实现
int callback_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val){
    printf("xxx--->%s(), %d, reg: %d, val: %d\n\n",__FUNCTION__,__LINE__,reg,val);
    return 0;
}

static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val){
    struct snd_soc_codec *c_codec = container_of(component, struct snd_soc_codec, component);
    printf("xxx--->%s(), %d, reg: %d, val: %d\n",__FUNCTION__,__LINE__,reg,val);    
    return codec->driver->write(c_codec, reg, val);
}


void codec_register(struct snd_soc_codec_driver *codec_drv){
    printf("xxx--->%s(), %d\n",__FUNCTION__,__LINE__);
    if(codec_drv->write)
	codec->component.write = snd_soc_codec_drv_write;
}

//把snd_soc_write()和callback_write()关联起来;我们调用snd_soc_write就会调用callback_write()函数.
int snd_soc_write(struct snd_soc_codec *codec,unsigned int reg, unsigned int val){
    printf("xxx--->%s(), %d, reg: %d, val: %d\n",__FUNCTION__,__LINE__,reg,val);
    if(codec->component.write)
	return codec->component.write(&codec->component, reg, val);    
    return 0;
}

int main(){
    codec = (struct snd_soc_codec*)malloc(sizeof(struct snd_soc_codec));
    //注册回调函数
    struct snd_soc_codec_driver test_codec = {
	.write = callback_write,
    };
    
    codec->driver = &test_codec;
    //关联
    codec_register(codec->driver);

    //方式1:最简单的回调.
    //codec->driver->write(codec, 11, 35); 
    
    //方式2        
    while(1){
	snd_soc_write(codec, 11, 35);
    //最简化
    //codec->driver->write(codec, 11, 35);
	sleep(1);
    }
    
    if(codec)
	free(codec);
}

 

你可能感兴趣的:(Android,Audio学习,Linux,kernel学习)