什么是设备节点
前面我们讲过,在驱动中实现file_operations结构体并注册进内核时,我们使用该驱动的时候自己手动用mknod手动创建的设备节点,这个设备节点是用来被应用程序打开和操作的,是应用和驱动交互不可缺少的。
怎么让驱动自动创建节点
需要使用到两个函数,一是class_create()函数,还有一个是device_create()函数。那么他们有什么作用呢?请看:
1、class_create(),可以理解为该函数会在/dev/下创建一个目录,如:input目录、bus目录等。
2、device_create(),可以理解为在class_create()创建的目录下创建一个设备节点。所以在device_create()就可以传入class_create()创建的类。
贴出函数原型供大家参考:
struct class *class_create (struct module *owner, const char *name);
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
顺便贴出销毁设备和类的函数原型:
void device_destroy(struct class *class, dev_t devt);
void class_destroy(struct class *cls);
具体代码
该代码在上节linux应用与驱动的交互方式之file_operations结构体代码的基础上增加了自动创建设备节点的方法,需要注意的是,该代码并未控制实际的硬件,只是一个框架,可以加上自己的代码实现自己的功能:
#include <linux/ide.h>
#include <linux/module.h>
#define XXX_MAJOR 200 /* 主设备号 */
#define XXX_NAME "xxx_test" /* 设备名 */
struct class * xxx_class; /* 类 */
struct device * xxx_device; /* 设备 */
static int xxx_open(struct inode *inode, struct file *filp)
{
//通常返回:0 成功;其他 失败
return 0;
}
static ssize_t xxx_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
//通常返回:读取的字节数;小于0,表示读取失败
return 0;
}
static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
//通常返回:写入的字节数;小于0,表示写入失败
return 0;
}
static int xxx_release(struct inode *inode, struct file *filp)
{
//通常返回:0 成功;其他 失败
return 0;
}
//本xxx_fops只列出了部分常用的操作
static const struct file_operations xxx_fops = {
//owner 拥有该结构体的模块的指针,一般设置为 THIS_MODULE
.owner = THIS_MODULE,
//open 函数用于打开设备文件,用户程序打开设备文件会得到一个设备描述符,并执行驱动指定的open函数(不管驱动有无open函数,用户使用都需要打开)
.open = xxx_open,
//read 函数用于读取设备文件,应用执行read时会调用该函数
.read = xxx_read,
//write 函数用于向设备文件写入(发送)数据,应用执行write时会调用该函数
.write = xxx_write,
//release 函数用于释放(关闭)设备文件,与应用程序中的 close 函数对应
.release = xxx_release,
};
//模块初始化函数,在模块装载的时候调用
static int __init xxx_init(void)
{
int ret = 0;
//主设备号为0,自动分配设备号,返回值是分配的设备号
ret = register_chrdev(XXX_MAJOR, XXX_NAME, &xxx_fops);
//返回值为负数,注册失败
if(ret < 0)
{
return -1;
}
//创建类,在/dev目录下生产xxx目录
xxx_class = class_create(THIS_MODULE, "xxx");
//创建设备节点,在/dev/xxx/目录下生成xxx_driver设备文件
xxx_device = device_create(xxx_class, NULL, XXX_MAJOR, NULL, "xxx_driver");
return 0;
}
//模块退出函数,在模块卸载的时候调用
static void __exit xxx_exit(void)
{
//注销字符设备驱动
unregister_chrdev(XXX_MAJOR, XXX_NAME);
//销毁设备节点,会删除/dev/xxx/目录下的xxx_driver设备文件
device_destroy(xxx_class, XXX_MAJOR);
//销毁类,会删除/dev目录下的xxx目录
class_destroy(xxx_class);
}
//向内核表明初始化函数,在模块装载的时候调用
module_init(xxx_init);
//向内核表明退出函数,在模块卸载的时候调用
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiaoShuATao");
注:作者水平有限,如有错误,请大家及时指出,我会第一时间修改,谢谢大家了。
版权说明:可自由转载使用,转载请注明出处。