一、构建file_operations
static struct file_operations hello_drv = {
.owner = THIS_MODULE,
.open = hello_drv_open,
.release = hello_drv_close,
.read = hello_drv_read,
.write = hello_drv_write,
};
*宏THIS_MODULE,它的定义如下是
*define THIS_MODULE (&this_module)
*this_module是一个struct module变量,代表当前模块
详解请参考https://blog.csdn.net/a954423389/article/details/6101369
二、定义file_operations结构体里的函数
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_to_user(buf,kernel_buf,MIN(1024,size));//copy_to_user(void *to, const void *from, unsigned long n)
return 0;
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(kernel_buf, buf,MIN(1024,size));//copy_from_user(void *to, const void *from, unsigned long n);
return 0;
}
static int hello_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int hello_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
*这些函数的输入参数和输出可以参考fs.h文件里的file_operations结构体里的成员.
*copy_to_user(void *to, const void *from, unsigned long n)
to:目标地址(用户空间)
from:源地址(内核空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
*copy_from_user(void *to, const void *from, unsigned long n)
to:目标地址(内核空间)
from:源地址(用户空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
详解请参考https://blog.csdn.net/xiaodingqq/article/details/80150347
三、初始化
static int __init hello_init(void)
{
int err;
/* /dev/hello */
major = register_chrdev(0, "hello", &hello_drv);
hello_class = class_create(THIS_MODULE, "hello_class");//创建一个类,使mdev可以在"/dev/"目录下 面建立设备节点
err = PTR_ERR(hello_class);
if (IS_ERR(hello_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "hello");
return -1;
}
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");//创建设备节点,设备节点名为hello
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
module_init(hello_init);//insmod
*int register_chrdev(unsigned int, const char *,struct file_operations *)
第一个参数为0时候动态注册,非零时候静态注册。注册设备号(file_operations结构体),并返回主设备号。
第二个参数是设备名
第三个参数file_operations,如果是动态分配的,则函数返回分配的主设备号。
详解请参考https://blog.csdn.net/welbell_uplooking/article/details/83654312
*struct class *class_create(struct module *owner, const char *name)
注册一个类,使mdev可以在"/dev/"目录下 面建立设备节点
owner:指向要“拥有”这个结构类的模块的指针
name:指向该类名称的字符串的指针
*struct device *device_create(struct class *class, struct device *parent,dev_t devt,
void drvdata, const char *fmt, …)
class:指向这个设备应该注册的结构类的指针
parent:指向这个新设备的父结构设备的指针(如果有的话)
devt:要添加的char设备的dev_t
drvdata:要添加到设备进行回调的数据
fmt:设备名称的字符串
详解请参考https://www.cnblogs.com/ganrui/p/3804521.html
*static inline long __must_check PTR_ERR(__force const void *ptr)
{
return (long) ptr;
}
强制转换类型,并返回信息
*static inline bool __must_check IS_ERR(__force const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
用来判断返回的指针是否有错
详解请参考https://blog.csdn.net/adaptiver/article/details/40145313
四、注销
static void __exit hello_exit(void)
{
device_destroy(hello_class, MKDEV(major, 0));
class_destroy(hello_class);
unregister_chrdev(major, "hello");
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
}
module_exit(hello_exit);//rmmod
与初始化一一对应,就不过多解释了。
MODULE_LICENSE("GPL");
遵循GPL。