重庆市网站建设_网站建设公司_加载速度优化_seo优化
2026/1/20 8:52:17 网站建设 项目流程

title: faux
categories:

  • linux
  • drivers
  • base
    tags:
  • linux
  • drivers
  • base
    abbrlink: 7a8aa269
    date: 2025-10-03 09:01:49

https://github.com/wdfk-prog/linux-study

文章目录

  • drivers/base/faux.c 虚拟设备总线(Faux Bus) 简化虚拟设备驱动的创建
      • 历史与背景
        • 这项技术是为了解决什么特定问题而诞生的?
        • 它的发展经历了哪些重要的里程碑或版本迭代?
        • 目前该技术的社区活跃度和主流应用情况如何?
      • 核心原理与设计
        • 它的核心工作原理是什么?
        • 它的主要优势体现在哪些方面?
        • 它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
      • 使用场景
        • 在哪些具体的业务或技术场景下,它是首选解决方案?请举例说明。
        • 是否有不推荐使用该技术的场景?为什么?
      • 对比分析
        • 请将其 与 其他相似技术 进行详细对比。
    • faux_bus_init: 初始化并注册一个虚拟总线
    • faux_device_create_with_groups / faux_device_create: 创建并注册一个虚拟设备

drivers/base/faux.c 虚拟设备总线(Faux Bus) 简化虚拟设备驱动的创建

历史与背景

这项技术是为了解决什么特定问题而诞生的?

drivers/base/faux.c文件所实现的 “Faux Bus”(虚拟总线)是一项较新的内核技术,在 Linux 6.14 内核中被合并。它的诞生主要是为了解决一个长期存在的内核开发“滥用”问题:将平台总线(Platform Bus)用于不属于平台设备(Platform Device)的场景

内核维护者 Greg Kroah-Hartman 指出,多年来,许多开发者为了利用设备模型的便利性(如自动的驱动-设备绑定、probe/remove回调机制),会将一些纯粹的虚拟设备或简单的逻辑设备注册为“平台设备”。 这种做法在功能上可行,但从设计哲学上看是不正确的,因为平台设备本意是指那些在SoC(片上系统)上,无法通过正常总线(如PCI, USB)枚举发现的、有固定内存地址或硬件资源的设备。将纯虚拟设备(例如一个用于测试的dummy regulator)注册为平台设备,是一种概念上的滥用,并给代码带来了不必要的复杂性。

Faux Bus 的目的就是提供一个极其简单的、专为这类虚拟或“假”设备设计的总线,从而清理代码,让平台总线的用途回归其本意。

它的发展经历了哪些重要的里程碑或版本迭代?
  • 2025年2月:由内核核心维护者 Greg Kroah-Hartman 提出 “Faux Bus” 的概念和初始补丁集,并征求社区意见。
  • Linux 6.14内核:该技术被正式合并进入主线内核。一个显著的特点是,它在被引入的同时,就提供了C语言和Rust语言的API绑定,这在内核新接口的开发中较为少见,也体现了对新兴内核开发语言的支持。
  • Linux 6.15及以后:社区开始将内核中原先滥用平台总线的驱动,逐步转换到使用 Faux Bus。
目前该技术的社区活跃度和主流应用情况如何?

作为一个新兴的内核API,Faux Bus 正处于被逐步推广和应用的阶段。内核社区正在积极地识别那些适合转换的驱动程序,并提交补丁。它的主要应用场景是内核内部的虚拟设备、测试驱动和一些简单的逻辑抽象设备,例如:

  • Dummy regulator 驱动
  • USB PHY (physical layer) 的一些辅助代码

核心原理与设计

它的核心工作原理是什么?

