Linux设备驱动probe过程(三)
前两周整理了Linux设备驱动probe的一些流程,文章链接如下:
本周把剩下的坑填上,分析下热插拔设备驱动是如何probe的。典型的热插拔设备有PCI和USB。鉴于USB流传度和通用性更广,本文选用USB HOST HID作为分析示例。
本文的章节设计如下:
- USB设备驱动概述。整理了USB驱动架构有哪些基本构成,HID位于架构哪个位置,具体负责什么功能,为接下来HID probe流程的展开做铺垫。
- USB HID设备驱动。讲述以USB鼠标为例,从设备插入到正常工作的过程。
- 多设备驱动probe。介绍DRM架构如何实现多设备依次按顺序完成probe的方法。
1. USB设备驱动概述
本章作为铺垫层,只进行一些和后文有关的概念科普,模型比较单一,不考虑存在集线器情况。
USB设备属于热插拔设备,probe发生在USB设备硬件连接后,当USB设备插入后,会根据usb_device_id
匹配,找到目标usb driver
后,再触发usb设备创建和probe。
USB驱动架构分为Host和Device侧,Host侧作为主机,可以接入多个Device设备(比如键盘、鼠标、U盘),通过发送心跳包维持连接状态。按照USB协议规定,所有USB事务和数据传输都由Host发起,Device没有主动通知Host的能力。
Device设备一般负责单一功能,不过也有些设备(比如USB网卡),可以模拟出多个设备出来(网卡和串口)。
USB驱动结构图如下:
从主机侧的角度来看,需要编写的USB驱动程序包括:主机控制器驱动(USB HCD)和设备驱动(USB Devices Driver)两类,而USB Core作为公共代码和桥梁一般不需要进行额外开发。USB HCD驱动程序控制插入其中的USB设备,而USB Devices驱动程序控制该设备如何作为从设备与主机通信。
1.1 USB HCD主机控制器驱动
从USB Host侧看,处于最底层的是USB HCD(Host Controller Driver)主机控制器驱动,负责控制物理连接usb端口的通信、数据传输、设备插入拔出、电源管理,按协议可分为OHCI/EHCI/UHCI/xHCI:
- UHCI:Intel主导,通用主机控制接口,USB1.0/1.1;
- OHCI:开放主机控制接口,USB1.1;
- EHCI:Intel主导,增强主机控制接口,USB2.0;
- xHCI:可扩展主机控制器接口,最新USB3.0接口,可以兼容USB 1.x/2.0/3.x;
usb_hcd
结构体描述USB主机控制器驱动,它包含USB控制器的"家务"信息、硬件资源、状态描述和用于操作主机控制器的hc_driver等。
1.1.1 dwc3示例(拓展阅读)
USB HCD集成在芯片SOC中,不属于热插拔范畴。USB HCD驱动probe位于kernel_init初始化阶段,dwc3公共代码(drivers/usb/dwc3/core.c)中并不涉及clock、reset pin和power的操作,很多方案会在dwc3外再封装一层driver,用于处理clock、reset pin、power的初始化,对应dwc3_xxx_probe
函数。在完成外部初始化之后,通过of_platform_populate
调用dwc3_probe
,完成phy,irq和工作模式的初始化。驱动调用参考下图:
在dwc3_probe
到dwc3_host_init
调用过程中涉及了1次进程切换,dwc3_host_init
函数完成xhci注册,匹配xhci_plat_probe
进行调用。
xhci_plat_probe
初始化usb总线和phy,调用usb_add_hcd
完成HCD结构体和USB bus/device的添加。
usb_register_bus
注册USB bus,链接到对应usb core中,以便于后续进行bus list扫描和发现设备。
usb_new_device
注册usb设备,并发起设备枚举。
hub_probe
函数初始化root hub,初始化urb和events。
1.2 USB Core驱动
usb core驱动位于drivers/usb/core/usb.c,处于协议中间层,初始化函数usb_init
由subsys_initcall
声明,位于kernel init 4
位置,位于在module_init
之后。USB Core负责USB驱动管理和协议处理的主要工作,包括:
- 通过定义一些数据结构体、宏和功能函数,向上为设备驱动提供编程接口,向下为USB HCD提供编程接口;
- 维护整个系统的USB设备信息;
- 完成设备热插拔控制、总线数据传输控制等。
HCD提供硬件抽象,它只对USB Core一个负责,USB Core将设备驱动的请求映射到相关的HCD,设备驱动不能直接访问HCD,USB Core是HCD与USB设备的唯一桥梁。
USB Core注册了USB总线,USB文件系统,USB Hub以及USB generic设备驱动。
/*
* Init
*/
static int __init usb_init(void)
{
...
retval = bus_register(&usb_bus_type); // 注册USB总线驱动usb_bus_type,创建devices和drivers
if (retval)
goto bus_register_failed;
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); // 创建usb bus通知回调usb_bus_nb
if (retval)