当前位置:   article > 正文

USB 设备驱动之设备接入梳理_hub_port_connect()函数(三)

hub_port_connect

hub_port_connect()函数

断开该端口设备的连接:如果是root hub,挂接在控制器上的,则断开该端口下的设备。

  1. if (udev) {
  2. if (hcd->usb_phy && !hdev->parent)
  3. usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
  4. usb_disconnect(&port_dev->child);
  5. }

处理的是hub上有设备断开的情况。

  1. if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
  2. (portchange & USB_PORT_STAT_C_CONNECTION))
  3. clear_bit(port1, hub->removed_bits);
  4. if (portchange & (USB_PORT_STAT_C_CONNECTION |
  5. USB_PORT_STAT_C_ENABLE)) {
  6. status = hub_port_debounce_be_stable(hub, port1);
  7. if (status < 0) {
  8. if (status != -ENODEV &&
  9. port1 != unreliable_port &&
  10. printk_ratelimit())
  11. dev_err(&port_dev->dev, "connect-debounce failed\n");
  12. portstatus &= ~USB_PORT_STAT_CONNECTION;
  13. unreliable_port = port1;
  14. } else {
  15. portstatus = status;
  16. }
  17. }

hub port 状态相关的宏定义如下:

  1. /*
  2. * wPortStatus bit field
  3. * See USB 2.0 spec Table 11-21
  4. */
  5. #define USB_PORT_STAT_CONNECTION 0x0001
  6. #define USB_PORT_STAT_ENABLE 0x0002
  7. #define USB_PORT_STAT_SUSPEND 0x0004
  8. #define USB_PORT_STAT_OVERCURRENT 0x0008
  9. #define USB_PORT_STAT_RESET 0x0010
  10. #define USB_PORT_STAT_L1 0x0020
  11. /* bits 6 to 7 are reserved */
  12. #define USB_PORT_STAT_POWER 0x0100
  13. #define USB_PORT_STAT_LOW_SPEED 0x0200
  14. #define USB_PORT_STAT_HIGH_SPEED 0x0400
  15. #define USB_PORT_STAT_TEST 0x0800
  16. #define USB_PORT_STAT_INDICATOR 0x1000
  17. /* 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为:

  1. /*
  2. * wPortChange bit field
  3. * See USB 2.0 spec Table 11-22 and USB 2.0 LPM ECN Table-4.10
  4. * Bits 0 to 5 shown, bits 6 to 15 are reserved
  5. */
  6. #define USB_PORT_STAT_C_CONNECTION 0x0001
  7. #define USB_PORT_STAT_C_ENABLE 0x0002
  8. #define USB_PORT_STAT_C_SUSPEND 0x0004
  9. #define USB_PORT_STAT_C_OVERCURRENT 0x0008
  10. #define USB_PORT_STAT_C_RESET 0x0010
  11. #define USB_PORT_STAT_C_L1 0x0020
  12. /*

上面这段代码翻译过来就是:如果有设备断开或者设备连接情况发生了改变,都清除hub的remove bits。如果设备连接情况发生了改变且端口是被使能的,那么先去抖;消除抖动,接入或拔出时,会有物理抖动,导致状态不稳定,所以需要消抖。消抖后如果设备移除了,设置hub feature等清理工作。

根据速度设置hub设备总线电流的阈值

  1. if (hub_is_superspeed(hub->hdev))
  2. unit_load = 150;
  3. else
  4. unit_load = 100;

 

  1. for (i = 0; i < SET_CONFIG_TRIES; i++) {
  2. /* reallocate for each attempt, since references
  3. * to the previous one can escape in various ways
  4. */
  5. udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配usb设备内存并初始化bus、type、group、设备在系统中的路径(dev->path)、ep0的属性并设置设备状态为attached。
  6. //这里有一个疑问:设备中端点0是没有描述符的,但是这里有初始化ep0.desc的代码,是软件层面对ep0有单独的描述吗?
  7. if (!udev) {
  8. dev_err(&port_dev->dev,
  9. "couldn't allocate usb_device\n");
  10. goto done;
  11. }
  12. usb_set_device_state(udev, USB_STATE_POWERED); //设置为 power状态,并设置电源等。
  13. udev->bus_mA = hub->mA_per_port;
  14. udev->level = hdev->level + 1;
  15. udev->wusb = hub_is_wusb(hub);
  16. /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
  17. if (hub_is_superspeed(hub->hdev)) //判断速度是否为高速
  18. udev->speed = USB_SPEED_SUPER;
  19. else
  20. udev->speed = USB_SPEED_UNKNOWN;
  21. choose_devnum(udev); //从USB总线的编号数组中找到一个合适的编号,为设备分配地址做好准备。
  22. if (udev->devnum <= 0) {
  23. status = -ENOTCONN; /* Don't retry */
  24. goto loop;
  25. }
  26. /* reset (non-USB 3.0 devices) and get descriptor */
  27. usb_lock_port(port_dev);
  28. status = hub_port_init(hub, udev, port1, i); //初始化设备,设置地址,读取设备描述符
  29. usb_unlock_port(port_dev);
  30. if (status < 0)
  31. goto loop;
  32. if (udev->quirks & USB_QUIRK_DELAY_INIT)
  33. msleep(2000);
  34. /* consecutive bus-powered hubs aren't reliable; they can
  35. * violate the voltage drop budget. if the new child has
  36. * a "powered" LED, users should notice we didn't enable it
  37. * (without reading syslog), even without per-port LEDs
  38. * on the parent.
  39. */
  40. if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
  41. && udev->bus_mA <= unit_load) {
  42. u16 devstat;
  43. status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
  44. &devstat);
  45. if (status) {
  46. dev_dbg(&udev->dev, "get status %d ?\n", status);
  47. goto loop_disable;
  48. }
  49. if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
  50. dev_err(&udev->dev,
  51. "can't connect bus-powered hub "
  52. "to this port\n");
  53. if (hub->has_indicators) {
  54. hub->indicator[port1-1] =
  55. INDICATOR_AMBER_BLINK;
  56. queue_delayed_work(
  57. system_power_efficient_wq,
  58. &hub->leds, 0);
  59. }
  60. status = -ENOTCONN; /* Don't retry */
  61. goto loop_disable;
  62. }
  63. }
  64. /* check for devices running slower than they could */
  65. if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
  66. && udev->speed == USB_SPEED_FULL
  67. && highspeed_hubs != 0)
  68. check_highspeed(hub, udev, port1);
  69. /* Store the parent's children[] pointer. At this point
  70. * udev becomes globally accessible, although presumably
  71. * no one will look at it until hdev is unlocked.
  72. */
  73. status = 0;
  74. mutex_lock(&usb_port_peer_mutex);
  75. /* We mustn't add new devices if the parent hub has
  76. * been disconnected; we would race with the
  77. * recursively_mark_NOTATTACHED() routine.
  78. */
  79. spin_lock_irq(&device_state_lock);
  80. if (hdev->state == USB_STATE_NOTATTACHED)
  81. status = -ENOTCONN;
  82. else
  83. port_dev->child = udev;
  84. spin_unlock_irq(&device_state_lock);
  85. mutex_unlock(&usb_port_peer_mutex);
  86. /* Run it through the hoops (find a driver, etc) */
  87. if (!status) {
  88. status = usb_new_device(udev); //读取、解析配置描述符,解析端点描述符
  89. if (status) {
  90. mutex_lock(&usb_port_peer_mutex);
  91. spin_lock_irq(&device_state_lock);
  92. port_dev->child = NULL;
  93. spin_unlock_irq(&device_state_lock);
  94. mutex_unlock(&usb_port_peer_mutex);
  95. } else {
  96. if (hcd->usb_phy && !hdev->parent)
  97. usb_phy_notify_connect(hcd->usb_phy,
  98. udev->speed);
  99. }
  100. }
  101. if (status)
  102. goto loop_disable;
  103. status = hub_power_remaining(hub);
  104. if (status)
  105. dev_dbg(hub->intfdev, "%dmA power budget left\n", status);
  106. printk(KERN_EMERG"pompey hub: %s %d status:%d\n",__func__,__FUNCTION__,status);
  107. return;
  108. printk(KERN_EMERG"pompey hub: %s %d status:%d\n",__func__,__FUNCTION__,status);
  109. loop_disable:
  110. hub_port_disable(hub, port1, 1);
  111. loop:
  112. usb_ep0_reinit(udev);
  113. release_devnum(udev);
  114. hub_free_dev(udev);
  115. usb_put_dev(udev);
  116. if ((status == -ENOTCONN) || (status == -ENOTSUPP))
  117. break;
  118. /* When halfway through our retry count, power-cycle the port */
  119. if (i == (SET_CONFIG_TRIES / 2) - 1) {
  120. dev_info(&port_dev->dev, "attempt power cycle\n");
  121. usb_hub_set_port_power(hdev, hub, port1, false);
  122. msleep(2 * hub_power_on_good_delay(hub));
  123. usb_hub_set_port_power(hdev, hub, port1, true);
  124. msleep(hub_power_on_good_delay(hub));
  125. }
  126. }

经过一系列的操作,设备就清清楚楚的被host了解了,是什么设备(设备描述符、配置描述符)、有什么功能(接口描述符)、怎么传数据(端点描述符)都明明白白了。

for (i = 0; i < SET_CONFIG_TRIES; i++) 

......

这里的目的就是多试几次,以防失败。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/263480?site
推荐阅读
相关标签
  

闽ICP备14008679号