drivers/base/faux.c的核心原理是提供一个极简的API,将“创建设备”和“创建并绑定驱动”这两个动作合二为一。

  1. 定义一个新总线:代码内部定义了一个名为 “faux” 的bus_type。这是一个非常简单的总线,没有复杂的匹配逻辑。
  2. 统一的创建函数:它对外暴露的核心API是faux_device_create_with_groups()。当一个内核模块调用这个函数时,它会执行以下一系列操作:
    • 动态地创建一个struct device_driver实例。这个驱动被设置为属于 “faux” 总线。
    • 动态地创建一个struct device实例,并将其总线也设置为 “faux”。
    • 自动绑定:由于设备和驱动被创建时就明确了对应关系,内核会立即将它们绑定在一起。这个绑定操作会触发调用调用者提供的.probe回调函数。
  3. 生命周期管理faux_device_create_with_groups()函数会返回一个指向新创建的faux_device的指针。这个设备的生命周期由调用者管理。当不再需要该设备时,调用者只需调用faux_device_destroy(),该函数会自动处理驱动的.remove回调、设备和驱动的注销以及内存的释放。
它的主要优势体现在哪些方面?
  • API极其简单:相比平台设备的注册,Faux Bus 的API更简单,只需要两个核心函数(创建和销毁)。
  • 概念清晰:为虚拟设备和逻辑设备提供了一个专属的、名正言顺的“家”,避免了对平台总线的滥用,使内核代码的意图更清晰。
  • 代码更简洁:在一些转换案例中,使用 Faux Bus 相比原先使用平台总线的代码,行数有所减少,逻辑也更直接。
  • 自动绑定:创建设备的同时就隐式创建并绑定了驱动,开发者无需关心匹配逻辑。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
  • 功能极简:Faux Bus 被设计为只处理最简单的情况。它没有设备树(Device Tree)或ACPI支持,不适用于需要从固件获取信息的设备。
  • 无匹配逻辑:它不支持一个驱动匹配多个设备,或者一个设备在多个驱动间选择。设备和驱动是一对一的、在创建时就锁定的关系。
  • 不适用于真实硬件:它的设计目标是纯软件的、虚拟的设备。任何与真实物理总线或硬件资源相关的设备都不应该使用 Faux Bus。

使用场景

在哪些具体的业务或技术场景下,它是首选解决方案?请举例说明。

Faux Bus 是为那些纯软件模拟的、生命周期由其他内核模块动态管理的逻辑设备提供的首选解决方案。

  • 场景一:Dummy Regulator
    内核的regulator/dummy.c驱动可以创建一个虚拟的稳压器(regulator),用于测试或满足那些在软件上需要一个regulator句柄但实际上没有硬件对应的场景。在过去,它通过注册一个platform_deviceplatform_driver来实现。现在,它可以直接使用faux_device_create()来创建这个虚拟稳压器,代码更简洁且概念上更正确。
  • 场景二:USB PHY 辅助逻辑
    某些USB控制器驱动需要在内部管理一个抽象的PHY层,这个PHY层可能没有独立的物理设备与之对应。使用 Faux Bus 可以为此创建一个逻辑上的设备和驱动,以便利用设备模型的probe/remove机制来管理其初始化和清理过程,而无需污染平台总线。
是否有不推荐使用该技术的场景?为什么?
  • 所有与物理硬件相关的设备:如果一个设备是通过PCIe、USB、I2C、SPI等物理总线连接的,或者是在设备树/ACPI中描述的SoC内部设备,绝对不能使用 Faux Bus。这些设备必须使用其对应的真实总线类型(pci_driver,usb_driver,platform_driver等)。
  • 需要驱动与设备分离的场景:如果希望一个驱动能支持多种设备,或者一个设备能由多个驱动中的一个来处理(例如一个通用驱动和一个厂商特定驱动),则不应使用 Faux Bus,因为它不支持这种分离的匹配逻辑。

对比分析

请将其 与 其他相似技术 进行详细对比。

Faux Bus 的主要对比对象就是被它取代的“滥用”方案——平台总线(Platform Bus),以及另一个虚拟总线——虚拟总线(Virtual Bus)。

