Linux-标准字符设备

1. 标准字符设备

标准字符是内核对字符设备驱动的一种管理方式。

标准字符设备和早期字符、杂项字符设备本质上相同,都是对字符设备驱动的不同管理方式。

一个设备驱动,不管用早期字符设备、杂项字符设备、标准字符设备去管理,设备驱动功能没有任何区别!

标准字符设备是由早期字符设备拓展得到的,是由早期字符设备发展而来的,和早期字符设备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))

猜你喜欢

转载自www.cnblogs.com/646087666-lxd/p/12461424.html
今日推荐