天天看點

Linux核心調試sysfs

在調試驅動,可能需要對驅動裡的某些變量進行讀寫,或函數調用。可通過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目錄下删除一個屬性集合,并删除集合中的屬性檔案      

繼續閱讀