5.3.5.字符设备驱动注册代码分析1
5.3.5.1、老接口分析
register_chrdev 默认此设备号为0
__register_chrdev 并且传入子设备号的起始为0,最大子设备数为256
__register_chrdev_region 注册主次设备号的
cdev_alloc
cdev->owner = fops->owner; //这两行赋值就等效于cdev_init函数完成的任务
cdev->ops = fops;
cdev_add 注册驱动
5.3.5.2、新接口分析
register_chrdev_region
__register_chrdev_region
cdev_alloc
cdev_init
cdev_add
alloc_chrdev_region
__register_chrdev_region 传入major=0;进行内核自动分配的处理。
cdev_alloc
cdev_init
cdev_add
再对比旧新接口,在本质上做的任务其实是一样的。
struct char_device_struct //整个设备驱动,驱动加设备号,这个是直接放在内核管理数组里面的
{
struct char_device_struct *next;//链表用来连接子设备
unsigned int major;主设备号
unsigned int baseminor;次设备号的起始标号
int minorct;最小的次设备号数
char name[64];名字,也就我们对驱动命名不能超过64个字节
struct cdev *cdev; 指向表示驱动的结构体
这个结构体就表示一个主次设备驱动,
}*chrdevs[CHRDEV_MAJOR_HASH_SIZE];
chrdevs这个结构体指针数组就是内核用来管理设备驱动的数组,各个驱动用char_device_struct表示,并将其首地址放到chrdevs数组中。CHRDEV_MAJOR_HASH_SIZE这个大小255也就证明前面cat /proc/devices中从0到255,一个内核支持256个设备驱动。
struct cdev { //只表示设备驱动,未含设备号
struct kobject kobj; 计数 用来表示该设备驱动被使用了几次,使用一次加1,使用完一次减一,每次减法都与0进行对比,来查看是否还人使用该设备驱动,如果没有则可以释放申请来的驱动内存,因为之前是使用内核申请堆内存来存放的,因此引入计数来表示是否要进行是否内存
struct module *owner;表示代表一个内核模块
const struct file_operations *ops;基本是一些函数指针指向驱动中实现的一些函数open...
struct list_head list;链表
dev_t dev;主次设备号,可以用三个宏来拆分合并 MKDEV,MAJOR,MINOR;
unsigned int count;子设备的数量
};
__register_chrdev_region。传入主设备号,次设备号起始,次设备号数量,名字。作用就是注册设备号,返回一个structchar_device_struct*。表示内部申请堆内存存放结构体,返回首地址。
分析内部
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);果然申请了堆内存来存放结构体
处理了如果由内核分配major==0时的处理,然后再合并。内部就是完成对char_device_struct结构体元素的赋值。