ARM64 Linux 6.10 内核驱动(13):bus.c / driver.c 总线两张表,驱动怎么挂上去

§1.2 bus.c / driver.c:总线两张表,驱动怎么挂上去

平台:QEMU virt + ARM64。这两份是驱动模型的模板胶水,不是 UART 业务。


1. 这是模板,不是业务

device_registerbus_registerdriver_register 写法同一套路:

复制代码
门禁(对象在不在、重名没有)
  → 入表(klist)
  → 自动配对(probe / attach)
  → sysfs / uevent
出错则回滚

和业务代码的「校验 → 入库 → 发事件」很像。清单读它们是为了认骨架。

业务填在槽里:

模板 virt 上的业务
bus_type.match platform_matchcompatible
bus_type.probe platform_probeplatform_driver.probe
driver_register 你的 .ko / module_platform_driver

driver_register 里那条 pr_warn:总线已经有 .probe 时不要再填 device_driver.probecall_driver_probe 优先 bus->probe,你的会被忽略)。platform 正确写法是 platform_driver.probe,由 platform_probe 转发。


2. 两张表在哪(匹配用 klist,不是 sysfs)

每条总线的内核私有数据是 struct subsys_privatedrivers/base/base.h)。对外的 struct bus_type 是 const 描述(名字、函数指针);能挂节点的链表在 priv 上。bus_to_subsys(bus) 把二者连起来。

复制代码
struct subsys_private {
	struct kset *devices_kset;   // /sys/bus/<名>/devices
	struct kset *drivers_kset;   // /sys/bus/<名>/drivers
	struct klist klist_devices;  // ★ 设备表
	struct klist klist_drivers;  // ★ 驱动表
	unsigned int drivers_autoprobe:1;
	...
};

bus_registerklist_init 这两张。

链表 谁挂 谁扫 含义
klist_devices bus_add_device bus_for_each_dev 这条总线上有哪些设备
klist_drivers bus_add_driver bus_for_each_drv 这条总线上有哪些驱动

第三张表 在每个驱动上:drv->p->klist_devicesbus_add_driver 里初始化为空,driver_bound(probe 成功)才往里挂driver_for_each_device / driver_detach 扫的是它,不是总线设备表。

sysfs 是给人看的镜像,内核 match 不读 /sys

复制代码
/sys/bus/platform/devices/   ← 符号链接
/sys/bus/platform/drivers/

bus_add_deviceklist_addsysfs_create_link,不要把目录当成匹配表。


3. bus_register:先有容器

virt 上 platform_bus_register() 启动早期调用,bus->name"platform"

做完三件清单相关的事:

  1. /sys/bus/<name> 出现(挂在 buses_init 建的 bus_kset / /sys/bus 下)
  2. devices / drivers 两个 kset,以及两张空 klist
  3. drivers_autoprobe = 1:以后 device_add 会自动 bus_probe_devicedriver_register 会自动 driver_attach

.match / .probe 不在这里填 ,已经写在 platform_bus_type 上。本函数不往表里塞设备或驱动。


4. 设备入表 / 出表

4.1 bus_add_devicedevice_add 调用)

  1. 总线默认属性(bus->dev_groups
  2. /sys/bus/<bus>/devices/<名> → 设备 kobj;设备下 subsystem/sys/bus/<bus>
  3. klist_add_tail(&dev->p->knode_bus, &sp->klist_devices)

没有 dev->bus 直接返回 0(不少纯 class 设备)。

这里还不 probe

4.2 bus_probe_device(仍由 device_add 调用,在入表之后)

不是再登记一张表。 设备已经在 klist_devices 里,这里是:去驱动表里找对象。

复制代码
if (sp->drivers_autoprobe)
    device_initial_probe(dev);   // 进 dd.c,扫 klist_drivers

后面的 subsys_interface->add_dev 是观察者,不是 platform_driver.probe

-EPROBE_DEFER 重试:deferred_probe_work_func 再调本函数,把链重走一遍。

关掉 autoprobe:设备在表里、sysfs 也有,但不自动 probe

4.3 bus_remove_devicedevice_del 调用)

bus_add_device 的逆过程,并且解绑驱动:

  1. 拆符号链接和属性
  2. klist_del 离开 klist_devices
  3. device_release_driverdd.cdevice_remove

