udev
udev根据sysfs系统提供的设备信息来实现对/dev目录下设备节点的动态管理,包括设备节点的创建和删除。
因此想要系统可以自动创建设备节点就是要利用udev,就是在sysfs系统中注册设备信息。
sysfs
sys/devices
安装模块之后会在sysfs/device下创建对应的设备名同名文件夹,通过检测这个文件夹来自动创建设备节点。
book@100ask:/sys/devices/virtual/input/mice$ ls
dev power subsystem uevent
其中也储存了设备的信息。
cat uevent
MAJOR=13
MINOR=63
DEVNAME=input/mice
sysfs/devices目录与/dev目录下数据相互对应的
book@100ask:/sys/devices/virtual/input/mice$ ls /dev/input/mice -l
crw-rw---- 1 root input 13, 63 Jun 11 17:32 /dev/input/mice
sys/class
sysfs是管理设备的一种虚拟文件系统,挂载在/sys目录下。每一个设备在sysfs目录中都有唯一对应的目录,可以从用户层访问。
将所有的设备分类统一,比如输入设备都在class/input目录下。
sys/class/XXX/dev:设备号信息
sys/class/XXX/uevent:完整的设备信息
udev根据sysfs目录中的内容,在/dev目录下创建相应的设备节点。
class_creat 创建一个类
/* 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); \
})
将会在 sysfs/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, ...)
{
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
va_end(vargs);
return dev;
}
parent该设备的父类,或者NULL;drvdata设备回调函数值,或者NULL;fmt const char *类型的可变参数,设备名(节点)。
device_create就是在sysfs系统下创建设备节点。
当模块被加载时:
1、在sys/devices中创建设备同名XXX目录;并注册到特定的class(sysfs/class)。
2、在sys/devices/XXX下创建dev目录(设备节点),存入设备号信息。
3、udev检测到sysfs下的设备更新,自动去/dev下创建设备节点。
关于参数列表中的 … 三个圆点
“变参数函数”,头文件<stdarg.h>
这里提供了一个特殊类型va_list。在每个变参数函数的函数体里必须定义一个va_list类型的局部变量,它将成为访问由三个圆点所代表的实际参数的媒介。在能够用vap访问实际参数之前,必须首先用“函数”va_start做这个变量初始化。函数va_start的类型特征可以大致描述为:
va_start(va_list vap, 最后一个普通参数)
实际上va_start通常并不是函数,而是用宏定义实现的一种功能。在函数sum里对vap初始化的语句应当写为:
va_start(vap, n);
在完成这个初始化之后,我们就可以通过另一个宏va_arg访问函数调用的各个实际参数了。
但是所有参数类型是固定的。
注册流程
1、定义
static struct lock_class_key *hello_class;
static struct file_operations hello_drv = {}
2、注册
1、注册设备名设备号,得到设备号
register_chrdev(major, "hello", &hello_drv);
2、创建设备类
hello_class = class_create(THIS_MODULE, "hello_class");
3、创建设备==**节点**==并注册到sysfs/devices下。
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");
3、出错返回和销毁
if(IS_ERR(error)){
printk("......");
/*提取错误码*/
ret = PTR_ERR(error);
goto A
}
A:
device_destroy(hello_class, MKDEV(major, minor));
class_destroy(hello_class);
/* 在卸载时主设备号不能为0 */
unregister_chrdev(major, "hello");
销毁时后创建的先销毁,先创建的后销毁。
1、如果不是自己创建的类,就不要销毁了。
2、在每一个可能出错地方都需要记得销毁。
/proc/devices 中呈现的是已经分配好的设备号,但不代表该设备号对应的设备节点已经被创建。插入驱动后都可以根据/proc/devices文件中的信息来创建设备节点。
device_creat()函数用于在sysfs/class中创建dev文件,以供用户空间使用;是在sysfs系统中创建设备节点。
udev根据sysfs目录中的内容,在/dev目录下创建相应的设备节点。