在調試驅動,可能需要對驅動裡的某些變量進行讀寫,或函數調用。可通過sysfs接口建立驅動對應的屬性,使得可以在使用者空間通過sysfs接口的show和store函數與硬體互動;
Syss接口可通過sysfs_create_group()來建立,如果裝置驅動要建立,需要用到函數宏DEVICE_ATTR;
另外總線對應BUS_ATTR、裝置驅動對應DRIVER_ATTR、類(class)對應CLASS_ATTR,均在kernel/include/linux/device.h下定義:
1 //下面的show和store隻是簡單舉例
2 static ssize_t gpio_show(struct device *d, struct device_attribute*attr, char *buf)
3 {
4 printk("gpio_show()\n");
5 returnpr_info("store\n");
6 }
7
8 static ssize_t gpio_store(struct device *d, struct device_attribute *attr,const char *buf,size_t count)
9 {
10 printk("gpio_store()\n");
11 returnpr_info("store\n");
12 }
13
14 //用DEVICE_ATTR宏建立屬性gpio檔案,如果show()或是store()沒有功能,就以NULL代替
15 static DEVICE_ATTR(gpio, S_IWUSR |S_IRUGO, gpio_show, gpio_store);
16
17 //屬性結構體數組最後一項必須以NULL結尾。
18 static struct attribute *gpio_attrs[] = {
19 &dev_attr_gpio.attr,
20 NULL
21 };
DEVICE_ATTR:
DEVICE_ATTR 的定義DEVICE_ATTR(_name,_mode, _show, _store);可知這裡gpio是name,mode是S_IWUSR |S_IRUGO,讀操作_show是gpio_show函數,寫操作_store 是gpio_store函數;
因為:
1 #define DEVICE_ATTR(_name, _mode, _show, _store) \
2 struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
device_attribute:
1 /* interface for exporting device attributes */
2 struct device_attribute {
3 struct attribute attr;
4 ssize_t (*show)(struct device *dev, struct device_attribute *attr,
5 char *buf);
6 ssize_t (*store)(struct device *dev, struct device_attribute *attr,
7 const char *buf, size_t count);
8 };
Mode是權限位,在kernel/include/uapi/linux/stat.h
1 #define S_IRWXU 00700 //使用者可讀寫和執行
2 #define S_IRUSR 00400//使用者可讀
3 #define S_IWUSR 00200//使用者可寫
4 #define S_IXUSR 00100//使用者可執行
5
6 #define S_IRWXG 00070//使用者組可讀寫和執行
7 #define S_IRGRP 00040//使用者組可讀
8 #define S_IWGRP 00020//使用者組可寫
9 #define S_IXGRP 00010//使用者組可執行
10
11 #define S_IRWXO 00007//其他可讀寫和執行
12 #define S_IROTH 00004//其他可讀
13 #define S_IWOTH 00002//其他可寫
14 #define S_IXOTH 00001//其他可執行
device_attribute結構體
為了使對屬性的讀寫變得有意義,一般将attribute結構嵌入到其他資料結構中。子系統通常都會定義自己的屬性結構,并且提供添加和删除屬性檔案的包裝函數,比如裝置屬性結構體定義:
1 /* interface for exporting device attributes */
2 struct device_attribute {
3 struct attribute attr;
4 ssize_t (*show)(structdevice *dev, struct device_attribute *attr,
5 char*buf);
6 ssize_t (*store)(structdevice *dev, struct device_attribute *attr,
7 const char *buf, size_t count);
8 };
2. 定義attribute屬性結構體數組到屬性組中:
1 static const struct attribute_group gpio_attr_grp = {
2 .attrs = gpio_attrs,
3 }
4 我們這裡隻有一個屬性結構體數組隻有一個成員,可以有多個,比如:
5 static struct attribute *gpio_keys_attrs[] = {
6 &dev_attr_keys.attr,
7 &dev_attr_switches.attr,
8 &dev_attr_disabled_keys.attr,
9 &dev_attr_disabled_switches.attr,
10 &dev_attr_test.attr,
11 NULL,
12 };
屬性attribute結構體定義:
1 struct attribute {
2 const char *name;
3 umode_t mode;
4 #ifdef CONFIG_DEBUG_LOCK_ALLOC
5 bool ignore_lockdep:1;
6 struct lock_class_key *key;
7 struct lock_class_key skey;
8 #endif
9 };
建立sysfs接口後,就可以在adb shell 終端檢視到和操作接口了。當我們将資料 echo 到接口中時,在使用者空間完成了一次 write 操作,對應到 kernel ,調用了驅動中的”store”。當我們cat一個接口時則會調用”show” 。這樣就建立了 android 層到 kernel 的橋梁,操作的細節在”show”和”store” 中完成的。
3. 建立屬性檔案的sysfs接口:
1 ret = sysfs_create_group(&pdev->dev.kobj,&gpio_attr_grp);
2 sysfs_create_group()在kobj目錄下建立一個屬性集合,并顯示集合中的屬性檔案。如果檔案已存在,會報錯。
3
4 //删除接口
5 sysfs_remove_group(&pdev->dev.kobj,&gpio_keys_attr_group);
6 sysfs_remove_group()在kobj目錄下删除一個屬性集合,并删除集合中的屬性檔案