函数宏DEVICE_ATTR,原型为
#define DEVICE_ATTR(_name,_mode,_show,_store)\
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
参数介绍:
_name :文件节点名称
_mode :文件节点权限
_show :表示读方法,当我们cat 这个节点时,调用此方法
_store:表示写方法,当我们echo值到这个节点时,调用此方法。
回调函数:
ssize_t xxx_show(struct device *dev,
struct device_attribute *attr, char *buf) //show 函数原型
使用cat时调用此方法,显示出来的值为buf缓存区的值。
ssize_t xxx_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count) //store 函数原型
使用echo写入值时,调用此方法,buf的值为echo的值 注意echo写入的字符串后会自带一个’\n’也就是换行。
DEVICE_ATTR(name, 0xxx, xxx_show, xxx_store); //调用宏进行文件节点创建。
在调用宏,并写好回调函数后,应当使用device_create_file创建device属性文件。
int device_create_file(struct device *,struct device_attribute *); //创建device属性文件
void device_remove_file(struct device *,struct device_attribute *); //移除device属性文件
注意事项:
1.缓冲区的大小应总是PAGE_SIZE个字节。
2.show方法应该返回放入缓冲区的字节数,即snprintf的返回值
3.show方法应该总是使用snprintf.
4.store方法应该返回实际使用的字节数,可以使用strlen来得到。
snprintf 函数介绍:
int snprintf(char *str,size_t n,const char *format, ...);
将可变参数“…”按照format的格式格式化字符串,然后拷贝至str中。
如果字符串长度 < n ,则将此字符串全部复制到str中,并给其后添加一个字符串结束符(’\0’)
如果字符串长度 >= n,则只能将其中的n-1个字符复制到str中,并给其后添加一个字符串结束符。
函数执行成功返回预写入的字符串长度,若出错则返回负值。
驱动增加可控制节点
//alvin add
static ssize_t rt5670_codec_controll_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct rt5670_priv *rt5670 = i2c_get_clientdata(client);
struct snd_soc_codec *codec = rt5670->codec;
int ret,val;
char *str = NULL;
//if (rt5670_readable_register(dev, RT5670_STO1_ADC_DIG_VOL))
//{
val = snd_soc_read(codec, RT5670_STO1_ADC_DIG_VOL);
if (0x8080 == (val & 0x8080)){
str = "off";
} else
str = "on";
ret = snprintf(buf, PAGE_SIZE,"%s : 0x1c :%x\n",str,val);
return ret;
}
static ssize_t rt5670_codec_controll_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct rt5670_priv *rt5670 = i2c_get_clientdata(client);
struct snd_soc_codec *codec = rt5670->codec;
int val;
//int ret;
//char *str = "on\n";
val = snd_soc_read(codec, RT5670_STO1_ADC_DIG_VOL);
//printk("alvin debug:\nval = %d buf is %s\nstr is %s\n",val,buf,str);
//ret = strcmp(buf,str);
//printk("ret : %d\n",ret);
if (strncmp(buf,"on\n",strlen(buf)) == 0){
val &= 0x7f7f;
printk("alvin debug1:\n %x",val);
}
if (strncmp(buf,"off\n",strlen(buf)) == 0){
val |= 0x8080;
printk("alvin debug2:\n %x",val);
}
printk("alvin debug3:\nval = %x \n",val);
snd_soc_write(codec,RT5670_STO1_ADC_DIG_VOL,val);
return count;
}
static DEVICE_ATTR(codec_controll, 0660, rt5670_codec_controll_show, rt5670_codec_controll_store);
probe函数中添加:
ret = device_create_file(codec->dev, &dev_attr_codec_controll);
if (ret != 0) {
dev_err(codec->dev,
"Failed to create codec_controll sysfs files: %d\n", ret);
return ret;
}