Linux设备文件的创建
/************************************************************************************
*本文为个人学习记录,如有错误,欢迎指正。
* http://www.cnblogs.com/chen-farsight/p/6154941.html
* https://blog.csdn.net/yueqian_scut/article/details/46771595
************************************************************************************/
1. 创建设备文件的两种方式
(1)手动创建:mknod命令
在驱动程序insmod成功之后,通过mknod命令手动创建设备文件至/dev目录下:mknod /dev/xxx c 主设备号 次设备号。("c"表示字符设备、"b"表示块设备、"p"表示网络设备)
(2)自动创建设备文件:mdev
在设备驱动注册到系统后,调用class_create为该设备在/sys/class目录下创建一个设备类,再调用device_create函数为每个设备创建对应的设备,并通过uevent机制调用mdev(嵌入式linux由busybox提供)来调用mknod创建设备文件至/dev目录下。
2. 自动创建设备文件过程分析
2.1 相关数据结构
struct class和struct device则通过sysfs向用户层提供信息。
class_private是class的私有结构,class通过class_private注册到系统中;device_private是device的私有结构,device通过device_private注册到系统中。注册到系统中也是将相应的数据结构加入到系统已经存在的链表中,但是这些链接的细节并不希望暴露给用户,也没有必要暴露出来,所以才有private的结构。
//所在文件/kernel/include/linux/device.h //设备类 struct class { const char *name; //设备类名称 struct module *owner;//创建设备类的module struct class_attribute *class_attrs;//设备类属性 struct device_attribute *dev_attrs;//设备属性 struct kobject *dev_kobj;//kobject再sysfs中代表一个目录 ..................... struct class_private *p;//设备类得以注册到系统的连接件 }; //drivers/base/base.h struct class_private { struct klist class_devices;//设备类包含的设备(kobject) .................................. struct class *class;//指向设备类数据结构,即要创建的本级目录信息 };
//所在文件/kernel/include/linux/device.h struct device { struct device *parent; //sysfs/devices/中的父设备 struct device_private *p; //设备得以注册到系统的连接件 struct kobject kobj; //设备目录 const char *init_name; //设备名称 struct bus_type *bus; //设备所属总线 struct device_driver *driver; //设备使用的驱动 struct klist_node knode_class;//连接到设备类的klist struct class *class; //所属设备类 ..................... }; //所在文件/kernel/drivers/base/base.h struct device_private { struct klist klist_children; //连接子设备 struct klist_node knode_parent; //加入到父设备链表 struct klist_node knode_driver; //加入到驱动的设备链表 struct klist_node knode_bus; //加入到总线的链表 struct device *device; //对应设备结构 };
2.2 创建过程
step1:调用class_create函数在/sys/class目录下创建一个设备类。
/* 功能:在/sys/class目录下创建一个目录,目录名是name指定的 参数: struct module *owner - THIS_MODULE const char *name - 设备名 返回值: 成功:class指针 失败: - bool IS_ERR(const void *ptr) 判断是否出错 long PTR_ERR(const void *ptr) 转换错误码 */ struct class *class_create(struct module *owner, const char *name);
step2:调用device_create函数在step1创建的设备类目录下创建具体的设备目录和设备属性文件。
/* 功能: 在class指针指向的目录下再创建一个目录,目录名由const char *fmt, ...指出、并导出设备信息(dev_t) 参数: struct class *cls - class指针 struct device *parent - 父对象,NULL dev_t devt - 设备号 void *drvdata - 驱动私有数据 const char *fmt, ... - fmt是目录名字符串格式,...就是不定参数 返回值: 成功 - device指针 失败 - bool IS_ERR(const void *ptr) 判断是否出错 long PTR_ERR(const void *ptr) 转换错误码 */ struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
step3:在/dev创建设备文件(系统自动进行)
step1、step2都是在sysfs文件系统中创建目录或者文件,而应用程序访问的设备文件则需要创建在/dev/目录下。该项工作由mdev完成(需保证根文件系统支持mdev,由busybox配置)。
2.2 注销过程
step1:删除设备类目录下的设备
/* 功能:删除device_create创建的目录 参数: struct class *cls - class指针 dev_t devt - 设备号 */ void device_destroy(struct class *cls, dev_t devt);
step2:删除/sys/class目录下的设备类
/* 功能:删除class指针指向的目录 参数: struct class *cls - class指针 */ void class_destroy(struct class *cls);