• class_create(),device_create()使用


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

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

    /* This is a #define to keep the compiler from merging different
     * instances of the __key variable */
    #define class_create(owner, name)		
    ({						
      static struct lock_class_key __key;	
      __class_create(owner, name, &__key);	
    })
    
    /**
     * class_create - create a struct class structure
     * @owner: pointer to the module that is to "own" this struct class
     * @name: pointer to a string for the name of this class.
     * @key: the lock_class_key for this class; used by mutex lock debugging
     *
     * This is used to create a struct class pointer that can then be used
     * in calls to device_create().
     *
     * Returns &struct class pointer on success, or ERR_PTR() on error.
     *
     * Note, the pointer created here is to be destroyed when finished by
     * making a call to class_destroy().
     */
    struct class *__class_create(struct module *owner, const char *name,
               struct lock_class_key *key)

    关键的一句是:

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

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

    官方说明:
    /**
     * device_create - creates a device and registers it with sysfs
     * @class: pointer to the struct class that this device should be registered to
     * @parent: pointer to the parent struct device of this new device, if any
     * @devt: the dev_t for the char device to be added
     * @drvdata: the data to be added to the device for callbacks
     * @fmt: string for the device's name
     *
     * This function can be used by char device classes.  A struct device
     * will be created in sysfs, registered to the specified class.
     *
     * A "dev" file will be created, showing the dev_t for the device, if
     * the dev_t is not 0,0.
     * If a pointer to a parent struct device is passed in, the newly created
     * struct device will be a child of that device in sysfs.
     * The pointer to the struct device will be returned from the call.
     * Any further sysfs files that might be required can be created using this
     * pointer.
     *
     * Returns &struct device pointer on success, or ERR_PTR() on error.
     *
     * Note: the struct class passed to this function must have previously
     * been created with a call to class_create().
     */
    struct device *device_create(struct class *class, struct device *parent,
               dev_t devt, void *drvdata, const char *fmt, ...)

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

    官方说明:
    /**
     * device_create_file - create sysfs attribute file for device.
     * @dev: device.
     * @attr: device attribute descriptor.
     */
    int device_create_file(struct device *dev,
               const struct device_attribute *attr)

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

    static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);  
    
    /*读取寄存器val的值到缓冲区buf中,内部使用*/  
    static ssize_t __hello_get_val(struct xxx_dev* dev, char* buf) {  
      int val = 0;		  
      
      /*同步访问*/  
      if(down_interruptible(&(dev->sem))) {				  
        return -ERESTARTSYS;		  
      }		  
      
      val = dev->val;		  
      up(&(dev->sem));		  
      
      return snprintf(buf, PAGE_SIZE, "%d/n", val);  
    }  
      
    /*把缓冲区buf的值写到设备寄存器val中去,内部使用*/  
    static ssize_t __hello_set_val(struct xxx_dev* dev, const char* buf, size_t count) {  
      int val = 0;		  
      
      /*将字符串转换成数字*/		  
      val = simple_strtol(buf, NULL, 10);		  
      
      /*同步访问*/		  
      if(down_interruptible(&(dev->sem))) {				  
        return -ERESTARTSYS;		  
      }		  
      
      dev->val = val;		  
      up(&(dev->sem));  
      
      return count;  
    }  
      
    /*读取设备属性val*/  
    static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {  
      struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);		  
      
      return __hello_get_val(hdev, buf);  
    }  
      
    /*写设备属性val*/  
    static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {   
      struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);	
        
      return __hello_set_val(hdev, buf, count);  
    } 
    
    /*模块加载方法*/  
    static int __init xxx_init(void){   
      ... 
      
      /*在/sys/class/xxx/xxx目录下创建属性文件val*/  
      err = device_create_file(temp, &dev_attr_val);  
      if(err < 0) {  
        printk(KERN_ALERT"Failed to create attribute val.");				  
        goto destroy_device;  
      }
      
      ...
    }

    b.在用户空间读取属性

    ...
    read(dev->fd, val, sizeof(*val));
    ...
    write(dev->fd, &val, sizeof(val));
    ...

    四、使用示例

    /*在/sys/class/目录下创建设备类别目录xxx*/ 
      g_vircdev_class = class_create(THIS_MODULE, VIRCDEV_CLASS_NAME);
      if(IS_ERR(g_vircdev_class)) {  
        err = PTR_ERR(g_vircdev_class);  
        printk(KERN_ALERT "Failed to create class.
    ");  
        goto CLASS_CREATE_ERR;  
      }
      
      /*在/dev/目录和/sys/class/xxx目录下分别创建设备文件xxx*/
      dev = device_create(g_vircdev_class, NULL, devt, NULL, VIRCDEV_DEVICE_NAME);
      if(IS_ERR(dev)) {  
        err = PTR_ERR(dev);  
        printk(KERN_ALERT "Failed to create device.
    ");  
        goto DEVICE_CREATE_ERR;  
      }
      
      /*在/sys/class/xxx/xxx目录下创建属性文件val*/ 
      err = device_create_file(dev, attr);  
      if(err < 0) {  
        printk(KERN_ALERT"Failed to create attribute file.");				  
        goto DEVICE_CREATE_FILE_ERR;  
      }
  • 相关阅读:
    [golang]text/template模板
    [golang]Go内嵌静态资源go-bindata的安装及使用
    GoCN每日新闻(2019-09-23)
    spring mvc中获取请求URL
    HBuilder搭配逍遥Android模拟器进行开发
    python 数据结构
    JDK8+Tomcat8配置https【转】
    JFinal的使用
    RESTful API 设计指南【转】
    jQuery验证控件jquery.validate.js的使用介绍
  • 原文地址:https://www.cnblogs.com/oracleloyal/p/5359509.html
Copyright © 2020-2023  润新知