1.ATTR介紹
應(yīng)用層與內(nèi)核驅(qū)動層的交互胜臊,一般是通過驅(qū)動節(jié)點的讀寫來實現(xiàn)勺卢。即驅(qū)動開發(fā)人員在完成驅(qū)動設(shè)備的創(chuàng)建后,同時會創(chuàng)建對應(yīng)的節(jié)點象对,且提供節(jié)點的訪問函數(shù)黑忱,以便應(yīng)用層開發(fā)調(diào)用。驅(qū)動提供接口的方法有注冊file_operation結(jié)構(gòu)體勒魔,另一種方法就是本文要記錄的建立ATTR節(jié)點甫煞。
使用DEVICE_ATTR,可以實現(xiàn)驅(qū)動在sys目錄自動創(chuàng)建文件,我們只需要實現(xiàn)show和store函數(shù)即可冠绢。然后在應(yīng)用層就能通過cat和echo命令來對sys創(chuàng)建出來的文件進行讀寫驅(qū)動設(shè)備,實現(xiàn)交互抚吠。
2.基本原理概述
2.1 DEVICE_ATTR()
DEVICE_ATTR()定義位于Android/kernel-4.14/include/linux/device.h
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
__ATTR()位于Android/kernel-4.14/include/linux/sysfs.h
#define __ATTR_PREALLOC(_name, _mode, _show, _store) { \
.attr = {.name = __stringify(_name), \
.mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\
.show = _show, \
.store = _store, \
}
發(fā)現(xiàn)DEVICE_ATTR()只是內(nèi)核定義的一個宏,使用此宏作用相當(dāng)于定義并填充了一個device_attribute類型的結(jié)構(gòu)體dev_attr_xx弟胀。其中需要注意的是_mode參數(shù)表示文件權(quán)限楷力,一般是給0664喊式,權(quán)限比0664高會報錯(也可以用S_IWUSR(用戶可寫),S_IRUSR(用戶可讀)等宏代替)萧朝。
將DEVICE_ATTR()宏完全展開
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = { \
.attr = {.name = __stringify(_name), \
.mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\
.show = _show, \
.store = _store, \
}
2.2 device_attribute
device_attribute同樣定義位于Android/kernel-4.14/include/linux/device.h
/* interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
device_attribute結(jié)構(gòu)體內(nèi)包含一個attribute 和 show岔留、store函數(shù)。其中show接口實現(xiàn)adb內(nèi) cat讀取顯示功能检柬,store實現(xiàn)的是echo 寫入功能贸诚。
因此在驅(qū)動中,需要實現(xiàn)show厕吉、store接口功能酱固。
2.3 device_create_file
在實例完struct device_attribute dev_attr_xx后,需要將此結(jié)構(gòu)體通過device_create_file注冊到內(nèi)核中/sys/bus/platform/devices下头朱。定義在kernel-4.14/drivers/base/core.c
int device_create_file(struct device *dev,
const struct device_attribute *attr)
{
int error = 0;
if (dev) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
}
return error;
}
EXPORT_SYMBOL_GPL(device_create_file);
3.實際操作
首先在內(nèi)核創(chuàng)建一個驅(qū)動文件运悲,這里命名為attr_test。
增加節(jié)點讀接口
/創(chuàng)建ATTR可讀節(jié)點接口/
static ssize_t show_attr_test(struct device *dev, struct device_attribute *attr, char *buf)
{
int ret = 0;
ret = snprintf(buf, strlen(global_char), "%s\n", global_char);
printk("%s:%d: Entry %s, buf:%s", __FILE__, __LINE__, __func__, buf);
return ret;
}
/* 創(chuàng)建ATTR可寫節(jié)點接口 */
static ssize_t store_attr_test(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
memset(global_char, 0x00, sizeof(global_char));
ret = snprintf(global_char, sizeof(global_char), "%s", buf);
printk("%s:%d: Entry %s", __FILE__, __LINE__, __func__);
return ret;
}
填充到結(jié)構(gòu)體dev_attr_attr_test
DEVICE_ATTR(attr_test, 0664, show_attr_test, store_attr_test);
注冊到內(nèi)核中
#if 0
//默認(rèn)創(chuàng)建節(jié)點 注冊節(jié)點: /sys/class/bus/platform/attr_test
ret = device_create_file(&pdev->dev, &dev_attr_attr_test);
#else
//自定義路徑/sys/class/diy_class/diy_device/attr_test
diy_class = class_create(THIS_MODULE, "diy_class");
diy_device = device_create(diy_class, NULL,
MKDEV(0, 0),
NULL, "diy_device");
ret = device_create_file(diy_device, &dev_attr_attr_test);
#endif
注意:在實現(xiàn)show项钮、store時班眯,返回值必須為具體的字符長度,若返回0則會出導(dǎo)致數(shù)據(jù)傳輸出現(xiàn)問題烁巫,cat署隘、echo功能也會失敗。
2020-06-21