一、USB总线
系统启动-》初始化usb子系统-》向内核注册USB总线-》向USB总线中注册3个usb驱动(分别是USB插口驱动、HUB驱动、USB设备驱动)。
主机驱动注册为platform平台驱动-》先遍历平台总线的设备数组,执行platform的.match函数(platform_match)进行匹配,成功后执行.probe函数(ohci_hcd_s3c2410_drv_probe)-》在此函数中再遍历usb总线的驱动数组,执行.match函数(usb_device_match),成功后执行.probe函数(预先注册的3个usb驱动)-》检测其他usb设备拔插。。。
//----------------------------------------USBBUS------------------------------------
【USB总线注册】
//usb_bus_type提供了驱动和设备匹配的匹配函数
retval = bus_register(&usb_bus_type);
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match, // 内部会将 设备驱动 和 接口驱动 分开匹配(提高效率)
... ...
};
//使用bus_register插口注册USB总线,会创建出两条数组拿来分别储存向USB总线注册的设备和驱动。
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&bus->klist_drivers, NULL, NULL);
1、在usb总线注册USB插口驱动,该驱动被置于usb总线的驱动数组中。(一个设备可以注册多个插口驱动)
//注册usbfs插口驱动,提供了在用户空间直接访问USB硬件设备的插口,完成USB设备在用户空间的映射
retval = usb_register(&usbfs_driver);
struct usb_driver usbfs_driver = {
.name = "usbfs",
.probe = driver_probe, // .match成功后,执行
.disconnect = driver_disconnect,
... ...
};
2、在usb总线注册一个hub插口驱动,该驱动被置于usb总线的驱动数组中。
retval = usb_register(&hub_driver);
khubd_task = kthread_run(hub_thread, NULL, "khubd");// 创建一个死循环线程hub_thread,用来处理USB设备的断开、连接等事件
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe, // 通过usb_fill_int_urb创建urb请求块同时注册了一个中断处理函数hub_irq,用来唤醒hub_thread线程来处理USB设备事件(热插拔)
.disconnect = hub_disconnect,
... ...
};
3、在usb总线注册通用USB设备驱动linux usb 驱动,该驱动被置于usb总线的驱动数组中。
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe, // 通用USB设备匹配成功后执行
.disconnect = generic_disconnect,
... ...
};
二、USB主机驱动
【主机驱动器HCD】——platform模型
USBHCD注册在平台总线上。拿来处理主机控制器的初始化以及数据的传输,并检测外部设备插入、拔出,完成设备枚举。
1、设备(或则采用设备树描述)
struct platform_device s3c_device_usb = {
.name = "s3c2410-ohci",
.resource = s3c_usb_resource
... ...
};
platform_add_devices(); // 注册设备信息
2、主机驱动注册
retval = platform_driver_register(&ohci_hcd_s3c2410_driver); //内部会调用platform_match 进行驱动-设备匹配
struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-ohci",
},
... ...
};
3、平台总线:此处的platform总线(虚拟总线)完成USB主机控制器的驱动和设备匹配.
USBBUS的USB总线是完成设备驱动与设备信息的匹配.
struct bus_type platform_bus_type = {
.name = "platform",
.match = platform_match,
... ...
};
调用platform_driver_register函数注册主机控制器驱动后,遍历平台总线的设备数组,调用platform_match进行设备-驱动匹配linux命令tar红旗linux桌面版,匹配上后会调用驱动的ohci_hcd_s3c2410_drv_probe函数。
ohci_hcd_s3c2410_drv_probe流程解析:遍历usb总线的驱动数组,调用usb_device_match进行匹配(第一节的USB总线)linux usb 驱动,匹配成功后执行设备驱动的.probe函数。如执行USB通用设备驱动函数generic_probe。
//-------------------------------------------------------------------------------------------------------
驱动开发中,所有注册的USB设备,都是向USB总线注册,由USB总线实现驱动-设备的匹配。
入门级的设备驱动程序可以看下篇文章的剖析——内核键盘驱动源码。