在調試驅動,可能需要對驅動里的某些變數進行讀寫,或函數調用。可通過sysfs介面創建驅動對應的屬性,使得可以在用戶空間通過sysfs介面的show和store函數與硬體交互; Syss介面可通過sysfs_create_group()來創建,如果設備驅動要創建,需要用到函數巨集DEVICE_ATTR; ...
在調試驅動,可能需要對驅動里的某些變數進行讀寫,或函數調用。可通過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目錄下刪除一個屬性集合,並刪除集合中的屬性文件