赞
踩
断开该端口设备的连接:如果是root hub,挂接在控制器上的,则断开该端口下的设备。
- if (udev) {
- if (hcd->usb_phy && !hdev->parent)
- usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
- usb_disconnect(&port_dev->child);
- }
处理的是hub上有设备断开的情况。
- if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
- (portchange & USB_PORT_STAT_C_CONNECTION))
- clear_bit(port1, hub->removed_bits);
-
- if (portchange & (USB_PORT_STAT_C_CONNECTION |
- USB_PORT_STAT_C_ENABLE)) {
- status = hub_port_debounce_be_stable(hub, port1);
- if (status < 0) {
- if (status != -ENODEV &&
- port1 != unreliable_port &&
- printk_ratelimit())
- dev_err(&port_dev->dev, "connect-debounce failed\n");
- portstatus &= ~USB_PORT_STAT_CONNECTION;
- unreliable_port = port1;
- } else {
- portstatus = status;
- }
- }
hub port 状态相关的宏定义如下:
-
- /*
- * wPortStatus bit field
- * See USB 2.0 spec Table 11-21
- */
- #define USB_PORT_STAT_CONNECTION 0x0001
- #define USB_PORT_STAT_ENABLE 0x0002
- #define USB_PORT_STAT_SUSPEND 0x0004
- #define USB_PORT_STAT_OVERCURRENT 0x0008
- #define USB_PORT_STAT_RESET 0x0010
- #define USB_PORT_STAT_L1 0x0020
- /* bits 6 to 7 are reserved */
- #define USB_PORT_STAT_POWER 0x0100
- #define USB_PORT_STAT_LOW_SPEED 0x0200
- #define USB_PORT_STAT_HIGH_SPEED 0x0400
- #define USB_PORT_STAT_TEST 0x0800
- #define USB_PORT_STAT_INDICATOR 0x1000
- /* bits 13 to 15 are reserved */
对应usb2.0 协议 Hub端口状态标志位如协议中的 表11-21
由上表可知道:
bit0表示连接状态,1 是有设备连接,0 是没有设备连接。bit1表示端口被使能还是禁止工作,1 是被使能,0 是禁止工作状态。bit 2表示挂起状态,0 是没有被挂起,1 是被挂起。bit3 表示端口过电流,0 是没有过电流,1 是发生了过电流。bit4 表示是否重启了,0没有收到重启命令,1 是收到了重启命令。bit5~bit7 未使用。bit8 表示端口供电情况,1 是处于power off 状态,0 是出于power on状态。bit9 表示是设备的速度类型,0 是全速或者高速设备接入该端口,1 是低速设备接入。bit10 表示设备速度类型,0 表示全速设备接入,1是高速设备接入。bit11 表示该端口是否处于测试模式,0 不是,1 处于测试模式。bit12 该端口指示灯控制,0是默认颜色,1是软件控制的颜色。bit13~bit15 未启用。
要读懂上面的程序,除了知道Hub 端口的状态标志位的含义还不行,还得知道Hub 端口发生改变的标志位,摘自协议中的表11-22
bit0 表示状态发生了改变,是什么改变,不知道,也许是断开,也许是设备接入,1 表示改变了,0是没有改变,结合协议中的表11-21中的bit0判定是设备接入还是断开。bit1 表示端口使能/禁用的改变,当端口由于错误引起禁用时被置1。bit2 挂起状态的改变,该位是以host的视角来看设备的状态,0 是没有改变,1是从挂起恢复了。bit3 过电流指示,如果过电流,在hub的描述符中表示出来,0 是过电流发生且没有改善,1过电流指示消除。bit4表示重启状态,0 表示没有改变端口的状态,1表示重启完成。其余bit保留。在代码里对应的code为:
- /*
- * wPortChange bit field
- * See USB 2.0 spec Table 11-22 and USB 2.0 LPM ECN Table-4.10
- * Bits 0 to 5 shown, bits 6 to 15 are reserved
- */
- #define USB_PORT_STAT_C_CONNECTION 0x0001
- #define USB_PORT_STAT_C_ENABLE 0x0002
- #define USB_PORT_STAT_C_SUSPEND 0x0004
- #define USB_PORT_STAT_C_OVERCURRENT 0x0008
- #define USB_PORT_STAT_C_RESET 0x0010
- #define USB_PORT_STAT_C_L1 0x0020
- /*
上面这段代码翻译过来就是:如果有设备断开或者设备连接情况发生了改变,都清除hub的remove bits。如果设备连接情况发生了改变且端口是被使能的,那么先去抖;消除抖动,接入或拔出时,会有物理抖动,导致状态不稳定,所以需要消抖。消抖后如果设备移除了,设置hub feature等清理工作。
根据速度设置hub设备总线电流的阈值
- if (hub_is_superspeed(hub->hdev))
- unit_load = 150;
- else
- unit_load = 100;
- for (i = 0; i < SET_CONFIG_TRIES; i++) {
-
- /* reallocate for each attempt, since references
- * to the previous one can escape in various ways
- */
- udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配usb设备内存并初始化bus、type、group、设备在系统中的路径(dev->path)、ep0的属性并设置设备状态为attached。
- //这里有一个疑问:设备中端点0是没有描述符的,但是这里有初始化ep0.desc的代码,是软件层面对ep0有单独的描述吗?
- if (!udev) {
- dev_err(&port_dev->dev,
- "couldn't allocate usb_device\n");
- goto done;
- }
-
- usb_set_device_state(udev, USB_STATE_POWERED); //设置为 power状态,并设置电源等。
- udev->bus_mA = hub->mA_per_port;
- udev->level = hdev->level + 1;
- udev->wusb = hub_is_wusb(hub);
-
- /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
- if (hub_is_superspeed(hub->hdev)) //判断速度是否为高速
- udev->speed = USB_SPEED_SUPER;
- else
- udev->speed = USB_SPEED_UNKNOWN;
-
- choose_devnum(udev); //从USB总线的编号数组中找到一个合适的编号,为设备分配地址做好准备。
- if (udev->devnum <= 0) {
- status = -ENOTCONN; /* Don't retry */
- goto loop;
- }
-
- /* reset (non-USB 3.0 devices) and get descriptor */
- usb_lock_port(port_dev);
- status = hub_port_init(hub, udev, port1, i); //初始化设备,设置地址,读取设备描述符
- usb_unlock_port(port_dev);
- if (status < 0)
- goto loop;
-
- if (udev->quirks & USB_QUIRK_DELAY_INIT)
- msleep(2000);
-
- /* consecutive bus-powered hubs aren't reliable; they can
- * violate the voltage drop budget. if the new child has
- * a "powered" LED, users should notice we didn't enable it
- * (without reading syslog), even without per-port LEDs
- * on the parent.
- */
- if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
- && udev->bus_mA <= unit_load) {
- u16 devstat;
-
- status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
- &devstat);
- if (status) {
- dev_dbg(&udev->dev, "get status %d ?\n", status);
- goto loop_disable;
- }
- if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
- dev_err(&udev->dev,
- "can't connect bus-powered hub "
- "to this port\n");
- if (hub->has_indicators) {
- hub->indicator[port1-1] =
- INDICATOR_AMBER_BLINK;
- queue_delayed_work(
- system_power_efficient_wq,
- &hub->leds, 0);
- }
- status = -ENOTCONN; /* Don't retry */
- goto loop_disable;
- }
- }
-
- /* check for devices running slower than they could */
- if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
- && udev->speed == USB_SPEED_FULL
- && highspeed_hubs != 0)
- check_highspeed(hub, udev, port1);
-
- /* Store the parent's children[] pointer. At this point
- * udev becomes globally accessible, although presumably
- * no one will look at it until hdev is unlocked.
- */
- status = 0;
-
- mutex_lock(&usb_port_peer_mutex);
-
- /* We mustn't add new devices if the parent hub has
- * been disconnected; we would race with the
- * recursively_mark_NOTATTACHED() routine.
- */
- spin_lock_irq(&device_state_lock);
- if (hdev->state == USB_STATE_NOTATTACHED)
- status = -ENOTCONN;
- else
- port_dev->child = udev;
- spin_unlock_irq(&device_state_lock);
- mutex_unlock(&usb_port_peer_mutex);
-
- /* Run it through the hoops (find a driver, etc) */
- if (!status) {
- status = usb_new_device(udev); //读取、解析配置描述符,解析端点描述符
- if (status) {
- mutex_lock(&usb_port_peer_mutex);
- spin_lock_irq(&device_state_lock);
- port_dev->child = NULL;
- spin_unlock_irq(&device_state_lock);
- mutex_unlock(&usb_port_peer_mutex);
- } else {
- if (hcd->usb_phy && !hdev->parent)
- usb_phy_notify_connect(hcd->usb_phy,
- udev->speed);
- }
- }
-
- if (status)
- goto loop_disable;
-
- status = hub_power_remaining(hub);
- if (status)
- dev_dbg(hub->intfdev, "%dmA power budget left\n", status);
-
- printk(KERN_EMERG"pompey hub: %s %d status:%d\n",__func__,__FUNCTION__,status);
- return;
-
- printk(KERN_EMERG"pompey hub: %s %d status:%d\n",__func__,__FUNCTION__,status);
- loop_disable:
- hub_port_disable(hub, port1, 1);
- loop:
- usb_ep0_reinit(udev);
- release_devnum(udev);
- hub_free_dev(udev);
- usb_put_dev(udev);
- if ((status == -ENOTCONN) || (status == -ENOTSUPP))
- break;
-
- /* When halfway through our retry count, power-cycle the port */
- if (i == (SET_CONFIG_TRIES / 2) - 1) {
- dev_info(&port_dev->dev, "attempt power cycle\n");
- usb_hub_set_port_power(hdev, hub, port1, false);
- msleep(2 * hub_power_on_good_delay(hub));
- usb_hub_set_port_power(hdev, hub, port1, true);
- msleep(hub_power_on_good_delay(hub));
- }
- }
经过一系列的操作,设备就清清楚楚的被host了解了,是什么设备(设备描述符、配置描述符)、有什么功能(接口描述符)、怎么传数据(端点描述符)都明明白白了。
for (i = 0; i < SET_CONFIG_TRIES; i++)
......
这里的目的就是多试几次,以防失败。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。