天天看點

linux usb host,linux USB host驅動

介紹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);