简介

操作系统将虚拟内存分为内核空间和用户空间。内核空间严格保留用于运行内核,内核扩展和大多数设备驱动程序。相反,用户空间是所有用户模式应用程序都在其中工作的存储区,并且可以在必要时将该存储区换出。
在用户空间和内核空间之间进行通信的方法有很多

  1. IOCTL
  2. Procfs
  3. Sysfs
  4. Configfs
  5. Debugfs
  6. Sysctl
  7. UDP Sockets
  8. Netlink Sockets

在这里我们讨论Sysfs
Sysfs是内核导出的虚拟文件系统,类似于。Sysfs中的文件包含有关设备和驱动程序的信息。Sysfs中的某些文件甚至是可写的,用于配置和控制连接到系统的设备。Sysfs始终安装在上 。 /proc``/sys
Sysfs是将系统信息从内核空间导出到特定设备的用户空间的常用方法。sysfs与内核的设备驱动程序模型绑定在一起。procfs用于导出特定于进程的信息,而debugfs用于由开发人员导出调试信息。
在了解Sysfs,我们需要先来了解Kernel Objects.

Kernel Objects

Sysfs的核心模块是kobject, 你可以将kobject看作绑定内核和Sysfs之间的胶水。

  1. # include/linux/kobject.h
  2. struct kobject {
  3. const char *name;
  4. struct list_head entry;
  5. struct kobject *parent;
  6. struct kset *kset;
  7. struct kobj_type *ktype;
  8. struct kernfs_node *sd; /* sysfs directory entry */
  9. struct kref kref;
  10. ...
  11. }
  12. struct kobject
  13. |– name (Name of the kobject. Current kobject is created with this name in sysfs.)
  14. |– parent (This is kobjects parent. When we create a directory in sysfs for current kobject, it will create under this parent directory)
  15. |– ktype (the type associated with a kobject)
  16. |– kset (a group of kobjects all of which are embedded in structures of the same type)
  17. |– sd (points to a sysfs_dirent structure that represents this kobject in sysfs.)
  18. |– kref (provides reference counting)

