开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点(包括ldd3中不少例子也是这样),实际上现在Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。
内核中定义了struct class结构体,顾名思义,一个struct
class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建
好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应
device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

此外,利用device_create_file函数可以在/sys/class/下创建对应的属性文件,从而通过对该文件的读写实现特定的数据操作。

  1. /* This is a #define to keep the compiler from merging different
  2. * instances of the __key variable */
  3. #define class_create(owner, name) \
  4. ({ \
  5. static struct lock_class_key __key; \
  6. __class_create(owner, name, &__key); \
  7. })
  8.  
  9. /**
  10. * class_create - create a struct class structure
  11. * @owner: pointer to the module that is to "own" this struct class
  12. * @name: pointer to a string for the name of this class.
  13. * @key: the lock_class_key for this class; used by mutex lock debugging
  14. *
  15. * This is used to create a struct class pointer that can then be used
  16. * in calls to device_create().
  17. *
  18. * Returns &struct class pointer on success, or ERR_PTR() on error.
  19. *
  20. * Note, the pointer created here is to be destroyed when finished by
  21. * making a call to class_destroy().
  22. */
  23. struct class *__class_create(struct module *owner, const char *name,
  24. struct lock_class_key *key)

关键的一句是:

  1. * This is used to create a struct class pointer that can then be used
  2. * in calls to device_create().
  3. -->这个函数用来创建一个struct class的结构体指针,这个指针可用作device_create()函数的参数。

也就是说,这个函数主要是在调用device_create()前使用,创建一个struct class类型的变量,并返回其指针。
二、device_create

  1. 官方说明:
  2. /**
  3. * device_create - creates a device and registers it with sysfs
  4. * @class: pointer to the struct class that this device should be registered to
  5. * @parent: pointer to the parent struct device of this new device, if any
  6. * @devt: the dev_t for the char device to be added
  7. * @drvdata: the data to be added to the device for callbacks
  8. * @fmt: string for the device's name
  9. *
  10. * This function can be used by char device classes. A struct device
  11. * will be created in sysfs, registered to the specified class.
  12. *
  13. * A "dev" file will be created, showing the dev_t for the device, if
  14. * the dev_t is not 0,0.
  15. * If a pointer to a parent struct device is passed in, the newly created
  16. * struct device will be a child of that device in sysfs.
  17. * The pointer to the struct device will be returned from the call.
  18. * Any further sysfs files that might be required can be created using this
  19. * pointer.
  20. *
  21. * Returns &struct device pointer on success, or ERR_PTR() on error.
  22. *
  23. * Note: the struct class passed to this function must have previously
  24. * been created with a call to class_create().
  25. */
  26. struct device *device_create(struct class *class, struct device *parent,
  27. dev_t devt, void *drvdata, const char *fmt, ...)

首先解释一下"sysfs":sysfs是linux2.6所提供的一种虚拟档案系统;在设备模型中,sysfs文件系统用来表示设备的结构,将设备的层 次结构形象的反应到用户空间中,从而可以通过修改sysfs中的文件属性来修改设备的属性值;sysfs被挂载到根目录下的"/sys"文件夹下。

  1. 官方说明:
  2. /**
  3. * device_create_file - create sysfs attribute file for device.
  4. * @dev: device.
  5. * @attr: device attribute descriptor.
  6. */
  7. int device_create_file(struct device *dev,
  8. const struct device_attribute *attr)

使用这个函数时要引用 device_create所返回的device*指针,作用是在/sys/class/下创建一个属性文件,从而通过对这个属性文件进行读写就能完成对应的数据操作。
如:
a.在驱动程序中使用 device_create_file创建属性文件

  1. static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);
  2.  
  3. /*读取寄存器val的值到缓冲区buf中,内部使用*/
  4. static ssize_t __hello_get_val(struct xxx_dev* dev, char* buf) {
  5. int val = 0;
  6.  
  7. /*同步访问*/
  8. if(down_interruptible(&(dev->sem))) {
  9. return -ERESTARTSYS;
  10. }
  11.  
  12. val = dev->val;
  13. up(&(dev->sem));
  14.  
  15. return snprintf(buf, PAGE_SIZE, "%d/n", val);
  16. }
  17.  
  18. /*把缓冲区buf的值写到设备寄存器val中去,内部使用*/
  19. static ssize_t __hello_set_val(struct xxx_dev* dev, const char* buf, size_t count) {
  20. int val = 0;
  21.  
  22. /*将字符串转换成数字*/
  23. val = simple_strtol(buf, NULL, 10);
  24.  
  25. /*同步访问*/
  26. if(down_interruptible(&(dev->sem))) {
  27. return -ERESTARTSYS;
  28. }
  29.  
  30. dev->val = val;
  31. up(&(dev->sem));
  32.  
  33. return count;
  34. }
  35.  
  36. /*读取设备属性val*/
  37. static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
  38. struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);
  39.  
  40. return __hello_get_val(hdev, buf);
  41. }
  42.  
  43. /*写设备属性val*/
  44. static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
  45. struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);
  46.  
  47. return __hello_set_val(hdev, buf, count);
  48. }
  49.  
  50. /*模块加载方法*/
  51. static int __init xxx_init(void){
  52. ...
  53.  
  54. /*在/sys/class/xxx/xxx目录下创建属性文件val*/
  55. err = device_create_file(temp, &dev_attr_val);
  56. if(err < 0) {
  57. printk(KERN_ALERT"Failed to create attribute val.");
  58. goto destroy_device;
  59. }
  60.  
  61. ...
  62. }

b.在用户空间读取属性

  1. ...
  2. read(dev->fd, val, sizeof(*val));
  3. ...
  4. write(dev->fd, &val, sizeof(val));
  5. ...

