介紹USB系統架構,隻關注架構部分,不涉及細節
USB裝置注冊過程
usb_add_hcd -> register_root_hub -> usb_new_device -> device_add(添加裝置) ->
usb_device_match(驅動比對) -> generic_probe -> usb_set_configuration -> device_add(添加接口) ->
usb_device_match(ID 比對) -> usb接口驅動的probe
USB初始化
usb_int
usb_int初始化整個usb系統的基礎部分
注冊USB總線
bus_register(&usb_bus_type);
注冊usbfs驅動
usb_register(&usbfs_driver);
注冊usb hub驅動
usb_hub_init -> usb_register(&hub_driver)
注冊通用裝置驅動
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)
host總線初始化
以msm ehci為例
初始化echi驅動資料結構
ehci_init_driver(&msm_hc_driver, &msm_overrides);
使用ehci_hc_driver資料結構為基礎
建立hcd
1
2hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
其中msm_hc_driver在上一步初始化,以ehci_hc_driver為基礎
重點:hcd->self是一條usb總線
1
2
3struct usb_hcd {
struct usb_busself;
......
添加hcd到系統中
usb_add_hcd(hcd, hcd->irq, IRQF_SHARED)
向usb系統中注冊一條總線
usb_register_bus(&hcd->self))
建立一個USB裝置,作為根hub
rhdev = usb_alloc_dev(NULL, &hcd->self, 0)
hcd->self.root_hub = rhdev
詳見:usb裝置建立
為該總線注冊根hub
register_root_hub(hcd)
根hub注冊過程
擷取根hub的描述資訊
usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
向usb系統中添加了一個usb裝置:usb_new_device (usb_dev);
該裝置是上一步建立的根hub裝置struct usb_device \usb_dev = hcd->self.root_hub;*
usb裝置建立
usb_alloc_dev(struct usb_device parent,
struct usb_busbus, unsigned port1)
裝置類型:
1
2
3
4
5
6dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
...
if (unlikely(!parent)) {
root_hub = 1;
}
裝置路徑&裝置名字:
根hub:很簡單,路徑為”0”, 名字直接是總線編号
dev->devpath[0] = ‘0’;
dev_set_name(&dev->dev, “usb%d”, bus->busnum);
普通裝置
hub裝置自身(父裝置為根hub):路徑為端口編号
snprintf(dev->devpath, sizeof dev->devpath, “%d”, port1);
普通裝置(父裝置為hub裝置):路徑為hub路徑+端口編号
snprintf(dev->devpath, sizeof dev->devpath,”%s.%d”, parent->devpath, port1);
裝置名字:總線編号 + 裝置路徑
dev_set_name(&dev->dev, “%d-%s”, bus->busnum, dev->devpath);
usb添加裝置
int usb_new_device(struct usb_device *udev)
USB枚舉裝置
usb_enumerate_device(udev)
擷取USB配置:usb_get_configuration(udev)
顯示usb裝置資訊
announce_device(udev);
添加裝置
device_add(&udev->dev)
重點:會觸發probe
建立endpoint裝置
usb_create_ep_devs(&udev->dev, &udev->ep0, udev)
1
2
3
4
5
6ep_dev->udev = udev;
ep_dev->dev.groups = ep_dev_groups;
ep_dev->dev.type = &usb_ep_device_type;
ep_dev->dev.parent = parent;
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
device_register(&ep_dev->dev);
usb probe過程查找驅動
usb_device_match
usb裝置probe:generic_probe
選擇配置:usb_choose_configuration
設定配置:usb_set_configuration (重點)
usb接口probe:
配置id表:usb驅動的id_tableusb_match_id(intf, usb_drv->id_table)動态比對(非常有用)
usb 動态比對表
usb probe過程中,優先使用靜态表(代碼中寫死,編譯後不可更改),如果靜态表中沒有目前裝置(usb 接口)則使用動态表
動态表由應用層寫入
路徑:/sys/bus/usb/driver/\/new_id
格式:\\[InterfaceClass [refVendor refProduct]]
usb 設定配置
usb_set_configuration
周遊目前配置的接口(通過usb_get_configuration從usb裝置擷取)
1
2
3
4
5intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
周遊目前配置的接口
添加接口:device_add(&intf->dev)
重點:會觸發probe
hub初始化過程添加usb接口時(device_add)觸發probe,如果接口是hub,則執行hub_probe
hub的比對表:USB_CLASS_HUB=91
2
3
4
5
6
7
8
9
10
11
12static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR //指定産商的hub
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, //裝置為hub
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, //接口為hub
.bInterfaceClass = USB_CLASS_HUB},
{ }
};
hub_probe
建立1個hub,配置hub(重點)
1
2
3
4
5hub = kzalloc(sizeof(*hub), GFP_KERNEL)
...
INIT_WORK(&hub->events, hub_event);
usb_set_intfdata (intf, hub);
hub_configure(hub, endpoint)
hub_event是重點
配置hub
hub_configure(struct usb_hub hub, struct usb_endpoint_descriptorendpoint)
擷取hub的描述
get_hub_descriptor(hdev, hub->descriptor)
擷取hub裝置的狀态
usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus)
擷取hub的狀态
hub_hub_status(hub, &hubstatus, &hubchange)
get_hub_status(hub->hdev, &hub->status->hub)
建立端口裝置
1
2
3
4
5
6
7
8for (i = 0; i < maxchild; i++) {
ret = usb_hub_create_port_device(hub, i + 1);
if (ret < 0) {
dev_err(hub->intfdev,
"couldn't create port%d device.\n", i + 1);
break;
}
}
1
2
3
4
5
6port_dev->dev.groups = port_dev_group;
port_dev->dev.type = &usb_port_device_type;
port_dev->dev.driver = &usb_port_driver;
dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
port1);
retval = device_register(&port_dev->dev);
建立的端口在/sys/bus/usb/device/下可見
hub事件處理
hub_event
處理hub下每個端口的事件
1
2
3
4for (i = 1; i <= hdev->maxchild; i++) {
...
port_event(hub, i);
}
port_event
擷取端口狀态:hub_port_status(hub, port1, &portstatus, &portchange)
端口連接配接事件發生變化時,執行hub_port_connect_change
hub端口連接配接事件
hub_port_connect_change->hub_port_connect
端口下有裝置,則先移除
1
2
3
4
5if (udev) {
if (hcd->usb_phy && !hdev->parent)
usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
usb_disconnect(&port_dev->child);
}
建立一個usb裝置
udev = usb_alloc_dev(hdev, hdev->bus, port1)
初始化hub port
hub_port_init(hub, udev, port1, i);
擷取裝置描述:usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE)
添加usb裝置
status = usb_new_device(udev);