Linux-.标准字符设备
标准字符是内核对字符设备驱动的一种管理方式。
标准字符设备和早期字符、杂项字符设备本质上相同,都是对字符设备驱动的不同管理方式。
一个设备驱动,不管用早期字符设备、杂项字符设备、标准字符设备去管理,设备驱动功能没有任何区别!
标准字符设备是由早期字符设备拓展得到的,是由早期字符设备发展而来的,和早期字符设备80%相似!
标准字符设备的用途:主要在早期字符设备基础上,拓展了设备号的范围!
标准字符设备也可以用来管理一类类的设备!
特殊声明:标准字符设备的设备号分配比较灵活、自由!
3.1 标准字符设备的特性
字符设备具备三种核心属性:设备号、设备节点文件、文件操作集合
标准字符设备的设备号分布:u32 devnum = (major << 20) | minor;
主设备号: 0 ~ 2^12
次设备号: 0 ~ 2^20
设备节点文件:
标准字符设备注册成功之后,分配得到设备号。但是设备节点文件并不会自动创建,需要手动创建!
例: mknod /dev/led_hehe c major minor
文件操作集合:
所有设备驱动的文件操作集合完全相同。
3.2 标准字符设备结构体
标准字符设备结构体实质上和早期字符设备结构体一样!
标准字符设备结构体:struct cdev
struct cdev {
struct kobject kobj;
struct module owner; //THIS_MODULE
const struct file_operations ops; //文件操作集合
struct list_head list; //字符设备总线
dev_t dev; //设备号
unsigned int count; //要同时连续注册的设备个数
};
3.3 标准字符设备注册函数
标准字符设备是由早期字符设备拓展而来的,分析早期字符设备注册函数,可以获取标准字符设备注册方式!
早期字符设备注册函数分析: register_chrdev();
register_chrdev();
--> __register_chrdev(major, 0, 256, name, fops); //因为该函数,早期字符设备才必须同时注册256个次设备号
--> struct cdev *cdev; // 1. 字符设备结构体指针变量声明
--> __register_chrdev_region(major, baseminor, count, name);//2. 分配一个主设备号对应的多个连续次设备号
--> cdev = cdev_alloc(); //3. 在内核层分配字符设备结构体变量空间
--> cdev->owner = fops->owner; //4. 对字符设备结构体变量赋值
--> cdev->ops = fops;
--> kobject_set_name(&cdev->kobj, "%s", name);
--> cdev_add(cdev, MKDEV(cd->major, baseminor), count); //5. 注册当前字符设备到字符设备总线
--> return major ? 0 : cd->major;
根据早期字符设备注册流程,分析得到标准字符设备注册方式:
1)根据标准字符设备结构体定义结构体指针变量,用来表示当前设备驱动。 --> struct cdev
2)分配结构体变量空间。 --> cdev_alloc();
3)申请设备号。可以申请一个主设备号对应的多个连续次设备号。 --> alloc_chrdev_region();
4)标准字符设备结构体变量初始化。 --> cdev_init();
5)注册标准字符设备到字符设备总线。 --> cdev_add();
cdev_alloc();
函数原型:struct cdev cdev_alloc(void);
函数功能:在内核层分配标准字符设备结构体变量空间
形参列表:无
返回值:
成功:分配得到的结构体变量空间首地址
失败:NULL
释放结构体空间:void kfree(const void p);
alloc_chrdev_region();
函数原型:int alloc_chrdev_region(dev_t dev, unsigned baseminor, unsigned count, const char name);
函数功能:申请一个主设备号及其对应的多个连续次设备号
形参列表:
dev:指针类型的传参。 用来接收申请得到的起始设备号。
baseminor:起始次设备号
count:同时申请的连续次设备号的个数
name:设备号标签(随意)
返回值:
成功:0
失败:负数
释放设备号:void unregister_chrdev_region(dev_t from, unsigned count);
cdev_init();
函数原型:void cdev_init(struct cdev cdev, const struct file_operations fops);
函数功能:对标准字符设备结构体变量初始化(主要初始化文件操作集合)
形参列表:
cdev:要初始化的结构体变量
fops:文件操作集合
返回值:无
cdev_add();
函数原型:int cdev_add(struct cdev p, dev_t dev, unsigned count);
函数功能:注册字符设备驱动到字符设备总线。(可以同时注册多个设备)
形参列表:
p:要注册的设备驱动对应的设备结构体
dev:要注册的起始设备号
count:要连续注册的设备号的个数
返回值:
成功:0
失败:负数
注销函数:void cdev_del(struct cdev p);
补充:设备号和主设备号、次设备号之间转换的方式!
#define MINORBITS 20
#define MINORMASK ((1UL << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
来源:51CTO
作者:qq59a65ffb52e85
链接:https://blog.51cto.com/13258379/2477234