标准字符设备注册函数
标准字符设备是由早期字符设备拓展而来的,分析早期字符设备注册函数,可以获取标准字符设备注册方式!
早期字符设备注册函数分析: 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;
根据早期字符设备注册流程,分析得到标准字符设备注册方式:
- 根据标准字符设备结构体定义结构体指针变量,用来表示当前设备驱动。 --> struct cdev
- 分配结构体变量空间。 --> cdev_alloc();
- 申请设备号。可以申请一个主设备号对应的多个连续次设备号。 --> alloc_chrdev_region();
- 标准字符设备结构体变量初始化。 --> cdev_init();
- 注册标准字符设备到字符设备总线。 --> 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))