花了两天大概了解了sysfs,想着为下来了PCI总线与设备的驱动调试各方面做些准备.不过sysfs还真是有些复杂,或者说本来就只想&quot;吃快餐&quot;.本想用现有的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 &quot;test&quot;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, &quot;%d\n&quot;, ((data) ? 1 : 0));}ssize_t test_ata_store(const char *buf, size_t n){ int val; sscanf(buf, &quot;%d&quot;, &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){ ret = sysfs_create_file(kobj, my_sysfs_attrs); if(ret < 0) printk(&quot;sysfs is not created\n&quot;); } }}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) sysfs_remove_file(kobj, my_sysfs_attrs); }}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;} |
|