特性Faux Bus (faux.c)Platform Bus (platform.c)Virtual Bus (subsys_virtual_register)
设计用途用于纯粹的、简单的、与硬件无关的虚拟/逻辑设备,以取代对平台总线的滥用。用于SoC上那些无法被硬件自动枚举的、通常在设备树或ACPI中描述的真实硬件设备。用于表示一类虚拟设备,这些设备通常出现在/sys/devices/virtual/下,如网络设备(net)或输入设备(input)。
API复杂度极低。核心API只有创建和销毁,设备和驱动在创建时自动绑定。中等。需要分别定义platform_deviceplatform_driver,并通过匹配机制(如设备树的compatible字符串或设备名)进行绑定。。提供注册总线的API,但设备和驱动的注册仍需分开处理。
设备-驱动关系一对一,创建时锁定。一个faux_device_create调用就唯一对应一个驱动实例。多对多,运行时匹配。一个驱动可以支持多种设备,一个设备也可以匹配多个潜在的驱动。灵活,由子系统自身决定。
硬件/固件支持。完全不处理设备树或ACPI。核心特性。平台总线的核心任务就是处理通过固件描述的硬件设备。
Sysfs路径/sys/bus/faux/devices//sys/bus/platform/devices//sys/devices/virtual/<subsys_name>/
典型例子Dummy regulator, USB PHY 逻辑。I2C控制器、SPI控制器、SoC内部的DMA引擎。网络接口(eth0)、TTY设备、输入设备(event0)。

faux_bus_init: 初始化并注册一个虚拟总线

此代码片段的作用是定义并注册一个完整的、自包含的 “faux” (虚拟) 总线系统。这个过程是 Linux 设备模型中建立新总线的基础, 它包括三个核心步骤:

  1. 注册一个根设备 (faux_bus_root): 这个设备在sysfs中作为虚拟总线层次结构的顶层目录, 通常位于/sys/devices/faux
  2. 注册一个总线类型 (faux_bus_type): 这定义了总线的名称、行为以及最重要的——设备与驱动的匹配规则 (match函数) 和探测/移除逻辑 (probe/remove函数)。
  3. 注册一个驱动程序 (faux_driver): 这是挂载在此总线上的一个驱动实例。
/* * 定义一个静态的 struct device 实例, 作为虚拟总线的根设备. * 在 sysfs 中, 它通常会表现为 /sys/devices/faux 目录. * 'static' 关键字使其在此文件外部不可见. */staticstructdevicefaux_bus_root={/* * .init_name: 初始化时使用的设备名称. * device_register() 函数将使用这个名称来创建 kobject, 也就是 sysfs 中的目录名. */.init_name="faux",};/* * 定义一个静态的、常量类型的 struct bus_type 实例. * 它描述了 "faux" 总线的所有核心属性和行为. * 'const' 表示这个结构体的内容在编译后是只读的. */staticconststructbus_typefaux_bus_type={/* * .name: 总线的名称. 这将会在 sysfs 中创建 /sys/bus/faux 目录. */.name="faux",/* * .match: 一个函数指针, 指向用于判断设备和驱动是否匹配的函数. * 当有新设备或新驱动注册到这个总线时, 内核会调用此函数进行匹配. * 此处指向未提供的 faux_match 函数. */.match=faux_match,/* * .probe: 一个函数指针, 指向总线级别的探测函数. * 在驱动的 probe 函数被调用之前, 总线核心可能会调用此函数进行一些通用的设置. * 此处指向未提供的 faux_probe 函数. */.probe=faux_probe,/* * .remove: 一个函数指针, 指向总线级别的移除函数. * 当设备从总线上移除时调用. * 此处指向未提供的 faux_remove 函数. */.remove=faux_remove,};/* * 定义一个静态的 struct device_driver 实例. * 它代表一个将要注册到 "faux" 总线上的驱动程序. */staticstructdevice_driverfaux_driver={/* * .name: 驱动程序的名称. * 这将会在 /sys/bus/faux/drivers/ 目录下创建名为 "faux_driver" 的条目. */.name="faux_driver",/* * .bus: 一个指针, 指向此驱动所属的总线类型. * 这是将驱动程序与 faux_bus_type 关联起来的关键链接. */.bus=&faux_bus_type,/* * .probe_type: 指定探测类型为强制同步. * 这意味着当设备与此驱动匹配时, 驱动的 probe 函数会立即在当前上下文中被同步调用, * 而不是被推迟到异步的工作队列中. 这可以简化初始化时的依赖关系. */.probe_type=PROBE_FORCE_SYNCHRONOUS,/* * .suppress_bind_attrs: 设置为 true, 禁止在 sysfs 中为此驱动自动创建 "bind" 和 "unbind" 文件. * 这通常用于那些不希望被用户从用户空间手动绑定或解绑的驱动. */.suppress_bind_attrs=true,};/* * faux_bus_init: 模块初始化函数. * __init 宏告诉编译器将此函数放入 ".init.text" 段. * 在内核启动过程完成后, 这个段的内存可以被释放以节省RAM. * @return: 成功时返回 0, 失败时返回负的错误码. */int__initfaux_bus_init(void){/* * 定义一个整型变量 ret, 用于存储函数调用的返回值. */intret;/* * 调用 device_register() 函数注册 faux_bus_root 设备. * 这会在 sysfs 中创建 /sys/devices/faux. */ret=device_register(&faux_bus_root);/* * 检查注册是否失败 (返回值非零). */if(ret){/* * 如果注册失败, 调用 put_device() 来清理已部分初始化的 device 结构体, 释放其引用. */put_device(&faux_bus_root);/* * 返回错误码. */returnret;}/* * 调用 bus_register() 函数注册 faux_bus_type 总线类型. * 这会在 sysfs 中创建 /sys/bus/faux, 并使总线对内核的设备模型可见. */ret=bus_register(&faux_bus_type);/* * 检查注册是否失败. */if(ret)/* * 如果失败, 跳转到 error_bus 标签处进行清理. */gotoerror_bus;/* * 调用 driver_register() 函数注册 faux_driver 驱动程序. * 这会将驱动添加到 faux_bus_type 的驱动列表中, 并创建 /sys/bus/faux/drivers/faux_driver. */ret=driver_register(&faux_driver);/* * 检查注册是否失败. */if(ret)/* * 如果失败, 跳转到 error_driver 标签处进行清理. */gotoerror_driver;/* * 所有步骤都成功, 返回 0. */returnret;/* * 错误处理标签. 当 driver_register 失败时, 从这里开始清理. */error_driver:/* * 调用 bus_unregister() 注销之前成功注册的总线类型. */bus_unregister(&faux_bus_type);/* * 错误处理标签. 当 bus_register 失败时, 从这里开始清理. */error_bus:/* * 调用 device_unregister() 注销之前成功注册的根设备. */device_unregister(&faux_bus_root);/* * 返回导致失败的错误码. */returnret;}

