天天看点

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