news 2026/10/10 6:16:29

理解无设备树的platform平台驱动模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
理解无设备树的platform平台驱动模型

在Linux2.6以后的设备驱动模型中,需要关心总线、设备和驱动3个实体,总线将设备和驱动 绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

platform总线

linux系统内核使用bus_type结构体表示总线,该结构体定义在include/linux/device.h。

重点关注结构体中的函数: int (*match)(struct device *dev, struct device_driver *drv);

该函数完成设备和驱动之间匹配。总线就是使用match函数来根据注册的设备来查找对应的驱动,或根据注册的驱动来查找相应的设备,因此每一条总线都必须实现此函数。match函数的两个参数分别代表设备和驱动。

platform总线是bus_type的一个实例,定义在drivers/base/platform.c 。

struct bus_type platform_bus_type = { ... .match = platform_match, ... };

platform_bus_type就是platform平台总线。platform_match就是匹配函数。

static int platform_match(struct device *dev, struct device_driver *drv)

platform_match()函数确定了platform_device和platform_driver之间的匹配。

可能有四种匹配情况:

1、基于设备树风格的匹配

if (of_driver_match_device(dev,drv)) return 1

2、基于ACPI风格的匹配

if (acpi_driver_match_device(dev,drv)) return 1

3、匹配ID表

if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL;

4、匹配platform_device设备名和驱动的名字

return (strcmp(pdev->name, drv->name) == 0);

platform驱动

platform_driver结构体

struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); ... struct device_driver driver; const struct platform_device_id *id_table; ... };

id_table就是platform总线匹配驱动和设备时的第三种方法。

在编写platform驱动时,需要完成probe的编写,比如:

static int led_probe(struct platform_device *dev) { struct resource *ledsource; int ressize; ledsource = platform_get_resource(dev, IORESOURCE_MEM, 0); ressize = resource_size(ledsource); ... return 0; }

对resource的定义通常在BSP的板文件中进行,而在具体的设备驱动中通过函数platform_get_resource()获取:

struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);

resource_size()是一个内联函数,输入参数const struct resource *res,返回值是资源的大小,

结构体中device_driver的结构体定义在include/linux/device.h

struct device_driver { const char *name; struct bus_type *bus; ... const struct of_device_id *of_match_table; ... };

其中of_device_id结构体定义在include/linux/mod_devicetable.h,of_match_table就是采用设备树时驱动使用的匹配表。

struct of_device_id { char name[32]; char type[32]; char compatible[128]; const void *data; };

定义及初始化paltform_driver结构体变量后,需要调用platform_driver_register函数向linux内核注册一个platform驱动。

int platform_driver_register(struct platform_driver *driver)

在驱动卸载函数中通过platform_driver_unregister函数卸载platform驱动。

void platform_driver_unregister(struct platform_driver *drv)

需要增加的platform驱动函数和数据

static int xxx_probe(struct platform_device *dev) { cdev_init(&xxxdev.cdev, &xxx_fops); ... return 0; } static int xxx_remove(struct platfomr_device *dev) { ... cdev_del(&xxxdev.cdev); ... return 0; } static const struct of_device_id xxx_of_match[] = { {.compatible = "xxx-gpio"}, ..., }; static struct platform_driver xxx_driver = { .driver = { .name = "xxx", .of_match_table = xxx_of_match, }, .probe = xxx_probe, .remove = xxx_remove, }; static int __init xxxdriver_init(void) { return platform_driver_register(&xxx_driver); } static void __exit xxxdriver_exit(void) { platform_driver_unregister(&xxx_driver); } module_init(xxxdriver_init); module_exit(xxxdriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR();

platform设备

platform_device结构体表示platform设备,这个结构体定义在include/linux/platform_device.h。

struct platform_device { const char *name; int id; bool id_auto; struct device dev; u32 num_resources; struct resource *resource; ... };

其中name要和 paltform驱动的name字段相同,否则设备就无法匹配到对应的驱动。

resource结构体

struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent, *sibling, *child; };

不支持设备树的linux版本,需要写platform_device变量来描述设备信息,然后使用platform_device_register函数将设备信息注册到linux内核中。

int platform_device_register(struct platform_device *pdev)

注销platform设备的函数

void platform_device_unregister(struct platform_device *pdev)

platform设备信息框架

/* 寄存器地址定义 */ #define PERIPH1_REGISTER_BASE (0X20000000) #define PERIPH2_REGISTER_BASE (0X20000068) #define REGISTER_LENGTH 4 static struct resource xxx_resources[] = { [0] = { .start = PERIPH1_REGISTER_BASE, .end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1), .flags = IORESOURCE_MEM, }, [1] = { .start = PERIPH2_REGISTER_BASE, .end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1), .flags = IORESOURCE_MEM, }, }; static struct platform_device xxxdevice = { .name = "xxx-gpio", .id = -1, .num_resources = ARRAY_SIZE(xxx_resources), .resource = xxx_resources, }; static int __init xxxdevice_init(void) { return platform_device_register(&xxxdevice); } static void __exit xxxdevice_exit(void) { return platform_device_unregister(&xxxdevice); } module_init(xxxdevice_init); module_exit(xxxdevice_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR();

参考资料
1. I.MX6U 嵌入式 Linux 驱动开发指南 V2.0.1 正点原子

2. Linux设备驱动开发详解:基于最新的Linux 4.0内核

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 6:16:27

等待=什么才是真正的抄底?你赚的从来不是市场的钱,是别人迫不得已交出来的筹码:对手盘市场

什么才是真正的抄底?你赚的从来不是市场的钱,是别人迫不得已交出来的筹码 目录 什么才是真正的抄底?你赚的从来不是市场的钱,是别人迫不得已交出来的筹码 你赚的从来不是市场的钱,是别人迫不得已交出来的筹码 一、什么才叫真正的安全边际?对面的人根本不想卖 二、长线根…

作者头像 李华
网站建设 2026/10/10 6:15:51

Python实战第24期:Prompt工程基础

文章目录 引言:什么是Prompt工程? 一、什么是Prompt 1. Prompt的定义 2. Prompt的组成 3. Prompt的重要性 二、Prompt设计技巧 1. 明确具体 2. 提供上下文 4. 分步骤思考(Chain of Thought) 5. 指定输出格式 三、系统提示词 1. 什么是系统提示词 2. 系统提示词的作用 3. 系…

作者头像 李华
网站建设 2026/10/10 6:15:12

安卓编译器神器,编程学习随时随地

安卓手机上存在那些办公软件性质的编译器, 它们的页面工具具有比较高的还原度, 精细的画面展示在大家眼前, 让用户高效利用手机打开软件, 从而完成一系列的工作, 减少时间和特殊情况, 正在学习编程的用户, 在下载使用之后, 任何时间都可以进行练习, 赶紧有需要的体验编程的用户…

作者头像 李华
网站建设 2026/10/10 6:13:35

【单片机毕业设计】基于单片机的学生宿舍大气环境无线采集与远程安全预警系统设计 基于单片机的室内大气压与空气质量物联网监测声光报警装置设计(030109)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华