faux_device_create_with_groups / faux_device_create: 创建并注册一个虚拟设备

这两个函数共同提供了一个接口, 用于在内核中创建和注册一个虚拟的 (faux)设备。虚拟设备是纯粹由软件定义的实体, 它们不直接对应任何物理硬件, 但能被无缝地集成到Linux的设备驱动模型中。这使得它们可以拥有自己的驱动程序(通过回调函数实现)、出现在sysfs文件系统中, 并与其他真实设备进行交互。
faux_device_create_with_groups是核心实现, 它允许在创建设备的同时为其定义一组sysfs属性文件。faux_device_create则是一个简化的便利性封装, 用于创建一个不带任何额外sysfs属性的虚拟设备。

  • faux_device_create_with_groups: 创建带sysfs属性的虚拟设备 (核心实现)
/* * faux_device_create_with_groups - 创建一个虚拟设备, 将其注册到驱动核心, * 并为该设备填充一组初始的sysfs属性文件. * * @name: 我们正在添加的设备的名称, 对于所有虚拟设备必须是唯一的. * @parent: 指向一个可能的父设备(struct device)的指针. 如果设置为NULL, * 设备将被创建在sysfs中虚拟设备树的"根"目录下. * @faux_ops: 一个新的设备将回调的 struct faux_device_ops. 可以是NULL. * @groups: 当设备注册到驱动核心时, 将为此设备创建的一组sysfs属性. * * (函数说明省略...) * * 返回值: * * 如果创建设备时发生错误, 返回 NULL. * * 指向一个已在sysfs中注册的、有效的 struct faux_device 的指针. */structfaux_device*faux_device_create_with_groups(constchar*name,structdevice*parent,conststructfaux_device_ops*faux_ops,conststructattribute_group**groups){/* * 定义一个指向 faux_object 结构体的指针. faux_object 是包含 faux_device 和其他元数据的容器. */structfaux_object*faux_obj;/* * 定义一个指向 faux_device 结构体的指针. faux_device 是对标准 device 结构体的封装. */structfaux_device*faux_dev;/* * 定义一个指向标准 device 结构体的指针. 这是Linux内核中所有设备的通用表示. */structdevice*dev;/* * 定义一个整型变量 ret, 用于存储函数调用的返回值(错误码). */intret;/* * 为 faux_object 容器分配内存. kzalloc 会分配内存并将其内容清零. * GFP_KERNEL 表示这是一个常规的内核内存分配, 在需要时可以阻塞(睡眠). */faux_obj=kzalloc(sizeof(*faux_obj),GFP_KERNEL);/* * 如果内存分配失败, kzalloc 返回 NULL. */if(!faux_obj)returnNULL;/* 保存回调函数和属性组, 以便将来使用 */faux_obj->faux_ops=faux_ops;faux_obj->groups=groups;/* 初始化设备部分, 并将其注册到驱动核心 *//* * 获取 faux_obj 中内嵌的 faux_device 结构体的地址. */faux_dev=&faux_obj->faux_dev;/* * 获取 faux_dev 中内嵌的标准 device 结构体的地址. */dev=&faux_dev->dev;/* * 调用 device_initialize, 对标准 device 结构体的成员(如kobject, 锁等)进行初始化. * 这会为设备增加一个引用计数. */device_initialize(dev);/* * 设置设备的 .release 回调函数. 这是至关重要的一步. * 当此设备的最后一个引用被释放时(通过 put_device), 这个函数将被调用以释放 faux_obj 容器的内存, 防止内存泄漏. */dev->release=faux_device_release;/* * 如果调用者提供了父设备, 则设置它. */if(parent)dev->parent=parent;else/* * 否则, 使用虚拟总线的根设备作为父设备. */dev->parent=&faux_bus_root;/* * 将设备的总线类型设置为 faux_bus_type. 这会将设备与虚拟总线关联起来. */dev->bus=&faux_bus_type;/* * 使用调用者提供的名称来设置设备名. 这个名字将显示在sysfs中. */dev_set_name(dev,"%s",name);/* * 调用 device_add, 将设备正式添加到驱动核心. * 这是一个关键步骤, 它会使设备在sysfs中可见, 并触发总线去为它寻找匹配的驱动程序, * 从而导致 faux_ops 中的 .probe 回调函数(如果存在)被同步调用. */ret=device_add(dev);/* * 如果 device_add 失败. */if(ret){/* * 打印一条错误日志. */pr_err("%s: device_add for faux device '%s' failed with %d\n",__func__,name,ret);/* * 调用 put_device 来减少因 device_initialize 增加的引用计数. * 这将触发上面设置的 .release 回调, 从而释放 faux_obj 的内存. */put_device(dev);returnNULL;}/* * 验证我们是否已将驱动绑定到设备上 (即 probe 是否成功). * 如果没有, 我们就让创建失败, 因为调用者几乎不可能判断 probe 是否成功. */if(!dev->driver){/* * 如果 probe 失败 (dev->driver 仍然是 NULL), 则认为创建失败. */dev_dbg(dev,"probe did not succeed, tearing down the device\n");/* * 调用 faux_device_destroy 来清理并注销设备. */faux_device_destroy(faux_dev);/* * 将返回指针设置为 NULL. */faux_dev=NULL;}/* * 返回创建的虚拟设备指针, 如果失败则为 NULL. */returnfaux_dev;}/* * 将 faux_device_create_with_groups 符号导出, 供GPL许可证的模块使用. */EXPORT_SYMBOL_GPL(faux_device_create_with_groups);/** * faux_device_create - 创建一个虚拟设备并将其注册到驱动核心 * * (函数说明省略...) * */structfaux_device*faux_device_create(constchar*name,structdevice*parent,conststructfaux_device_ops*faux_ops){/* * 这是一个便利性封装函数. 它直接调用核心实现函数 faux_device_create_with_groups, * 并将属性组参数(groups)传递为 NULL, 表示不创建任何额外的sysfs属性文件. */returnfaux_device_create_with_groups(name,parent,faux_ops,NULL);}/* * 将 faux_device_create 符号导出, 供GPL许可证的模块使用. */EXPORT_SYMBOL_GPL(faux_device_create);

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询