1. USB固件
USB设备中有一个模块叫固件,固件是固化在集成电路内部的程序代码,USB固件中包含了USB设备的出厂信息,标识该设备的厂商ID、产品ID、主版本号和次版本号等。另外固件中还包含一组程序,这组程序主要完成USB协议的处理和设备的读写操作,USB设备固件和USB驱动之间通信的规范是通过USB协议来完成的。
2. USB device识别过程
定时轮询方式,当定时时间到了,运行定时器rh_timer的function函数rh_timer_func。
使用定时器查询的主要原因是USB没有中断USB控制器的能力,所以当USB设备接入之后,获取USB输入的信息是无法通过中断方式来获取,只能通过定时器定时轮训获取。
->rh_timer_func //usb/core/hcd.c
->usb_hcd_poll_rh_status
->hcd->driver->hub_status_data(hcd, buffer)
->usb_hcd_unlink_urb_from_ep(hcd, urb);
->usb_hcd_giveback_urb(hcd, urb, 0)
->usb_giveback_urb_bh(); //tasklet_hi_schedule(&bh->bh);
->__usb_hcd_giveback_urb(urb);
->urb->complete(urb); //hub_irq
->hub_irq //hub.c usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
->kick_hub_wq(hub);
->hub_event //INIT_WORK(&hub->events, hub_event);
->port_event(hub, i);
->hub_port_connect_change
->hub_port_connect
->hub_port_init
->usb_new_device(udev);
->usb_enumerate_device(udev);//开始枚举
->device_add(&udev->dev);//枚举完毕后加载设备驱动
3. USB device的枚举过程
内核辅助线程khubd用来监视与该集线器连接的所有端口,通常情况下,该线程处于休眠状态,当集线器驱动程序检测到USB端口状态变化后,该内核线程立马唤醒。
USB的枚举过程:USB的枚举过程是热插拔USB设备的起始步骤,该过程中,主机控制器获取设备的相关信息并配置好设备,集线器驱动程序负责该枚举过程。枚举过程主要分如下几步:
Step1:根集线器报告插入设备导致的端口电流变化,集线器驱动程序检测到这一状态变化后,唤醒khubd线程。
Step2:khubd识别出电流变化的那个端口。
Step3:khubd通过给控制端点0发送控制URB来实现从1-127中选出一个数作为插入设备的批量端点。
Step4:khubd利用端口0使用的控制URB从插入的设备那里获得设备描述符,然后获得配置描述符,并选择一个合适的。
Step5:khubd请求USB核心把对应的客户驱动程序和该USB设备挂钩。
Step4对应usb_enumerate_device(udev)函数
Step5对应device_add(&udev->dev)函数
所以,如果USB设备被正常识别(即枚举过程中成功读取到了USB设备的厂商信息)以后,就会根据设备中的厂商信息调用具体USB设备的驱动程序,比如U盘就会调用U盘的驱动程序。
4. USB driver
在USB device枚举完成之后通过device_add(&udev->dev)将usb device挂载到usb总线上,然后调用usb总线的match函数匹配usb_device和usb_driver,usb_bus_type总线的match函数对两类设备区别对待,usb_device和usb_device_driver配对,而usb_interface和usb_driver配对。
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
};
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { /*hub创建的usb_device和 usb_generic_driver 匹配走这个分支*/
/* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;
/* TODO: Add real matching code */
return 1;
} else if (is_usb_interface(dev)) {/* usb_interface 和 usb_driver匹配走这个分支 */
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
if (is_usb_device_driver(drv))
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
}
return 0;
}
static inline int is_usb_device(const struct device *dev)
{
return dev->type == &usb_device_type;
}
static inline int is_usb_interface(const struct device *dev)
{
return dev->type == &usb_if_device_type;
}
整个usb子系统只定义了一个struct usb_device_driver驱动,它定义在drivers/usb/core/generic.c文件中,在usb_init中注册,所以HUB会和usb_generic_driver匹配并调用其probe函数。
//drivers/usb/core/usb.c
static int __init usb_init(void)
{
int retval;
usb_init_pool_max();
retval = usb_debugfs_init();
usb_acpi_register();
retval = bus_register(&usb_bus_type);
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
retval = usb_major_init();
retval = usb_register(&usbfs_driver);
retval = usb_devio_init();
retval = usb_hub_init();
//向usb核心注册这个usb_device_driver驱动
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
usb_hub_cleanup();
return retval;
}
subsys_initcall(usb_init);
//drivers/usb/core/generic.c
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
搜索usb_driver就有很多了,比如鼠标,键盘,u盘,usb转串口,音频,视频等各种各种的设备,usb_driver通过usb_register函数注册。