linux驱动虚拟总线platform_driver和platform_driver(LED驱动)

本文介绍了Linux平台驱动模型,包括VID & PID、驱动和设备分离的概念。重点解析了platform_device和platform_driver的注册过程,以及probe函数在设备初始化中的作用。文章还讨论了虚拟总线带来的优势,如资源管理的独立性、可移植性和安全性,并提供了LED驱动的示例来说明open和ioctl的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VID & PID

每一个设备都有一个设备id和厂商id,设备管理器–>硬件属性–>详细信息–>属性–>硬件id,

驱动和设备分离

从Linux 2.6起引入了一套新的驱动管理和注册机制:Platform_device和Platform_driver。Linux中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver进行注册。

Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。

1、设备(platform_device)注册的过程中会调用platform总线的match函数去寻找目前已经挂接在platform总线上与设备(paltform_device)名字对应的驱动(platform_driver)。相反的驱动(platform_driver)注册的时候一样去寻找挂接在总线上名字对应的设备(platform_device)
2、匹配上后,会执行驱动(platform_driver)的probe函数
3、probe函数中会实现控制器的初始化和其他的一些准备工作,并且会有注册实际的设备(比如eeprom)

实现platform模型的过程就是总线对设备和驱动的匹配过程 。打个比方,就好比相亲,总线是红娘,设备是男方,驱动是女方:

a – 红娘(总线)负责男方(设备)和女方(驱动)的撮合;

b – 男方(女方)找到红娘,说我来登记一下,看有没有合适的姑娘(汉子)—— 设备或驱动的注册;

c – 红娘这时候就需要看看有没有八字(二者的name 字段)匹配的姑娘(汉子)——match 函数进行匹配,看name是否相同;

d – 如果八字不合,就告诉男方(女方)没有合适的对象,先等着,别急着乱做事 —— 设备和驱动会等待,直到匹配成功;

e – 终于遇到八字匹配的了,那就结婚呗!接完婚,男方就向女方交代,我有多少存款,我的房子在哪,钱放在哪等等( struct resource *resource),女方说好啊,于是去房子里拿钱,去给男方买菜啦,给自己买衣服、化妆品、首饰啊等等(int (*probe)(struct platform_device *) 匹配成功后驱动执行的第一个函数),当然如果男的跟小三跑了(设备卸载),女方也不会继续待下去的( int (*remove)(struct platform_device *))。

设备和驱动没有谁先谁后,谁先安装模块,谁就等待谁。

platform_device

定义在:include/linux/platform_device.h中
这是内核3.0.0中的定义

struct platform_device {
        const char      * name;//设备名称 重要
        int             id;	//设备号,相当于次设备号
        struct device   dev;	//所有设备通用的属性部分
        u32             num_resources;//设备使用到的resource的个数
        struct resource * resource;//设备使用到的资源数组的首地址

        const struct platform_device_id *id_entry;//设备ID表

        /* MFD cell pointer */
        struct mfd_cell *mfd_cell;

        /* arch specific additions */
        struct pdev_archdata    archdata; //自留地,用来提供扩展性的
};

设备模块先初始化后,注册设备端的设备
__init platdev_init:
platform_device_register(&platform_device)

static struct platform_device s3c_led_device = {
    .name    = "s3c_led",
    .id      = 1,
    .dev     = 
    {
        .platform_data = &s3c_led_data, 
        .release = platform_led_release, //一个关闭函数
    },
};

比如这个led的驱动,设备的结构体被注册到内