四、使用示例

  1. /*在/sys/class/目录下创建设备类别目录xxx*/
  2. g_vircdev_class = class_create(THIS_MODULE, VIRCDEV_CLASS_NAME);
  3. if(IS_ERR(g_vircdev_class)) {
  4. err = PTR_ERR(g_vircdev_class);
  5. printk(KERN_ALERT "Failed to create class.\n");
  6. goto CLASS_CREATE_ERR;
  7. }
  8.  
  9. /*在/dev/目录和/sys/class/xxx目录下分别创建设备文件xxx*/
  10. dev = device_create(g_vircdev_class, NULL, devt, NULL, VIRCDEV_DEVICE_NAME);
  11. if(IS_ERR(dev)) {
  12. err = PTR_ERR(dev);
  13. printk(KERN_ALERT "Failed to create device.\n");
  14. goto DEVICE_CREATE_ERR;
  15. }
  16.  
  17. /*在/sys/class/xxx/xxx目录下创建属性文件val*/
  18. err = device_create_file(dev, attr);
  19. if(err < 0) {
  20. printk(KERN_ALERT"Failed to create attribute file.");
  21. goto DEVICE_CREATE_FILE_ERR;
  22. }

class_create(),device_create()使用的更多相关文章

  1. class_create(),device_create自动创建设备文件结点

    class_create(),device_create自动创建设备文件结点 从linux 内核2.6的某个版本之后,devfs不复存在,udev成为devfs的替代.相比devfs,udev有很多优 ...

  2. 基于linux-2.6.35的class_create(),device_create解析

    基于linux-2.6.35的class_create(),device_create解析 作者:苗老师,华清远见嵌入式学院讲师. 从linux内核2.6的某个版本之后,devfs不复存在,udev成 ...

  3. class_create(),device_create自动创建设备文件结点【转】

    本文参考来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhenwenxian/archive/2010/03/28/5424434.aspx 本文转自:http://ww ...

  4. linux 字符设备驱动写法

    字符设备,块设备书 一.register_chrdev_region, register_chrdev, misc_register misc device(杂项设备) 在 Linux 内核的incl ...

  5. linux内核编程笔记【原创】

    以下为本人学习笔记,如有转载请注明出处,谢谢 DEFINE_MUTEX(buzzer_mutex); mutex_lock(&buzzer_mutex); mutex_unlock(& ...

  6. Tiny6410 LED字符设备驱动

    1.查看用户手册 led1.led2.led3.led4 连接的分别是 GPK4.GPK5.GPK6.GPK7 2.查询6410芯片手册 下面还需要3个步骤: 1.设置GPIO为OUTPUT. 将GP ...

  7. linux 驱动入门2

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境. http://www.cnblogs.com/nan-jing/articles/5775038.html 这里提到.有这么多牛人. ...

  8. 跟着内核学框架-从misc子系统到3+2+1设备识别驱动框架

    misc子系统在Linux中是一个非常简单的子系统,但是其清晰的框架结构非常适合用来研究设备识别模型.本文从misc子系统的使用出发,通过了解其机制来总结一套的设备识别的驱动框架,即使用使用同一个驱动 ...

  9. 【Linux高级驱动】linux设备驱动模型之平台设备驱动机制

    [1:引言: linux字符设备驱动的基本编程流程] 1.实现模块加载函数  a.申请主设备号    register_chrdev(major,name,file_operations);  b.创 ...

随机推荐

  1. php实现二路归并排序

    $arr = [9, 43, 12, 0, 87, 1]; function merge_sort(&$arr){ _merge_sort($arr, $arr, 0, count($arr) ...

  2. noi 97 积木游戏

    思路:黑书的例题 #include<map> #include<set> #include<cmath> #include<queue> #includ ...

  3. 【转】华为Java编程军规,每季度代码验收标准

    引言: 这个标准是衡量代码本身的缺陷,也是衡量一个研发人员本身的价值. 军规一:[避免在程序中使用魔鬼数字,必须用有意义的常量来标识.] 军规二:[明确方法的功能,一个方法仅完成一个功能.] 军规三: ...

  4. 【转】Oracle 中的 TO_DATE 和 TO_CHAR 函数 日期处理

    Oracle 中的 TO_DATE 和 TO_CHAR 函数oracle 中 TO_DATE 函数的时间格式,以 2008-09-10 23:45:56 为例 格式 说明 显示值 备注 Year(年) ...

  5. 在网页中制作icon图标

    用字体在网页中画icon图标 第一步:获取字体资源IconMoon网站https://icomoon.io iconMoon中有很多免费小图标可用,还能设置下载图标的使用属性(通过网站中设立的按钮pr ...

  6. json2.js 的使用

    转载自:http://www.cnblogs.com/youring2/archive/2013/03/01/2938850.html -------------------------------- ...

  7. hive操作语句使用详解

    #创建表人信息表  person(String name,int age) hive> create table person(name STRING,age INT)ROW FORMAT DE ...

  8. jQuery 删除或是清空某个HTML元素示例

    jQuery使用下面两个方法来删除或是清空某个HTML元素. remove() – 删除指定的元素(包括其子元素)empty() – 清空指定元素的子元素 1.remove()  <!DOCTY ...

  9. OC11_真正的代理

    // // ReceiveReportDelegate.h // OC11_真正的代理 // // Created by zhangxueming on 15/6/24. // Copyright ( ...

  10. 开放-封闭原则(OCP)

    对于僵化性的臭味,应用OCP原则之后,再进行同样的改动时,只需添加新代码,而不必改动已正常运行的代码. 扩展模块行为的方式通常是修改模块的Code,不允许修改的模块常常被认为是具有固定的行为. Ope ...