开始写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.\n");
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.\n");
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;
}

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. mysql 中浮点型与定点型记录

    为了能够引起大家的重视,在介绍浮点数与定点数以前先让大家看一个例子: mysql> CREATE TABLE test (c1 float(10,2),c2 decimal(10,2)); Qu ...

  2. Spring Data Jpa 详解 (配置篇)

    前言: JPA全称Java Persistence API,即Java持久化API,它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据,结合其他ORM的使用,能达到简化开发 ...

  3. ZOJ 1586 QS Network (最小生成树)

    QS Network Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Sta ...

  4. XAML设计器卡死

    在生成工程时,存在这样一个记录: “未能找到一个或多个间接引用的程序集.分析不需要这些程序集.但是,如果没有这些程序集,分析结果可能不完整”. 表现形式既不是错误,可也不是警告.之所以关注到这个问题, ...

  5. Oracle数据库作业-3 查询

    1. 查询Student表中的所有记录的Sname.Ssex和Class列.

  6. 【转】使用nmon监控suse或linux操作系统

    目的:使用nmon监控操作系统的内存,CPU等症状 nmon介绍:nmon 工具可以为AIX和Linux性能专家提供监视和分析性能数据的功能,其中包括CPU,内存,IO,free空间,页面空间页面速度 ...

  7. MySQL防注入[待续]

    1.将输入的参数变成整数 $id = isset[$_GET['tid']]?$_GET['tid']+0:0; 可以防止:"*.php?tid=3 or 1"这样的语句.

  8. HDU4272LianLianKan(dfs)

    Problem Description I like playing game with my friend, although sometimes looks pretty naive. Today ...

  9. VHDL MOD和REM(转)

    mod(取模)and rem(取余) VHDL has mod and rem. They return the same value if both arguments are positive. ...

  10. Cocos2d-x移植到WindowsPhone8移植问题-框架rapidjson移植问题

    Cocos2d-x 3.0提供了JSON框架rapidjson可以在Windows Phone 8平台使用,如果没有进行必要的配置,在编译的时候会报错,document.h等头文件找不到的错误.在Wi ...