<think>我们正在讨论Linux设备模型中的三个关键结构体:platform_device、platform_driverdevice_driver。 它们之间的关系是: 1. platform_device 代表一个具体的平台设备,通常描述SoC上的外设(如I2C控制器、SPI控制器等),它包含设备的资源(如内存地址、中断号等)。 2. device_driver 是一个通用的设备驱动结构体,包含驱动的基本操作(如probe、remove)设备模型需要的字段。 3. platform_driver 是平台设备驱动,它内嵌了一个device_driver结构体,并扩展了平台设备特有的操作(如平台设备匹配电源管理)。 具体关系如下: - platform_driver 结构体中包含一个 device_driver 结构体成员(通常命名为driver)。 - platform_driver 通过其内部的 device_driver 成员与内核设备模型关联。 - 当注册一个 platform_driver 时,实际上是通过其内部的 device_driver 注册到总线上(platform_bus_type)。 - platform_device platform_driver 通过名称进行匹配(即platform_device的name字段platform_driver的id_table或者driver.name匹配)。 - 匹配成功后,会调用 platform_driver 中的 probe 函数。 结构体定义(简化): ```c struct platform_device { const char *name; // 设备名称,用于匹配驱动 int id; struct device dev; // 内嵌的通用设备结构体 // ... 资源信息等 }; struct device_driver { const char *name; // 驱动名称 struct bus_type *bus; // 所属总线 int (*probe)(struct device *dev); // 探测设备 int (*remove)(struct device *dev); // 移除设备 // ... 其他操作 }; struct platform_driver { int (*probe)(struct platform_device *); // 平台设备的探测函数 int (*remove)(struct platform_device *); // 移除函数 struct device_driver driver; // 内嵌的通用设备驱动 const struct platform_device_id *id_table; // 设备匹配表 }; ``` 工作流程: 1. 系统启动时,平台设备(platform_device)通常通过板级文件或设备树被注册到内核。 2. 驱动程序通过调用`platform_driver_register`注册一个platform_driver。 3. 内核的platform总线(platform_bus_type)会尝试将已注册的设备与驱动进行匹配。 4. 匹配依据:platform_driverdriver.name与platform_device的name匹配,或者platform_driver的id_table中的任一条目与platform_device的name匹配。 5. 匹配成功则调用platform_driver的probe函数(注意:实际调用的是platform_driver->driver.probe,但通常这个函数指针被设置为一个内部函数,该内部函数会调用platform_driver->probe,并将device转换为platform_device)。 注意:在platform_driver的初始化中,通常会将device_driver的probe函数设置为一个通用的平台驱动probe函数(例如platform_drv_probe),这个函数会调用platform_driver自己的probe函数。 总结: - platform_device 描述硬件设备。 - platform_driver 包含驱动该硬件设备的函数,并内嵌一个device_driver。 - device_driver 是设备驱动的通用部分,由platform_driver中的driver成员实现。 关系图: platform_driver -> 包含 device_driver platform_device -> 包含 device 在总线上,device_driverdevice进行匹配,而实际上匹配的是platform_deviceplatform_driver。 §§相关问题§§ 1. 在内核中,platform_deviceplatform_driver是如何通过名称进行匹配的? 2. 当platform_driver注册时,其内嵌的device_driver的probe函数是如何被设置并最终调用到platform_driver的probe函数的? 3. 设备树(Device Tree)机制下,platform_device是如何被创建注册的? 4. platform_device结构体中的struct device dev成员与device_driver结构体有何关联? 5. 在platform驱动模型中,为什么需要将device_driver内嵌在platform_driver中,而不是直接使用device_driver?</think>### Linux设备驱动模型核心结构体关系解析 #### 1. **基础层级关系** ```c struct device_driver { // 通用驱动抽象 const char *name; // 驱动名称 struct bus_type *bus; // 所属总线 int (*probe)(struct device *dev); // 探测设备 ... }; struct platform_driver { // 平台设备驱动 int (*probe)(struct platform_device *); struct device_driver driver; // 内嵌通用驱动结构 const struct platform_device_id *id_table; ... }; struct platform_device { // 平台设备实例 const char *name; // 设备名称 struct device dev; // 内嵌设备基类 struct resource *resource; // 设备资源 ... }; ``` #### 2. **关键交互机制** 1. **注册绑定流程** ```mermaid graph LR A[platform_device_register] --> B[注册到platform_bus] C[platform_driver_register] --> D[注册driverplatform_bus] B & D --> E[总线匹配driver.name与device.name] E --> F[调用platform_driver.probe] ``` 2. **结构体内嵌关系** - `platform_driver` 包含 `device_driver` 成员 - `platform_device` 包含 `device` 成员 - 通过`container_of`宏实现父子结构转换: ```c struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct platform_driver *pdrv = container_of(drv, struct platform_driver, driver); ``` #### 3. **功能对比表** | 结构体 | 作用域 | 关键成员 | 生命周期管理 | |------------------|-------------|----------------------------|-------------------| | `device_driver` | 通用驱动模型 | name, bus, probe | 所有设备类型通用 | | `platform_driver`| 平台设备驱动 | driver, probe, id_table | 封装platform特有操作 | | `platform_device`| 平台设备实例 | name, dev, resource | 描述SoC固定资源 | #### 4. **典型驱动开发流程** ```c // 定义平台驱动 static struct platform_driver my_driver = { .probe = my_probe, .driver = { .name = "my_device", // 匹配设备名称 .owner = THIS_MODULE, }, }; // 设备探测函数 static int my_probe(struct platform_device *pdev) { // 1. 获取设备资源 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 2. 映射寄存器 void __iomem *base = devm_ioremap_resource(&pdev->dev, res); // 3. 注册字符设备等操作 ... } // 注册驱动 module_platform_driver(my_driver); ``` #### 5. **设备树(Device Tree)整合** 现代Linux使用设备树替代硬编码`platform_device`: ```dts my_device: my_device@0x12340000 { compatible = "vendor,my-device"; // 匹配驱动 reg = <0x12340000 0x1000>; // 寄存器空间 interrupts = <0 45 4>; // 中断号 }; ``` 驱动通过`of_match_table`匹配: ```c static const struct of_device_id my_of_ids[] = { { .compatible = "vendor,my-device" }, {} }; struct platform_driver my_driver = { .driver = { .of_match_table = my_of_ids, }, }; ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值