字符设备驱动框架,与设备模型没有任何直接关系,互相独立。
但是,通常有间接关系:字符设备驱动可能会主动搭配平台设备模型使用。
1. 字符设备驱动
字符设备驱动,有一套自己独有的数据结构,比如设备号、 struct cdev,不复杂都是基于 kobject 的微弱派生出来的体系。另外它与其他子系统互联互动,比如 VFS 进程 ,实现一套独立、精简、朴素的、灵活的、实用的驱动框架。
字符设备驱动的使用过程:
1.1 注册过程:
1. 准备 file_operations 结构体内必要的驱动函数;
2. 向字符设备框架申请设备号资源;
3. 初始化 cdev 结构体 cdev_init(dev, &fops);
4. 注册进 cdev core : cdev_add(dev, dev_num, MINOR_COUNT);
以上是必不可少的环节,下面是可选的,通常会有的:
5. 创建设备类:dev_class = class_create(THIS_MODULE, CLASS_NAME);
6. 创建设备节点:dev_device = device_create(dev_class, NULL, dev_num, NULL, DEVICE_NAME);
1.2 动态描述:
1. cdev core 和 VFS、进程协同工作;
2. 应用层调 open/read/write/lseek ,会陷入到系统调用对应的 sys_xxxs,最终会调用到内核里字符设备驱动注册过的 file_operations 的 open/read/write/llseek 驱动函数。
2. 设备模型
设备模型是linux内核管理硬件及其驱动的基石机制。将硬件管理分为:总线、设备、驱动。
总线节点上挂载设备链表和驱动链表,动态感知匹配
// match 函数的通用原型
typedef int (*bus_match_func_t)(struct device *dev, struct device_driver *drv);
/* 派生 match 方法 */
// (1) Platform 总线(platform_bus_type)
static int platform_match(struct device *dev, struct device_driver *drv);
// (2) PCI 总线(pci_bus_type)
static int pci_bus_match(struct device *dev, struct device_driver *drv);
// (3) I2C 总线(i2c_bus_type)
static int i2c_device_match(struct device *dev, struct device_driver *drv);
其中,平台总线是一条虚拟总线,其他比如 USB、PCIe、SPI/i2c 都是实际物理总线。那些物理总线支持热插拔更像内核亲生的。平台总线不支持硬件探测,且通常需要通过设备树将硬件信息注入到内核形成一个挂载在平台总线上的设备。
3. 平台设备模型
//平台设备模型的 match 方法:
static int platform_match(struct device *dev, struct device_driver *drv) {
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
// 1. 通过设备树匹配(of_match_table)
if (of_driver_match_device(dev, drv))
return 1;
// 2. 通过 ACPI 匹配(acpi_match_device)
if (acpi_driver_match_device(dev, drv))
return 1;
// 3. 通过 id_table 匹配(驱动定义的静态 ID 表)
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
// 4. 通过设备名称匹配(如 legacy 设备)
return strcmp(pdev->name, drv->name) == 0;
}
平台设备模型中,平台总线左手拉设备,右手牵驱动,主动感知匹配,若匹配成功就调用驱动的 probe 函数。这就是一个很纯粹的机制,可以在 probe 函数里面做任何事情,通常是会做跟硬件相关的任何事情,比如硬件中断注册、字符设备注册、pinctrl/gpio/input 注册等等等等等。
通常需要设备树配合,因为设备树上的硬件信息,会被内核解析生成为平台总线上挂载的设备。驱动程序通过平台设备模型的方式挂接到总线上的驱动链表上。