创建以及使用sysfs

  1. /sys中创建目录
  2. 创建sysfs文件
    1. struct kobject * kobject_create_and_add ( const char * name, struct kobject * parent);
    如果传递kernel_kobj 给第二个参数,它将在/ sys / kernel /下创建目录。如果传递firmware_kobj 第二个参数,它将在/ sys / firmware /下创建目录。如果传递fs_kobj 给第二个参数,它将在下创建目录**/sys/fs/**。如果传递NULL给第二个参数,它将在/ sys /下创建目录。该函数动态创建一个kobject结构,并将其注册到sysfs中。如果无法创建kobject,则将返回NULL。完成此结构后,调用 kobject_put 和该结构将在不再使用时动态释放。 ```c struct kobject *kobj_ref;

/Creating a directory in /sys/kernel/ / kobj_ref = kobject_create_and_add(“etx_sysfs”,kernel_kobj); //sys/kernel/etx_sysfs

/Freeing Kobj/ kobject_put(kobj_ref);

  1. <a name="JUDGC"></a>
  2. ## 创建Sysfs文件<br />
  3. 上面我们知道了怎么创建sys下的目录。现在我们需要创建sysfs文件了。<br />该文件用于通过sysfs与用户空间和内核空间进行交互。因此,我们可以使用sysfs属性创建sysfs文件。
  4. <a name="6kapL"></a>
  5. ### 创建属性
  6. ```c
  7. struct kobj_attribute {
  8. struct attribute attr;
  9. ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
  10. ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
  11. };

我们可以使用__ATTR 宏定义来创建

  1. __ATTR(name, permission, show_ptr, store_ptr);

API

  1. int sysfs_create_file ( struct kobject * kobj, const struct attribute * attr);
  2. void sysfs_remove_file ( struct kobject * kobj, const struct attribute * attr);

代码

  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kdev_t.h>
  5. #include <linux/fs.h>
  6. #include <linux/cdev.h>
  7. #include <linux/device.h>
  8. #include <linux/slab.h> //kmalloc()
  9. #include <linux/uaccess.h> //copy_to/from_user()
  10. #include <linux/sysfs.h>
  11. #include <linux/kobject.h>
  12. volatile int etx_value = 0;
  13. dev_t dev = 0;
  14. static struct class *dev_class;
  15. static struct cdev etx_cdev;
  16. struct kobject *kobj_ref;
  17. static int __init etx_driver_init(void);
  18. static void __exit etx_driver_exit(void);
  19. /*************** Driver Fuctions **********************/
  20. static int etx_open(struct inode *inode, struct file *file);
  21. static int etx_release(struct inode *inode, struct file *file);
  22. static ssize_t etx_read(struct file *filp,
  23. char __user *buf, size_t len, loff_t *off);
  24. static ssize_t etx_write(struct file *filp,
  25. const char *buf, size_t len, loff_t *off);
  26. /*************** Sysfs Fuctions **********************/
  27. static ssize_t sysfs_show(struct kobject *kobj,
  28. struct kobj_attribute *attr, char *buf);
  29. static ssize_t sysfs_store(struct kobject *kobj,
  30. struct kobj_attribute *attr, const char *buf, size_t count);
  31. struct kobj_attribute etx_attr = __ATTR(etx_value, 0660, sysfs_show, sysfs_store);
  32. static struct file_operations fops =
  33. {
  34. .owner = THIS_MODULE,
  35. .read = etx_read,
  36. .write = etx_write,
  37. .open = etx_open,
  38. .release = etx_release,
  39. };
  40. static ssize_t sysfs_show(struct kobject *kobj,
  41. struct kobj_attribute *attr, char *buf)
  42. {
  43. printk(KERN_INFO "Sysfs - Read!!!\n");
  44. return sprintf(buf, "%d\n", etx_value);
  45. }
  46. static ssize_t sysfs_store(struct kobject *kobj,
  47. struct kobj_attribute *attr, const char *buf, size_t count)
  48. {
  49. printk(KERN_INFO "Sysfs - Write!!!\n");
  50. sscanf(buf, "%d\n", &etx_value);
  51. return count;
  52. }
  53. static int etx_open(struct inode *inode, struct file *file)
  54. {
  55. printk(KERN_INFO "Device File Opened...!!!\n");
  56. return 0;
  57. }
  58. static int etx_release(struct inode *inode, struct file *file)
  59. {
  60. printk(KERN_INFO "Device File Closed...!!!\n");
  61. return 0;
  62. }
  63. static ssize_t etx_read(struct file *filp,
  64. char __user *buf, size_t len, loff_t *off)
  65. {
  66. printk(KERN_INFO "Read function\n");
  67. return 0;
  68. }
  69. static ssize_t etx_write(struct file *filp,
  70. const char __user *buf, size_t len, loff_t *off)
  71. {
  72. printk(KERN_INFO "Write Function\n");
  73. return 0;
  74. }
  75. static int __init etx_driver_init(void)
  76. {
  77. /*Allocating Major number*/
  78. if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
  79. {
  80. printk(KERN_INFO "Cannot allocate major number\n");
  81. return -1;
  82. }
  83. printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
  84. /*Creating cdev structure*/
  85. cdev_init(&etx_cdev, &fops);
  86. /*Adding character device to the system*/
  87. if ((cdev_add(&etx_cdev, dev, 1)) < 0)
  88. {
  89. printk(KERN_INFO "Cannot add the device to the system\n");
  90. goto r_class;
  91. }
  92. /*Creating struct class*/
  93. if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
  94. {
  95. printk(KERN_INFO "Cannot create the struct class\n");
  96. goto r_class;
  97. }
  98. /*Creating device*/
  99. if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
  100. {
  101. printk(KERN_INFO "Cannot create the Device 1\n");
  102. goto r_device;
  103. }
  104. /*Creating a directory in /sys/kernel/ */
  105. kobj_ref = kobject_create_and_add("etx_sysfs", kernel_kobj);
  106. /*Creating sysfs file for etx_value*/
  107. if (sysfs_create_file(kobj_ref, &etx_attr.attr))
  108. {
  109. printk(KERN_INFO "Cannot create sysfs file......\n");
  110. goto r_sysfs;
  111. }
  112. printk(KERN_INFO "Device Driver Insert...Done!!!\n");
  113. return 0;
  114. r_sysfs:
  115. kobject_put(kobj_ref);
  116. sysfs_remove_file(kernel_kobj, &etx_attr.attr);
  117. r_device:
  118. class_destroy(dev_class);
  119. r_class:
  120. unregister_chrdev_region(dev, 1);
  121. cdev_del(&etx_cdev);
  122. return -1;
  123. }
  124. void __exit etx_driver_exit(void)
  125. {
  126. kobject_put(kobj_ref);
  127. sysfs_remove_file(kernel_kobj, &etx_attr.attr);
  128. device_destroy(dev_class, dev);
  129. class_destroy(dev_class);
  130. cdev_del(&etx_cdev);
  131. unregister_chrdev_region(dev, 1);
  132. printk(KERN_INFO "Device Driver Remove...Done!!!\n");
  133. }
  134. module_init(etx_driver_init);
  135. module_exit(etx_driver_exit);
  136. MODULE_LICENSE("GPL");
  137. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  138. MODULE_DESCRIPTION("A Sample Sysfs Demo");
  139. MODULE_VERSION("2:1.0");