花了兩天大概了解了sysfs,想著為下來了PCI總線與設備的驅動調試各方面做些準備.不過sysfs還真是有些復雜,或者說本來就只想"吃快餐".本想用現有的DEVICE_ATTR, DRIVER_ATTR, BUS_ATTR, CLASS_ATTR,可是這幾種設備的依賴有點多,只能參照別人的自己做了個.雖說sysfs比之前的ioctl在用戶層方面了不少,可是內核層要做的東西和要理解的東西會多些.本來還想再了解一下procfs, devfs,不過看來也只能看時間和精力了./* * my_dev_sysfs.c * author: fi9 * date: 2010-11-04 */#include <linux/config.h>#include <linux/module.h>#include <linux/kobject.h>#include <linux/sysfs.h>#include <linux/delay.h>#define MY_SYSFS_NAME "test"ssize_t my_attr_show(struct kobject *ko, struct attribute *attr, char *buf);ssize_t my_attr_store(struct kobject *kobj, struct attribute *attr,const char *buf, size_t count);void my_attr_release(struct kobject *ko);typedef struct my_attribute{ struct attribute attr; ssize_t (*show)(char *buf); ssize_t (*store)(const char *buf, size_t count);} my_attribute_t;#define MY_ATTR(_name, _mode, _show, _store) \my_attribute_t my_attr_##_name = { \ .attr = {.name = __stringify(_name) , .mode = _mode }, \ .show = _show, \ .store = _store, \};typedef struct my_info { struct kobject kobj;} my_info_t;struct sysfs_ops my_sysfs_ops = { .show = my_attr_show, .store = my_attr_store};////// begin 添加或修改此處ssize_t test_ata_show(char *buf);ssize_t test_ata_store(const char *buf, size_t n);MY_ATTR(ata, S_IRUGO|S_IWUGO, test_ata_show, test_ata_store);////// end 添加或修改此處struct attribute* my_sysfs_attrs[] = { &my_attr_ata.attr, // 添加或修改此處 NULL};struct kobj_type my_ktype = { .release = my_attr_release, .sysfs_ops = &my_sysfs_ops, .default_attrs = my_sysfs_attrs};my_info_t *my_info;////// begin 添加或修改此處ssize_t test_ata_show(char *buf){ int data; if (ata_on) data = 1; else data = 0; return sprintf(buf, "%d\n", ((data) ? 1 : 0));}ssize_t test_ata_store(const char *buf, size_t n){ int val; sscanf(buf, "%d", &val); if (val) { // ata on } else { // ata off } return n;}////// end 添加或修改此處// common func implssize_t my_attr_show(struct kobject *ko, struct attribute *attr, char *buf){ ssize_t len = 0; my_attribute_t *a = container_of(attr, my_attribute_t, attr); if (a->show) { len = a->show(buf); } return len;}ssize_t my_attr_store(struct kobject *kobj, struct attribute *attr,const char *buf, size_t count){ ssize_t len = 0; my_attribute_t *a = container_of(attr, my_attribute_t, attr); if (a->store) { len = a->store(buf, count); } return len;}void my_attr_release(struct kobject *ko){ my_info_t *a = container_of(ko, my_info_t, kobj); kfree(a); my_info = NULL;}void my_sysfs_add(struct kobject* kobj){ int i, n, ret; n = ARRAY_SIZE(my_sysfs_attrs) - 1; for (i=0; i<n; i++) { if (my_sysfs_attrs[i]){ ret = sysfs_create_file(kobj, my_sysfs_attrs[i]); if(ret < 0) printk("sysfs is not created\n"); } }}void my_sysfs_remove(struct kobject* kobj){ int i, n; n = ARRAY_SIZE(my_sysfs_attrs) - 1; for (i=0; i<n; i++) { if (my_sysfs_attrs[i]) sysfs_remove_file(kobj, my_sysfs_attrs[i]); }}void my_sysfs_unregister(void){ // remove all files in sysfs arch my_sysfs_remove(&my_info->kobj); // deref the kobject kobject_del(&my_info->kobj); kobject_put(&my_info->kobj); while (my_info) { schedule_timeout(HZ/2); } return;}int32_t my_sysfs_register(void){ int32_t error; my_info = kmalloc(sizeof(my_info_t), GFP_KERNEL); if (!my_info) { return -ENOMEM; } memset(my_info, 0, sizeof(my_info_t)); // init the kobject kobject_init(&my_info->kobj); my_info->kobj.ktype = &my_ktype; // generate dir & attr_file error = kobject_set_name(&my_info->kobj, MY_SYSFS_NAME); if (!error) { error = kobject_add(&my_info->kobj); if (!error) { my_sysfs_add(&my_info->kobj); } } if (error) { kfree(my_info); } return error;}
|