当前位置: 首页> 科技> 数码 > 字符设备驱动程序的两种注册方式

字符设备驱动程序的两种注册方式

时间:2025/9/16 10:31:32来源:https://blog.csdn.net/HRad7282/article/details/142343221 浏览次数:2次

第一种

int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
//功能:在内核中为某个设备号,申请主设备号,关联与此设备进行操作的方法。
参数1:major = 0  代表由系统自动分配一个设备号。major > 0值,代表静态指定使用某个主设备号(0-4096)
参数2:name: 要指定的设备的名称:"my_char_dev";
参数3:与设备号关联的操作设备的操作方法结构体:这个结构体有大量的与文件操作对应的回调函数的函数指针。
struct file_operations{//与文件read对应的函数指针ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//与write对应的函数指针ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);...//与open对应的函数指针int (*open) (struct inode *, struct file *);//与close对应函数指针:int (*release) (struct inode *, struct file *);...
};
//所以驱动层向上层提供的统计一的接口就是定义相应的函数,并填充struct file_opeations 结构体对象中的这些函数指针变量。//返回值:
如果major = 0时,那返回值就是成功:返回主设备号,失败返回错误码。
如果major > 0,成功返回0,返回0,失败返回错误码。//如果设备不再使用时,或者设备的驱动模块卸载时,就应当注册设号号:
void unregister_chrdev(unsigned int major, const char* name);
参数1 major就是要注销的设备号
参数2 要注销的设备的名称。

使用 register_chrdev 自动分配设备节点,会存在一个很大的问题:该设备会占用该主设备号的所有次设备号,这会有很大的危害

举个例子:
比如我的hello驱动主设备号是240,次设备号是0,
如果我使用 mknod 创建一个 /dev/abc 设备,主设备号也是240,次设备号 设置为1,
当我操作 /dev/abc 设备时,同样会调用我的hello驱动程序,
因为 register_chrdev 函数使得分配的主设备号下的所有次设备号都对应到hello驱动上了

解决方法:在设备注册时分配好固定的次设备号

第二种

一、alloc_chrdev_region、cdev_init、cdev_add

1、alloc_chardev_region:注册一系列字符设备编号

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
参数含义
dev分配的设备号(高12位是主设备号)
baseminor请求的起始次设备号
count请求的次设备号的数量
name自定义驱动程序名称

2、cdev_init:初始化cdev结构体

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
参数含义
cdevcdev结构体
file_operations关联应用程序和驱动程序的结构体(包含驱动读写函数指针等)

cdev 结构体,内部成员包括 file_operations 结构体、dev_t 设备号

struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
};

3、cdev_add:将字符设备添加到系统中

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
参数含义
pcdev结构体
dev分配的设备号(高12位是主设备号)
count请求的次设备号数量

二、注册驱动设备,并分配驱动设备次设备号

/* 初始化设备方法2:自动分配设备号,设置次设备号占用区域 */
//1.自动分配设备号(起始次设备号0,次设备数量 2,设备名称“hello_drv”)
alloc_chrdev_region(&hello_dev, 0, 2, "hello_drv");cdev_init(&hello_cdev, &hello_fops);cdev_add(&hello_cdev, hello_dev, 2);register_chrdev_region(hello_dev, 2, "hello_drv");

三、驱动程序示例

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/therm.h>
#include <linux/string.h>static unsigned char buff[100];
static struct class *hello_class;dev_t hello_dev;          		//保存分配的设备号
unsigned baseminor; 	  		//分配设备号的起始次设备号
static struct cdev hello_cdev;  //定义struct cdev 类型全局变量
unsigned char minor_count = 2; 	//指定次设备号个数static int hello_open (struct inode *node, struct file *filp)
{printk("hello_open\n");printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);return 0;
}static ssize_t hello_read (struct file *filp, char *buf, size_t size, loff_t *offset)
{size_t len = size > 100 ? 100 : size;printk("hello_read\n");copy_to_user(buf, buff, len);return len;
}static ssize_t hello_write (struct file *filp, const char *buf, size_t size, loff_t *offset)
{size_t len = size > 100 ? 100 : size;memset(buff, 0 ,sizeof(buff));printk("hello_write\n");copy_from_user(buff, buf, len);return len;
}static int hello_release (struct inode *node, struct file *filp)
{printk("hello_release\n");return 0;
}/*1.定义 file_operations 结构体*/
static const struct file_operations hello_fops = {.owner 		= THIS_MODULE,.read		= hello_read,.write		= hello_write,.open		= hello_open,.release    = hello_release,
};/*2.register_chrdev*//*3.入口函数*/
static int hello_init(void)
{struct device *dev;/* 初始化设备方法2:自动分配设备号,设置次设备号占用区域 */// 1. 自动分配设备号(起始次设备号baseminor,次设备数量 2)if(alloc_chrdev_region(&hello_dev, baseminor, minor_count, "hello_drv") < 0){printk(KERN_ERR"Unable to alloc_chrdev_region.\n");return -EINVAL;}//2.initialize a cdev structurecdev_init(&hello_cdev, &hello_fops);//3.add a char device to the systemif(cdev_add(&hello_cdev, hello_dev, minor_count) < 0){printk(KERN_ERR "Unable to cdev_add.\n");return -EINVAL;}//4.register a range of device numbersregister_chrdev_region(hello_dev, minor_count, "hello_drv");/*自动创建设备节点*//*在内核中创建设备*/hello_class = class_create(THIS_MODULE, "hello_class");if (IS_ERR(hello_class)) {printk("hello class create failed!\n");}/*在/dev下面创建设备节点*/device_create(hello_class, NULL, hello_dev, NULL, "hello");if (IS_ERR(dev)) {printk("hello device_create  failed!\n");}return 0;
}/*4.退出函数*/
static int hello_exit(void)
{//销毁设备device_destroy(hello_class, hello_dev);//删除设备类class_destroy(hello_class);/* 对应初始化设备方法2:自动分配设备号,设置次设备号占用区域 */unregister_chrdev_region(hello_dev, minor_count);cdev_del(&hello_cdev);return 0;
}	module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
关键字:字符设备驱动程序的两种注册方式

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: