字符设备驱动程序的另一种注册方法

一、 字符设备驱动程序框架请添加图片描述

编写驱动程序的套路:

  • 确定主设备号,也可以让内核分配
  • 定义自己的file_operations结构体
  • 实现对应的drv_open/drv_read/drv_write等函数,填入file_operations结构体
  • 把file_operations结构体告诉内核:register_chrdev
  • 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
  • 有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用unregister_chrdev
  • 其他完善:提供设备信息,自动创建设备节点:class_create, device_create

二、新的注册方法

  • 注册字符设备区域
    • 有主设备号:register_chrdev_region
    • 无主设备号:alloc_chrdev_region
  • 分配/设置/注册cdev
    • cdev_alloc
    • cdev_init
    • cdev_add
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>


static int major = 0;
static char kernel_buff[1024];
static struct class *hello_class;
static struct cdev hello_cdev;

#define MIN(a, b) (a < b ? a : b)

static int hello_drv_open(struct inode *node, struct file *file)
{
    
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;	
}

static ssize_t hello_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    
    
	int ret;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	ret = copy_to_user(buf, kernel_buff, MIN(1024, size));
	return ret;
}

static ssize_t hello_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    
    
	int ret;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	ret = copy_from_user(kernel_buff, buf, MIN(1024, size));
	return ret;
}

static int hello_drv_release(struct inode *node, struct file *file)
{
    
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;	
}

static struct file_operations hello_drv = {
    
    
	.owner   = THIS_MODULE,
	.open    = hello_drv_open,
	.read    = hello_drv_read,
	.write   = hello_drv_write,
	.release = hello_drv_release
};

static int __init hello_init(void)
{
    
    
	int err;
	dev_t devid;

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	//major = register_chrdev(0, "hello", &hello_drv);
	err = alloc_chrdev_region(&devid, 0, 1, "hello");	
	major = MAJOR(devid);
	if(err < 0) {
    
    
		printk("register chrdev failed: %d\n", err);
		return -1;
	}
	cdev_init(&hello_cdev, &hello_drv);
	cdev_add(&hello_cdev, devid, 1);
	
	hello_class = class_create(THIS_MODULE, "hello_class");
	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");	/* /dev/hello */

	return 0;
}

static void __exit hello_exit(void)
{
    
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destroy(hello_class, MKDEV(major, 0));
	class_destroy(hello_class);
//	unregister_chrdev(major, "hello");
	cdev_del(&hello_cdev);
	unregister_chrdev_region(MKDEV(major, 0), 1);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

三、上机实验

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
make

root@npi:~/test# insmod hello_drv.ko 
root@npi:~/test# ./hello_drv_test 
Usage: ./hello_drv_test -w <string> 
       ./hello_drv_test -r 
root@npi:~/test# ./hello_drv_test -r hello
APP read : 
root@npi:~/test# ./hello_drv_test -w hello
root@npi:~/test# ./hello_drv_test -r
APP read : hello
root@npi:~/test# ls /dev/hello -lh
crw------- 1 root root 244, 0 Mar 17 14:16 /dev/hello
root@npi:~/test# mknod /dev/hello c 244 1
mknod: /dev/hello: File exists
root@npi:~/test# mknod /dev/hello c 244 1
mknod: /dev/hello: File exists
root@npi:~/test# rm /dev/hello 
root@npi:~/test# mknod /dev/hello c 244 1
root@npi:~/test# ./hello_drv_test -r
can not open file /dev/hello

此时如果删除/dev/hello节点,然后手动创建一个244 1的节点,用测试程序就无法打开。
因为驱动程序只针对次设备号为0的,并不支持次设备号1

猜你喜欢

转载自blog.csdn.net/ch122633/article/details/129620169