第一个驱动hello_drv的详解

一、构建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)

扫描二维码关注公众号,回复: 11387874 查看本文章

​ 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。

猜你喜欢

转载自blog.csdn.net/weixin_46704960/article/details/106267954
今日推荐