自动创建设备节点
(一)创建设备节点的机制
1. mknod
将驱动编译到内核中,在内核启动时驱动自动被安装执行
2.devfs(2.4内核)
3. udev(2.6内核至今)
- 注:hotplug — 热插拔
(二)API
1. 向上提交目录
#include <linux/device.h>
struct class * class_create(owner, name)
功能:向上提交目录
参数:
@owner:THIS_MODULE 这个宏和模块安装卸载相关,并且会记录模块的引用计数值。
@name:目录名
返回值:成功返回结构体指针,失败返回错误码指针
- 补:
- 通过
IS_ERR(cls)
来判断是否失败。该宏定义在在cls是错误码指针时返回真,否则为假 - 当cls是错误码指针时,可以通过
PTR_ERR(cls)
来获得失败返回的错误码
2. 销毁目录
#include <linux/device.h>
void class_destroy(struct class *cls)
功能:销毁向上提交目录后产生的结构体
参数:
@cls:结构体指针
返回值:无
3. 向上提交创建节点的信息
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt,...)
功能:向上提交创建节点的信息
参数:
@class:指向目录的句柄
@parent:填写为NULL
@devt:设备号 (241,0)=>(241<<20|0)
MKDEV(major,minor) //将主和次设备号合成设备号
MAJOR(devno); //从设备号中获取主设备号
MINOR(devno); //从设备号中获取次设备号
@drvdata:驱动的私有数据,一般填写为NULL。
@fmt,...:创建节点的名字 "myled%d",i
返回值:成功返回结构体指针,失败返回错误码指针
- 注:
- MKDEV(ma,mi) 将主次设备号拼接成设备号
- MAJOR(devno) 从设备号中获取主设备号
- MINOR(devno) 从设备号中获取次设备号
4. 销毁节点的信息
void device_destroy(struct class *class, dev_t devt)
功能:销毁节点的信息
参数:
@class:指向目录的句柄
@devt:设备号 (241,0)=>(241<<20|0)
返回值:无
5. IS_ERR(cls)
的实现机制
(三)使用示例
功能需求:在上一篇驱动的基础上加入自动创建设备节点,而无需使用mknod来手动创建
需求分析:
设备文件是需要在应用层的open函数就需要使用,因此在驱动中自动创建节点就必须要在mydev_open函数之前实现,因此在mydev_init函数中进行自动创建设备节点,在mydev_exit函数中进行销毁创建的设备节点
代码实现(此处只展示有修改的代码部分):
LED.c
static int __init myioctl_init(void){
//入口注册设备
major=register_chrdev(0,CHRNAME,&myfops); //第一个参数为0,表示由系统分配主设备号,此时返回值就是系统分配的主设备号
if(major < 0){//说明出错,返回了错误码,错误码均为负数
pr_err("register_chrdev error:%d\n",major);
return major; //失败返回错误码
}
printk("major=%d\n",major);
//向上提交目录
mycls = class_create(THIS_MODULE,"class_name");
if(IS_ERR(mycls)){//成功返回结构体指针,失败返回错误码指针
//为真则说明是错误码指针
pr_err("class create error:%ld\n",PTR_ERR(mycls));
return PTR_ERR(mycls); //出错返回错误码
}
//向上提交节点信息
mydev = device_create(mycls,NULL,MKDEV(major,0),NULL,"myioctl");
if(IS_ERR(mydev)){//成功返回结构体指针,失败返回错误码指针
//为真则说明是错误码指针
pr_err("class create error:%ld\n",PTR_ERR(mydev));
return PTR_ERR(mydev); //出错返回错误码
}
return 0; //成功返回0
}
static void __exit myioctl_exit(void){
//销毁节点信息
device_destroy(mycls,MKDEV(major,0));
//销毁目录信息
class_destroy(mycls);
//出口销毁设备
unregister_chrdev(major,CHRNAME);
}