新的接口来注册字符设备

老接口:register_chrdev
新接口:register_chrdev_region / alloc_chrdev_region + cdev


cdev相关内容都在 #include <linux/cdev.h>头文件中
cdev结构体:
struct cdev {
struct kobject kobj;
struct module *owner; //一般初始化为:THIS_MODULE
const struct file_operations *ops; //字符设备用到的一个重要的结构体file_operations,cdev初始化时与之绑定
struct list_head list;
dev_t dev; //主设备号24位 与次设备号8位,dev_t为32位整形
unsigned int count;
};
相关函数:cdev_alloc、cdev_init、cdev_add、cdev_del
dev_t类型是设备号(主设备号+次设备号)
MKDEV、MAJOR、MINOR三个宏
MKDEV:用主设备号和次设备号得到设备号(dev_t)
MAJOR:用设备号得到主设备号
MINOR:用设备号得到次设备号


使用:register_chrdev_region + cdev来注册字符设备,涉及3个函数:
register_chrdev_region + cdev_init + cdev_add

具体注册的过程:
1.分配主次设备号
2.注册设备驱动

#define TEST_CNT 1
static dev_t device_num = 0;
static cdev test_dev = {0};

device_num = MKDEV(TEST_MAJOR, 0);
ret = register_chrdev_region(device_num, TEST_CNT, TEST_NAME);
if (ret)
{
	printk(KERN_INFO "register_chrdev_region fail!!!\n");	
	return -EINVAL;
}
printk(KERN_INFO "register_chrdev_region OK!!!\n");
cdev_init(&test_dev, &test_ops);
ret = cdev_add(&test_dev, device_num, TEST_CNT);
if (ret)
{
	printk(KERN_INFO "cdev_add fail!!!\n");	
	return -EINVAL;
}
printk(KERN_INFO "cdev_add OK!!!\n");

注册步骤分析:
1.首先使用MKDEV宏,生成一个设备号(主设备号和次设备号合成的设备号),
宏的使用方式:MKDEV(主设备号,次设备号)
2.register_chrdev_region,根据设备号和CNT值,决定生成几个字符设备
第一个参数:设备号(主设备号和次设备号合成的)
第二个参数:CNT值,要生成多少个字符设备,生成的字符设备的次设备号是不同的,从指定的次设备号开始依次往上加。但是字符设备数组里面还是1个设备,也可以说是一类设备。字符设备数组只在于在意主设备号,不在意次设备号。
例如:我们用MKDEV时候,指定的主设备号是200,次设备号是0.
我们使用register_chrdev_region,如果CNT传的是1,我们mknod的时候就用200和0去生成一个字符设备,如果传的是2,那我们mknod的时候就可以使用(200,0)和(200,1)去生成两个字符设备,注意是用指定的次设备号开始增加的。
第三个参数的name,就是将来字符设备数组里面的name
3.cdev_init,初始化一个cdev的结构体test_dev ,并把fops绑定上去
第一个参数:cdev类型的指针
第二个参数:fops类型的指针
4.cdev_add,把字符设备注册到系统中
第一个参数:cdev类型的指针
第二个参数:设备号(主设备号和次设备号合成的)
第三个参数:要注册到系统的字符设备的个数
5.注册完了之后,在exit函数中要记得写注销函数:
// 使用新的接口来注销字符设备驱动
// 注销分2步:
// 第一步真正注销字符设备驱动用cdev_del
cdev_del(&test_dev);
// 第二步去注销申请的主次设备号
unregister_chrdev_region(device_num, TEST_CNT);
cdev_del:传入已经注册了的cdev类型的指针
unregister_chrdev_region:传入设备号和个数


总结一下:
两个类型的变量:dev_t , cdev
字符设备的个数:TEST_CNT
#define TEST_CNT 1
static dev_t device_num = 0;
static cdev test_dev = {0};
一个MKDEV宏
三个函数:
register_chrdev_region
cdev_init
cdev_add
注销函数:
cdev_del
unregister_chrdev_region


使用alloc_chrdev_region自动分配设备号
alloc_chrdev_region + cdev,涉及三个函数:
alloc_chrdev_region + cdev_init + cdev_add

register_chrdev_region是在事先知道要使用的主、次设备号时使用的;要先查看cat /proc/devices去查看没有使用的。
更简便、更智能的方法是让内核给我们自动分配一个主设备号,使用alloc_chrdev_region就可以自动分配了。
自动分配的设备号,我们必须去知道他的主次设备号,否则后面没法去mknod创建他对应的设备文件。
1.使用MAJOR宏和MINOR宏从dev_t得到major和minor
2.反过来使用MKDEV宏从major和minor得到dev_t。
3.注意倒映式的错误处理机制。


自动分配设备号:

ret = alloc_chrdev_region(&device_num, 10, TEST_CNT, TEST_NAME);
if (ret)
{
	printk(KERN_INFO "alloc_chrdev_region fail!!!\n");
	goto alloc_chrdev_region_error;
}
printk(KERN_INFO "alloc_chrdev_region OK!!!\n");
printk(KERN_INFO "MAJOR = %d\n", MAJOR(device_num));
printk(KERN_INFO "MINOR = %d\n", MINOR(device_num));

说明:alloc_chrdev_region
参数1:设备号的指针,内核把分配的设备号存在这里面
参数2:次设备号的开始数字
参数3:将来要生成几个字符设备,这几个字符设备的主设备号是相同的,次设备号不同
参数4:字符设备数组里面的名字
我们使用MAJOR宏和MINOR宏可以知道内核给我们分配的主设备号和次设备号
内核分配主设备号是从大往小分配的,分配一个最大的空闲的主设备号。
cdev部分是上面相同。


使用cdev_alloc
前面我们定义的是:static struct cdev test_dev; 一个全局变量
现在我们来使用一个:static struct cdev * test_dev;
让内核去帮我们分配和管理内存,我们传一个指针进入,内核就会帮我们分配一块这样的空间。具体实现:

test_dev = cdev_alloc();
test_dev->owner = THIS_MODULE;
test_dev->ops = &test_ops;
空间分配之后我们进行填充。

老接口和新接口的分析
老接口:
register_chrdev
调用:
__register_chrdev
调用:
__register_chrdev_region
cdev_alloc
cdev_add
来完成字符设备的注册的。

新接口分析
register_chrdev_region
__register_chrdev_region

alloc_chrdev_region
__register_chrdev_region
最终都是使用 __register_chrdev_region + cdev 函数来进行注册的。


字符设备的管理,其实都会在char_dev.c文件中。这里面有个很重要的结构体:
static struct char_device_struct {
struct char_device_struct *next; 指向链表中的下一个元素的指针
unsigned int major;主设备号
unsigned int baseminor; 起始次设备号
int minorct; 有多少个字符设备(主设备号相同,次设备号不同)
char name[64]; 处理该设备编号范围内的设备驱动的名称
struct cdev cdev; / will die */// 指向字符设备驱动程序描述符的指针
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
chrdevs 这个指针数组就是驱动中用来记录字符设备的。
大小是255的,但是实际的使用中,我们使用的是1-254。传0或者255都会帮我们自动分配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值