两次 subsys_put:一次抵本函数的 bus_to_subsys,一次抵 bus_add_device 时拿的引用。


5. 驱动入表 / 出表

5.1 driver_registerdriver.c,对外入口)

platform_driver_register 先设 drv->bus = &platform_bus_type,再进这里。本函数只做门禁,活在 bus_add_driver

  • 总线必须已经 bus_register
  • 同名驱动不能重复(driver_find
  • bus_add_driver → 驱动 groupsKOBJ_ADD uevent
  • deferred_probe_extend_timeout:模块刚加载,给还在 defer 的设备多一点重试时间

5.2 bus_add_driver

  1. 分配 driver_private,kobj 放到 drivers_kset/sys/bus/<bus>/drivers/<名>
  2. 初始化 第三张表 priv->klist_devices(此时空)
  3. klist_add_tail(..., &sp->klist_drivers)
  4. drivers_autoprobedriver_attach(drv)dd.c:扫 klist_devices,对已有设备 match/probe)

insmod 你的 .ko 时,virt 上 DT 设备往往已经 device_add 过,走的就是第 4 步。

sysfs bind/unbind 文件清单可跳过。

5.3 driver_unregisterbus_remove_driver

  1. klist_remove 离开 klist_drivers(新 device_add 再也 match 不到这个驱动)
  2. driver_detach:扫 drv->p->klist_devices ,对每台已绑定设备 device_release_driver

不要和 bus_remove_device 搞反:那边拆一台设备;这边拆一个驱动(可能绑着多台设备)。


6. 两把刷子:bus_for_each_dev / bus_for_each_drv

不是「抽象设备 vs 驱动表」。同一条总线上两张平级的表,各扫一张。回调返回非 0 停扫。

时机 用谁 含义
设备后到(device_addbus_probe_device__device_attach bus_for_each_drv 这一台设备,对每个已有 driver match
驱动后到(insmoddriver_attach bus_for_each_dev 这一个 driver,对每个已有 device match

这就是清单「bus / device / driver 三段如何匹配」的骨架。字符串怎么比,仍是 drv->bus->match → virt 上 platform_match


7. 整条链(virt)

复制代码
buses_init                          /sys/bus
  → bus_register(platform_bus_type) 两张空表,autoprobe=1

设备侧(DT → platform_device):
  device_add
    → bus_add_device        入 klist_devices
    → bus_probe_device      扫 klist_drivers → dd.c probe

驱动侧(你的 platform_driver / 内核里已编进的驱动):
  driver_register
    → bus_add_driver        入 klist_drivers
    → driver_attach         扫 klist_devices → dd.c probe

谁先谁后都能碰上。写错 compatible:入表仍成功,卡在 platform_match,不 probe


8. driver.c 其余接口

清单不用精读:

  • driver_for_each_device / driver_find_device:扫第三张表
  • driver_create_file / driver_add_groups:驱动 kobj 的 sysfs 工具
  • driver_set_override:强制指定绑哪个驱动

相关推荐
六点_dn2 小时前
线上踩坑:Binlog重放,线上服务未停止导致主键冲突
linux·运维·服务器
持敬chijing2 小时前
CentOS 从零搭建 LAMP 环境完整实战指南
linux·运维·web安全·网络安全·centos
赋创小助手2 小时前
多GPU服务器交付验收:GPU健康、P2P、NCCL与稳定性测试思路
运维·服务器·人工智能·ai·部署·gpu·p2p
xiaoye-duck2 小时前
《Linux 网络编程》深入理解 TCP 协议(三):TCP 报头六大标志位详解
linux·网络·tcp
码行山野赴时序归途2 小时前
顺序表(Sequential List)详解:从数组到 C 语言实现
c语言·开发语言·数据结构·算法
Android系统攻城狮2 小时前
Linux Gstreamer深度解析之gst_audio_channel_positions_to_mask调用流程与实战(十七)
linux·运维·服务器·gstreamer音视频·音视频进阶
hanbo17C22 小时前
企业官网能不能看出公司实力?选建站公司前,先看这6条硬标准
运维·服务器·前端
33三 三like2 小时前
Jiangxi
linux·运维·服务器
linx2952 小时前
单元七 · 零基础路线图-第 1–3 周·变量、类型与字符串
c语言·开发语言·数据结构·c++·算法