linux usb枚举过程分析

本文深入探讨了USB设备的枚举机制,包括USB设备插入后的处理流程、中断定时查询机制、USB枚举过程以及核心函数hub_events的详细解析。文章还分析了hub_port_connect_change和hub_port_init函数,阐述了设备状态检测、防抖动处理、设备地址分配和配置信息读取的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

插入一个 USB设备的处理机制总体计: 
1. 中断定时查询: 
这里写图片描述 
2. 总体架构设计: 
这里写图片描述 
3. 解析各个部分:

中断定时查询: 
这里写图片描述

Hub层处理 
这里写图片描述
usb枚举 
这里写图片描述

当守护程序第一次运行或usb port上状态发生变化,守护进程被唤醒都会运行hub_events函数,这个函数在usb系统中处理核心位置,usb的枚举过程就是由它完成。

usb具体的枚举流程: 
这里写图片描述

hub_events函数

  • 
     
    1. static void hub_events(void)

    2. {

    3. struct list_head *tmp;

    4. struct usb_device *hdev;

    5. struct usb_interface *intf;

    6. struct usb_hub *hub;

    7. struct device *hub_dev;

    8. u16 hubstatus;

    9. u16 hubchange;

    10. u16 portstatus;

    11. u16 portchange;

    12. int i, ret;

    13. int connect_change, wakeup_change;

    14.  
    15. /*

    16. * We restart the list every time to avoid a deadlock with

    17. * deleting hubs downstream from this one. This should be

    18. * safe since we delete the hub from the event list.

    19. * Not the most efficient, but avoids deadlocks.

    20. */

    21. while (1) {

    22.  
    23. /* Grab the first entry at the beginning of the list */

    24. spin_lock_irq(&hub_event_lock);

    25. if (list_empty(&hub_event_list)) {

    26. spin_unlock_irq(&hub_event_lock);

    27. break;

    28. }

    29.  
    30. tmp = hub_event_list.next;

    31. list_del_init(tmp);

    32.  
    33. hub = list_entry(tmp, struct usb_hub, event_list);

    34. kref_get(&hub->kref);

    35.  
    36. /* make sure hdev is not freed before accessing it */

    37. if (hub->disconnected) { //判断hub是否连接

    38. spin_unlock_irq(&hub_event_lock);

    39. goto hub_disconnected;

    40. } else {

    41. usb_get_dev(hub->hdev);

    42. }

    43. spin_unlock_irq(&hub_event_lock);

    44.  
    45. hdev = hub->hdev;

    46. hub_dev = hub->intfdev;

    47. intf = to_usb_interface(hub_dev);

    48. dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",

    49. hdev->state, hub->descriptor

    50. ? hub->descriptor->bNbrPorts

    51. : 0,

    52. /* NOTE: expects max 15 ports... */

    53. (u16) hub->change_bits[0],

    54. (u16) hub->event_bits[0]);

    55.  
    56. /* Lock the device, then check to see if we were

    57. * disconnected while waiting for the lock to succeed. */

    58. usb_lock_device(hdev);

    59. if (unlikely(hub->disconnected))

    60. goto loop_disconnected;

    61.  
    62. /* If the hub has died, clean up after it */

    63. if (hdev->state == USB_STATE_NOTATTACHED) {

    64. hub->error = -ENODEV;

    65. hub_quiesce(hub, HUB_DISCONNECT);

    66. goto loop;

    67. }

    68.  
    69. /* Autoresume */

    70. ret = usb_autopm_get_interface(intf);

    71. if (ret) {

    72. dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);

    73. goto loop;

    74. }

    75.  
    76. /* If this is an inactive hub, do nothing */

    77. if (hub->quiescing)

    78. goto loop_autopm;

    79.  
    80. if (hub->error) {

    81. dev_dbg (hub_dev, "resetting for error %d\n",

    82. hub->error);

    83.  
    84. ret = usb_reset_device(hdev);

    85. if (ret) {

    86. dev_dbg (hub_dev,

    87. "error resetting hub: %d\n", ret);

    88. goto loop_autopm;

    89. }

    90.  
    91. hub->nerrors = 0;

    92. hub->error = 0;

    93. }

    94.  
    95. /* deal with port status changes */

    96. //遍历hub中的所有port,对各个port的状态进行查看,判断port是否发生了状态变化

    97. for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {

    98. if (test_bit(i, hub->busy_bits))

    99. continue;

    100. connect_change = test_bit(i, hub->change_bits);

    101. wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);

    102. if (!test_and_clear_bit(i, hub->event_bits) &&

    103. !connect_change && !wakeup_change)

    104. continue;

    105.  
    106. ret = hub_port_status(hub, i,

    107. &portstatus, &portchange);

    108. if (ret < 0)

    109. continue;

    110.  
    111. if (portchange & USB_PORT_STAT_C_CONNECTION) {

    112. usb_clear_port_feature(hdev, i,

    113. USB_PORT_FEAT_C_CONNECTION);

    114. connect_change = 1;

    115. }

    116.  
    117. if (portchange & USB_PORT_STAT_C_ENABLE) {

    118. if (!connect_change)

    119. dev_dbg (hub_dev,

    120. "port %d enable change, "

    121. "status %08x\n",

    122. i, portstatus);

    123. usb_clear_port_feature(hdev, i,

    124. USB_PORT_FEAT_C_ENABLE);

    125.  
    126. /*

    127. * EM interference sometimes causes badly

    128. * shielded USB devices to be shutdown by

    129. * the hub, this hack enables them again.

    130. * Works at least with mouse driver.

    131. */

    132. if (!(portstatus & USB_PORT_STAT_ENABLE)

    133. && !connect_change

    134. && hub->ports[i - 1]->child) {

    135. dev_err (hub_dev,

    136. "port %i "

    137. "disabled by hub (EMI?), "

    138. "re-enabling...\n",

    139. i);

    140. connect_change = 1;

    141. }

    142. }

    143.  
    144. if (hub_handle_remote_wakeup(hub, i,

    145. portstatus, portchange))

    146. connect_change = 1;

    147.  
    148. if (portchange & USB_PORT_STAT_C_OVERCURRENT) {

    149. u16 status = 0;

    150. u16 unused;

    151.  
    152. dev_dbg(hub_dev, "over-current change on port "

    153. "%d\n", i);

    154. usb_clear_port_feature(hdev, i,

    155. USB_PORT_FEAT_C_OVER_CURRENT);

    156. msleep(100); /* Cool down */

    157. hub_power_on(hub, true);

    158. hub_port_status(hub, i, &status, &unused);

    159. if (status & USB_PORT_STAT_OVERCURRENT)

    160. dev_err(hub_dev, "over-current "

    161. "condition on port %d\n", i);

    162. }

    163.  
    164. if (portchange & USB_PORT_STAT_C_RESET) {

    165. dev_dbg (hub_dev,

    166. "reset change on port %d\n",

    167. i);

    168. usb_clear_port_feature(hdev, i,

    169. USB_PORT_FEAT_C_RESET);

    170. }

    171. if ((portchange & USB_PORT_STAT_C_BH_RESET) &&

    172. hub_is_superspeed(hub->hdev)) {

    173. dev_dbg(hub_dev,

    174. "warm reset change on port %d\n",

    175. i);

    176. usb_clear_port_feature(hdev, i,

    177. USB_PORT_FEAT_C_BH_PORT_RESET);

    178. }

    179. if (portchange & USB_PORT_STAT_C_LINK_STATE) {

    180. usb_clear_port_feature(hub->hdev, i,

    181. USB_PORT_FEAT_C_PORT_LINK_STATE);

    182. }

    183. if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {

    184. dev_warn(hub_dev,

    185. "config error on port %d\n",

    186. i);

    187. usb_clear_port_feature(hub->hdev, i,

    188. USB_PORT_FEAT_C_PORT_CONFIG_ERROR);

    189. }

    190.  
    191. /* Warm reset a USB3 protocol port if it's in

    192. * SS.Inactive state.

    193. */

    194. if (hub_port_warm_reset_required(hub, portstatus)) {

    195. int status;

    196. struct usb_device *udev =

    197. hub->ports[i - 1]->child;

    198.  
    199. dev_dbg(hub_dev, "warm reset port %d\n", i);

    200. if (!udev ||

    201. !(portstatus & USB_PORT_STAT_CONNECTION) ||

    202. udev->state == USB_STATE_NOTATTACHED) {

    203. status = hub_port_reset(hub, i,

    204. NULL, HUB_BH_RESET_TIME,

    205. true);

    206. if (status < 0)

    207. hub_port_disable(hub, i, 1);

    208. } else {

    209. usb_lock_device(udev);

    210. status = usb_reset_device(udev);

    211. usb_unlock_device(udev);

    212. connect_change = 0;

    213. }

    214. }

    215.  
    216. if (connect_change)//如果port状态发生变化,则调用hub_port_connect_change

    217. hub_port_connect_change(hub, i,

    218. portstatus, portchange);

    219. } /* end for i */

    220.  
    221. /* deal with hub status changes */

    222. if (test_and_clear_bit(0, hub->event_bits) == 0)

    223. ; /* do nothing */

    224. else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)

    225. dev_err (hub_dev, "get_hub_status failed\n");

    226. else {

    227. if (hubchange & HUB_CHANGE_LOCAL_POWER) {

    228. dev_dbg (hub_dev, "power change\n");

    229. clear_hub_feature(hdev, C_HUB_LOCAL_POWER);

    230. if (hubstatus & HUB_STATUS_LOCAL_POWER)

    231. /* FIXME: Is this always true? */

    232. hub->limited_power = 1;

    233. else

    234. hub->limited_power = 0;

    235. }

    236. if (hubchange & HUB_CHANGE_OVERCURRENT) {

    237. u16 status = 0;

    238. u16 unused;

    239.  
    240. dev_dbg(hub_dev, "over-current change\n");

    241. clear_hub_feature(hdev, C_HUB_OVER_CURRENT);

    242. msleep(500); /* Cool down */

    243. hub_power_on(hub, true);

    244. hub_hub_status(hub, &status, &unused);

    245. if (status & HUB_STATUS_OVERCURRENT)

    246. dev_err(hub_dev, "over-current "

    247. "condition\n");

    248. }

    249. }

    250.  
    251. loop_autopm:

    252. /* Balance the usb_autopm_get_interface() above */

    253. usb_autopm_put_interface_no_suspend(intf);

    254. loop:

    255. /* Balance the usb_autopm_get_interface_no_resume() in

    256. * kick_khubd() and allow autosuspend.

    257. */

    258. usb_autopm_put_interface(intf);

    259. loop_disconnected:

    260. usb_unlock_device(hdev);

    261. usb_put_dev(hdev);

    262. hub_disconnected:

    263. kref_put(&hub->kref, hub_release);

    264.  
    265. } /* end while (1) */

    266. }

hub_events本身是一个死循环,只要条件满足它便会一直执行。 
首先判断hub_event_list是否为空,如果为空,则跳出循环,hub_events运行结束,会进入休眠状态;如果不为空,则从hub_event_list列表中取出某一项,并把它从hub_event_list中删除,通过list_entry来获取event_list所对应的hub,并增加hub使用计数;然后做了一些逻辑判断,判断hub是否连接,hub上是否有错误,如果有错误就重启hub,如果没有错误,接下来就对hub 上的每个port进行扫描,判断各个port是否发生状态变化;

接着遍历hub中的所有port,对各个port的状态进行查看,判断port是否发生了状态变化,如果产生了变化则调用hub_port_connect_change进行处理;

在hub结构中存在多个标志位,用来表示port一些状态:

  1. 如果usb的第i个port处于resume或reset状态,则hub中busy_bits中第i个位置1;如果busy_bits中第i个位置1,则退过当前port;
  2. event_bits中第0位用来表示hub本身是否产生local power status change和是否产生过流,其它的各位用来表示hub下各个port状态是否发生变化,这些状态包括: ConnectStatusChange 连接状态发生变化,PortEnableStatusChange端口使能状态发生变化,PortSuspendStatusChange端口从挂起到恢复完成,PortOverCurrentIndicatorChange端口过流状态发生变化,PortResetStatusChange端口reset10ms置位;

  3. remove_bits用来表示hub下各个port是否有设备连接,如果置位表示没有设备连接或设备已经断开;

  4. change_bits用来表示hub下各个端口逻辑状态是否发生变化,它是在hub初始化的时候赋值的,这些状态主要有:1.原先port上没有设备,现在检测到有设备连接;2.原先port上有设备,由于控制器不正常关闭或禁止usb port等原图使得该设备处于NOATTACHED态,则需要断开设备;

在遍历port时,首先对这些标志进行判断,如果没有产生变化则跳过当前port,否则读取当前port的status,判断出产生状态变化的原因; 
如果发生变化port的连接状态发生变化,清除相应的端口状态,设置connect_change变量为1; 
如果port的使能状态发生变化,清除相应的状态标志,如果是由于EMI电磁干扰引起的状态变化,则设置connect_change变量为1; 
……

经过一系列列port判断,如果发现port的连接状态发生变化或由于EMI导致连接使能发生变化,即connect_change=1,则调用hub_port_connect_change.



 
  1. /* Handle physical or logical connection change events.

  2. * This routine is called when:

  3. * a port connection-change occurs;

  4. * a port enable-change occurs (often caused by EMI);

  5. * usb_reset_and_verify_device() encounters changed descriptors (as from

  6. * a firmware download)

  7. * caller already locked the hub

  8. */

  9. static void hub_port_connect_change(struct usb_hub *hub, int port1,

  10. u16 portstatus, u16 portchange)

  11. {

  12. struct usb_device *hdev = hub->hdev;

  13. struct device *hub_dev = hub->intfdev;

  14. struct usb_hcd *hcd = bus_to_hcd(hdev->bus);

  15. unsigned wHubCharacteristics =

  16. le16_to_cpu(hub->descriptor->wHubCharacteristics);

  17. struct usb_device *udev;

  18. int status, i;

  19. unsigned unit_load;

  20.  
  21. dev_dbg (hub_dev,

  22. "port %d, status %04x, change %04x, %s\n",

  23. port1, portstatus, portchange, portspeed(hub, portstatus));

  24.  
  25. if (hub->has_indicators) {//如果当前的hub支持indicator指示灯,则设备指示灯为HUB_LED_AUTO

  26. set_port_led(hub, port1, HUB_LED_AUTO);

  27. hub->indicator[port1-1] = INDICATOR_AUTO;

  28. }

  29.  
  30. #ifdef CONFIG_USB_OTG

  31. /* during HNP, don't repeat the debounce */

  32. if (hdev->bus->is_b_host)

  33. portchange &= ~(USB_PORT_STAT_C_CONNECTION |

  34. USB_PORT_STAT_C_ENABLE);

  35. #endif

  36.  
  37. /* Try to resuscitate an existing device */

  38. udev = hub->ports[port1 - 1]->child;

  39. if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&

  40. udev->state != USB_STATE_NOTATTACHED) {

  41. usb_lock_device(udev);

  42. if (portstatus & USB_PORT_STAT_ENABLE) {

  43. status = 0; /* Nothing to do */

  44.  
  45. #ifdef CONFIG_PM_RUNTIME

  46. } else if (udev->state == USB_STATE_SUSPENDED &&

  47. udev->persist_enabled) {

  48. /* For a suspended device, treat this as a

  49. * remote wakeup event.

  50. */

  51. status = usb_remote_wakeup(udev);

  52. #endif

  53.  
  54. } else {

  55. status = -ENODEV; /* Don't resuscitate */

  56. }

  57. usb_unlock_device(udev);

  58.  
  59. if (status == 0) { //清除当前port的change_bits标志

  60. clear_bit(port1, hub->change_bits);

  61. return;

  62. }

  63. }

  64.  
  65. /* Disconnect any existing devices under this port */

  66. if (udev) {

  67. if (hcd->phy && !hdev->parent &&

  68. !(portstatus & USB_PORT_STAT_CONNECTION))

  69. usb_phy_notify_disconnect(hcd->phy, udev->speed);

  70. usb_disconnect(&hub->ports[port1 - 1]->child);

  71. }

  72. clear_bit(port1, hub->change_bits);

  73.  
  74. /* We can forget about a "removed" device when there's a physical

  75. * disconnect or the connect status changes.

  76. */

  77. if (!(portstatus & USB_PORT_STAT_CONNECTION) ||

  78. (portchange & USB_PORT_STAT_C_CONNECTION))

  79. clear_bit(port1, hub->removed_bits);

  80.  
  81. if (portchange & (USB_PORT_STAT_C_CONNECTION |

  82. USB_PORT_STAT_C_ENABLE)) {

  83. status = hub_port_debounce_be_stable(hub, port1);

  84. if (status < 0) {

  85. if (status != -ENODEV && printk_ratelimit())

  86. dev_err(hub_dev, "connect-debounce failed, "

  87. "port %d disabled\n", port1);

  88. portstatus &= ~USB_PORT_STAT_CONNECTION;

  89. } else {

  90. portstatus = status;

  91. }

  92. }

  93.  
  94. /* Return now if debouncing failed or nothing is connected or

  95. * the device was "removed".

  96. */

  97. if (!(portstatus & USB_PORT_STAT_CONNECTION) ||

  98. test_bit(port1, hub->removed_bits)) {

  99.  
  100. /* maybe switch power back on (e.g. root hub was reset) */

  101. if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2

  102. && !port_is_power_on(hub, portstatus))

  103. set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

  104.  
  105. if (portstatus & USB_PORT_STAT_ENABLE)

  106. goto done;

  107. return;

  108. }

  109. if (hub_is_superspeed(hub->hdev))

  110. unit_load = 150;

  111. else

  112. unit_load = 100;

  113.  
  114. status = 0;

  115. for (i = 0; i < SET_CONFIG_TRIES; i++) {

  116.  
  117. /* reallocate for each attempt, since references

  118. * to the previous one can escape in various ways

  119. * 通过usb_alloc_dev为新的USB设备申请资源,并进行一些初始化,

  120. * 将usb设置为USB_STATE_ATTACHED,表示设备已经连接

  121. */

  122. udev = usb_alloc_dev(hdev, hdev->bus, port1);

  123. if (!udev) {

  124. dev_err (hub_dev,

  125. "couldn't allocate port %d usb_device\n",

  126. port1);

  127. goto done;

  128. }

  129.  
  130. usb_set_device_state(udev, USB_STATE_POWERED);//设置usb设备为USB_STATE_POWERED态

  131. udev->bus_mA = hub->mA_per_port;//设置usb设备可以从port上获取的电流量

  132. udev->level = hdev->level + 1;,//设置usb设备的拓扑层级

  133. udev->wusb = hub_is_wusb(hub);

  134.  
  135. /* Only USB 3.0 devices are connected to SuperSpeed hubs. */

  136. //如果hub支持超速,则设置usb设备的速度为超速,否则设置usb设备速度 为unknow

  137. if (hub_is_superspeed(hub->hdev))

  138. udev->speed = USB_SPEED_SUPER;

  139. else

  140. udev->speed = USB_SPEED_UNKNOWN;

  141.  
  142. choose_devnum(udev); //从usb 总线中找到一个usb地址

  143. if (udev->devnum <= 0) {

  144. status = -ENOTCONN; /* Don't retry */

  145. goto loop;

  146. }

  147.  
  148. /* reset (non-USB 3.0 devices) and get descriptor */

  149. status = hub_port_init(hub, udev, port1, i);

  150. if (status < 0)

  151. goto loop;

  152.  
  153. usb_detect_quirks(udev);

  154. if (udev->quirks & USB_QUIRK_DELAY_INIT)

  155. msleep(1000);

  156.  
  157. /* consecutive bus-powered hubs aren't reliable; they can

  158. * violate the voltage drop budget. if the new child has

  159. * a "powered" LED, users should notice we didn't enable it

  160. * (without reading syslog), even without per-port LEDs

  161. * on the parent.

  162. */

  163. //如果当前的usb设备是一个hub,它由hub供电

  164. if (udev->descriptor.bDeviceClass == USB_CLASS_HUB

  165. && udev->bus_mA <= unit_load) {

  166. u16 devstat;

  167.  
  168. status = usb_get_status(udev, USB_RECIP_DEVICE, 0,

  169. &devstat);

  170. if (status < 2) {

  171. dev_dbg(&udev->dev, "get status %d ?\n", status);

  172. goto loop_disable;

  173. }

  174. le16_to_cpus(&devstat);

  175. if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {

  176. dev_err(&udev->dev,

  177. "can't connect bus-powered hub "

  178. "to this port\n");

  179. if (hub->has_indicators) {

  180. hub->indicator[port1-1] =

  181. INDICATOR_AMBER_BLINK;

  182. schedule_delayed_work (&hub->leds, 0);

  183. }

  184. status = -ENOTCONN; /* Don't retry */

  185. goto loop_disable;

  186. }

  187. }

  188.  
  189. /* check for devices running slower than they could */

  190. //如果usb设备支持高速运行,而现在却工作在全速,它就会通过点亮绿色指示灯来指示这种错误

  191. if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200

  192. && udev->speed == USB_SPEED_FULL

  193. && highspeed_hubs != 0)

  194. check_highspeed (hub, udev, port1);

  195.  
  196. /* Store the parent's children[] pointer. At this point

  197. * udev becomes globally accessible, although presumably

  198. * no one will look at it until hdev is unlocked.

  199. */

  200. status = 0;

  201.  
  202. /* We mustn't add new devices if the parent hub has

  203. * been disconnected; we would race with the

  204. * recursively_mark_NOTATTACHED() routine.

  205. */

  206. spin_lock_irq(&device_state_lock);

  207. if (hdev->state == USB_STATE_NOTATTACHED)

  208. status = -ENOTCONN;

  209. else

  210. hub->ports[port1 - 1]->child = udev;

  211. spin_unlock_irq(&device_state_lock);

  212.  
  213. /* Run it through the hoops (find a driver, etc) */

  214. if (!status) {

  215. status = usb_new_device(udev);//通过usb_new_device去获取usb设备的配置信息,将它注册到系统中

  216. if (status) {

  217. spin_lock_irq(&device_state_lock);

  218. hub->ports[port1 - 1]->child = NULL;

  219. spin_unlock_irq(&device_state_lock);

  220. }

  221. }

  222.  
  223. if (status)

  224. goto loop_disable;

  225.  
  226. status = hub_power_remaining(hub);

  227. if (status)

  228. dev_dbg(hub_dev, "%dmA power budget left\n", status);

  229.  
  230. return;

  231.  
  232. loop_disable:

  233. hub_port_disable(hub, port1, 1);

  234. loop:

  235. usb_ep0_reinit(udev);

  236. release_devnum(udev);

  237. hub_free_dev(udev);

  238. usb_put_dev(udev);

  239. if ((status == -ENOTCONN) || (status == -ENOTSUPP))

  240. break;

  241. }

  242. if (hub->hdev->parent ||

  243. !hcd->driver->port_handed_over ||

  244. !(hcd->driver->port_handed_over)(hcd, port1)) {

  245. if (status != -ENOTCONN && status != -ENODEV)

  246. dev_err(hub_dev, "unable to enumerate USB device on port %d\n",

  247. port1);

  248. }

  249.  
  250. done:

  251. hub_port_disable(hub, port1, 1);

  252. if (hcd->driver->relinquish_port && !hub->hdev->parent)

  253. hcd->driver->relinquish_port(hcd, port1);

  254. }

 

  • hub_port_connect_change分为两部分: 

第一部分主要是:确认是否有新设备插入; 
第二部分主要是:确认port口上有新设备插入后,分配设备资源,并进行枚举操作;

对于一些已经连接的设备,进行一些类似防抖动处理,处理机制:每隔25ms去读取port的status和change状态,查看port连接状态是否稳定,如果port处于稳定状态大于100ms,则认为当前port上的设备已经稳定,这种处理机制最长时间为1.5s;如果port处于稳定状态的时间小于100ms,则认为连接是不稳定的,则跳出当前port,去执行下一个port;

对于一个新插入的设备,并已经确定它的存在,则接下来会为这个usb设备进行枚举

一条usb总线下总共可以有128个设备,usb总线通过位图的形式来管理usb设备的地址,choose_devnum是从usb 总线中找到一个usb地址,usb地址在1和128之间; 
通过hub_port_init对usb设备进行reset,并设置usb设备的地址,获取usb设备的设备描述符,这个函数相对比较重要,所以对它进行了进一步分析:



 
  1. /* Reset device, (re)assign address, get device descriptor.

  2. * Device connection must be stable, no more debouncing needed.

  3. * Returns device in USB_STATE_ADDRESS, except on error.

  4. *

  5. * If this is called for an already-existing device (as part of

  6. * usb_reset_and_verify_device), the caller must own the device lock. For a

  7. * newly detected device that is not accessible through any global

  8. * pointers, it's not necessary to lock the device.

  9. */

  10. static int

  11. hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,

  12. int retry_counter)

  13. {

  14. static DEFINE_MUTEX(usb_address0_mutex);

  15.  
  16. struct usb_device *hdev = hub->hdev;

  17. struct usb_hcd *hcd = bus_to_hcd(hdev->bus);

  18. int i, j, retval;

  19. unsigned delay = HUB_SHORT_RESET_TIME;

  20. enum usb_device_speed oldspeed = udev->speed;

  21. const char *speed;

  22. int devnum = udev->devnum;

  23.  
  24. /* root hub ports have a slightly longer reset period

  25. * (from USB 2.0 spec, section 7.1.7.5)

  26. * 设置用于读取port状态的时间间隔,root hub需要50ms,普通的hub需要10ms,

  27. * 对于低速的usb设备需要200ms

  28. */

  29. if (!hdev->parent) {

  30. delay = HUB_ROOT_RESET_TIME;

  31. if (port1 == hdev->bus->otg_port)

  32. hdev->bus->b_hnp_enable = 0;

  33. }

  34.  
  35. /* Some low speed devices have problems with the quick delay, so */

  36. /* be a bit pessimistic with those devices. RHbug #23670 */

  37. if (oldspeed == USB_SPEED_LOW)

  38. delay = HUB_LONG_RESET_TIME;

  39.  
  40. mutex_lock(&usb_address0_mutex);

  41.  
  42. /* Reset the device; full speed may morph to high speed */

  43. /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */

  44. //通过hub_port_reset来reset设备

  45. retval = hub_port_reset(hub, port1, udev, delay, false);

  46. if (retval < 0) /* error or disconnect */

  47. goto fail;

  48. /* success, speed is known */

  49.  
  50. retval = -ENODEV;

  51.  
  52. if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {

  53. dev_dbg(&udev->dev, "device reset changed speed!\n");

  54. goto fail;

  55. }

  56. oldspeed = udev->speed;

  57.  
  58. /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...

  59. * it's fixed size except for full speed devices.

  60. * For Wireless USB devices, ep0 max packet is always 512 (tho

  61. * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].

  62. * 根据usb设备的速度来初始化endpont0的最大发送数据长度,

  63. * 对于无线usb其maxpacketsize为512字节,对于高速和全速为64字节,而低速为8个字节

  64. */

  65. switch (udev->speed) {

  66. case USB_SPEED_SUPER:

  67. case USB_SPEED_WIRELESS: /* fixed at 512 */

  68. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);

  69. break;

  70. case USB_SPEED_HIGH: /* fixed at 64 */

  71. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);

  72. break;

  73. case USB_SPEED_FULL: /* 8, 16, 32, or 64 */

  74. /* to determine the ep0 maxpacket size, try to read

  75. * the device descriptor to get bMaxPacketSize0 and

  76. * then correct our initial guess.

  77. */

  78. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);

  79. break;

  80. case USB_SPEED_LOW: /* fixed at 8 */

  81. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);

  82. break;

  83. default:

  84. goto fail;

  85. }

  86.  
  87. if (udev->speed == USB_SPEED_WIRELESS)

  88. speed = "variable speed Wireless";

  89. else

  90. speed = usb_speed_string(udev->speed);

  91.  
  92. if (udev->speed != USB_SPEED_SUPER)

  93. dev_info(&udev->dev,

  94. "%s %s USB device number %d using %s\n",

  95. (udev->config) ? "reset" : "new", speed,

  96. devnum, udev->bus->controller->driver->name);

  97.  
  98. /* Set up TT records, if needed */

  99. //如果hub为高速,而usb设备为低速或全速,则在它们之间需要有一个速度转换设备tt

  100. if (hdev->tt) {

  101. udev->tt = hdev->tt;

  102. udev->ttport = hdev->ttport;

  103. } else if (udev->speed != USB_SPEED_HIGH

  104. && hdev->speed == USB_SPEED_HIGH) {

  105. if (!hub->tt.hub) {

  106. dev_err(&udev->dev, "parent hub has no TT\n");

  107. retval = -EINVAL;

  108. goto fail;

  109. }

  110. udev->tt = &hub->tt;

  111. udev->ttport = port1;

  112. }

  113.  
  114. /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?

  115. * Because device hardware and firmware is sometimes buggy in

  116. * this area, and this is how Linux has done it for ages.

  117. * Change it cautiously.

  118. *

  119. * NOTE: If USE_NEW_SCHEME() is true we will start by issuing

  120. * a 64-byte GET_DESCRIPTOR request. This is what Windows does,

  121. * so it may help with some non-standards-compliant devices.

  122. * Otherwise we start with SET_ADDRESS and then try to read the

  123. * first 8 bytes of the device descriptor to get the ep0 maxpacket

  124. * value.

  125. */

  126. for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {

  127. if (USE_NEW_SCHEME(retry_counter) &&

  128. !(hcd->driver->flags & HCD_USB3) &&

  129. !((hcd->driver->flags & HCD_RT_OLD_ENUM) &&

  130. !hdev->parent)) {

  131. struct usb_device_descriptor *buf;

  132. ushort idvendor;

  133. int r = 0;

  134.  
  135. #define GET_DESCRIPTOR_BUFSIZE 64

  136. buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);

  137. if (!buf) {

  138. retval = -ENOMEM;

  139. continue;

  140. }

  141.  
  142. /* Retry on all errors; some devices are flakey.

  143. * 255 is for WUSB devices, we actually need to use

  144. * 512 (WUSB1.0[4.8.1]).

  145. */

  146. for (j = 0; j < 3; ++j) {

  147. buf->bMaxPacketSize0 = 0;

  148. r = usb_control_msg(udev, usb_rcvaddr0pipe(),

  149. USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,

  150. USB_DT_DEVICE << 8, 0,

  151. buf, GET_DESCRIPTOR_BUFSIZE,

  152. initial_descriptor_timeout);

  153. switch (buf->bMaxPacketSize0) {

  154. case 8: case 16: case 32: case 64: case 255:

  155. if (buf->bDescriptorType ==

  156. USB_DT_DEVICE) {

  157. r = 0;

  158. break;

  159. }

  160. /* FALL THROUGH */

  161. default:

  162. if (r == 0)

  163. r = -EPROTO;

  164. break;

  165. }

  166. if (r == 0)

  167. break;

  168. }

  169. udev->descriptor.bMaxPacketSize0 =

  170. buf->bMaxPacketSize0;

  171. idvendor = le16_to_cpu(buf->idVendor);

  172. kfree(buf);

  173.  
  174. /*

  175. * If it is a HSET Test device, we don't issue a

  176. * second reset which results in failure due to

  177. * speed change.

  178. */

  179. if (idvendor != 0x1a0a) {

  180. retval = hub_port_reset(hub, port1, udev,

  181. delay, false);

  182. if (retval < 0) /* error or disconnect */

  183. goto fail;

  184. if (oldspeed != udev->speed) {

  185. dev_dbg(&udev->dev,

  186. "device reset changed speed!\n");

  187. retval = -ENODEV;

  188. goto fail;

  189. }

  190. }

  191. if (r) {

  192. if (r != -ENODEV)

  193. dev_err(&udev->dev, "device descriptor read/64, error %d\n",

  194. r);

  195. retval = -EMSGSIZE;

  196. continue;

  197. }

  198. #undef GET_DESCRIPTOR_BUFSIZE

  199. }

  200.  
  201. /*

  202. * If device is WUSB, we already assigned an

  203. * unauthorized address in the Connect Ack sequence;

  204. * authorization will assign the final address.

  205. */

  206. if (udev->wusb == 0) {

  207. for (j = 0; j < SET_ADDRESS_TRIES; ++j) {

  208. retval = hub_set_address(udev, devnum);

  209. if (retval >= 0)

  210. break;

  211. msleep(200);

  212. }

  213. if (retval < 0) {

  214. if (retval != -ENODEV)

  215. dev_err(&udev->dev, "device not accepting address %d, error %d\n",

  216. devnum, retval);

  217. goto fail;

  218. }

  219. if (udev->speed == USB_SPEED_SUPER) {

  220. devnum = udev->devnum;

  221. dev_info(&udev->dev,

  222. "%s SuperSpeed USB device number %d using %s\n",

  223. (udev->config) ? "reset" : "new",

  224. devnum, udev->bus->controller->driver->name);

  225. }

  226.  
  227. /* cope with hardware quirkiness:

  228. * - let SET_ADDRESS settle, some device hardware wants it

  229. * - read ep0 maxpacket even for high and low speed,

  230. */

  231. msleep(10);

  232. if (USE_NEW_SCHEME(retry_counter) &&

  233. !(hcd->driver->flags & HCD_USB3) &&

  234. !((hcd->driver->flags & HCD_RT_OLD_ENUM) &&

  235. !hdev->parent))

  236. break;

  237. }

  238.  
  239. retval = usb_get_device_descriptor(udev, 8);

  240. if (retval < 8) {

  241. if (retval != -ENODEV)

  242. dev_err(&udev->dev,

  243. "device descriptor read/8, error %d\n",

  244. retval);

  245. if (retval >= 0)

  246. retval = -EMSGSIZE;

  247. } else {

  248. retval = 0;

  249. break;

  250. }

  251. }

  252. if (retval)

  253. goto fail;

  254.  
  255. if (hcd->phy && !hdev->parent)

  256. usb_phy_notify_connect(hcd->phy, udev->speed);

  257.  
  258. /*

  259. * Some superspeed devices have finished the link training process

  260. * and attached to a superspeed hub port, but the device descriptor

  261. * got from those devices show they aren't superspeed devices. Warm

  262. * reset the port attached by the devices can fix them.

  263. */

  264. if ((udev->speed == USB_SPEED_SUPER) &&

  265. (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {

  266. dev_err(&udev->dev, "got a wrong device descriptor, "

  267. "warm reset device\n");

  268. hub_port_reset(hub, port1, udev,

  269. HUB_BH_RESET_TIME, true);

  270. retval = -EINVAL;

  271. goto fail;

  272. }

  273.  
  274. if (udev->descriptor.bMaxPacketSize0 == 0xff ||

  275. udev->speed == USB_SPEED_SUPER)

  276. i = 512;

  277. else

  278. i = udev->descriptor.bMaxPacketSize0;

  279. if (usb_endpoint_maxp(&udev->ep0.desc) != i) {

  280. if (udev->speed == USB_SPEED_LOW ||

  281. !(i == 8 || i == 16 || i == 32 || i == 64)) {

  282. dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);

  283. retval = -EMSGSIZE;

  284. goto fail;

  285. }

  286. if (udev->speed == USB_SPEED_FULL)

  287. dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);

  288. else

  289. dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);

  290. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);

  291. usb_ep0_reinit(udev);

  292. }

  293.  
  294. //根据maxpacketsize去获取完整的设备描述符

  295. retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);

  296. if (retval < (signed)sizeof(udev->descriptor)) {

  297. if (retval != -ENODEV)

  298. dev_err(&udev->dev, "device descriptor read/all, error %d\n",

  299. retval);

  300. if (retval >= 0)

  301. retval = -ENOMSG;

  302. goto fail;

  303. }

  304.  
  305. if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {

  306. retval = usb_get_bos_descriptor(udev);

  307. if (!retval) {

  308. udev->lpm_capable = usb_device_supports_lpm(udev);

  309. usb_set_lpm_parameters(udev);

  310. }

  311. }

  312.  
  313. retval = 0;

  314. /* notify HCD that we have a device connected and addressed */

  315. if (hcd->driver->update_device)

  316. hcd->driver->update_device(hcd, udev);

  317. fail:

  318. if (retval) {

  319. hub_port_disable(hub, port1, 0);

  320. update_devnum(udev, devnum); /* for disconnect processing */

  321. }

  322. mutex_unlock(&usb_address0_mutex);

  323. return retval;

  324. }

hub_port_init首先对port进行reset,复位成功后设备usb设备的速度和端口0最大发送数据长度,设置usb设备的地址,并获取usb设备的设备描述符; 
通过hub_port_reset来reset设备,reset机制为:通过set_port_feature来传输USB_PORT_FEAT_RESET指令,设置成功后循环延时由之前确定的时间间隔后去读取port的status和change状态,要确保usb设备在reset后还能正常存在,如reset还能正常,则通过port的status状态位来确定usb设备的速度,循环延时总时间为500ms,而usb设备reset次数为5次, 
根据usb设备的速度来初始化endpont0的最大发送数据长度,对于无线usb其maxpacketsize为512字节,对于高速和全速为64字节,而低速为8个字节; 
如果hub为高速,而usb设备为低速或全速,则在它们之间需要有一个速度转换设备tt;

通过获取usb设备的设备描述符来得到usb设备的endpoint0的最大发送数据长度,设备描述符实际 上有18个字节,而endpoint0的maxpacketsize在设备描述符里的第8个字节位,所以只要获取设备描述符的前8个字节数据就可以了,但有些USB设备它并不支持只获取8个字节这样不完整的usb请求,为解决这种问题usb驱动里采用了两种策略去获取maxpacketsize,一种是windows作法,它直接向usb设备请求64字节数据,对于一些maxpacketsize为32或64的,它可以直接一次性把18个字节的设备描述符传输回来,而对于像low speed的设备它的maxpacketsize只有8个字节,就需要进行多次发送; 而Linux作法是先设置usb设备的地址,然后再发送8个字节数据请求,从返回的8个字节里获取endpoint0的maxpacketsize;



 
  1. /**

  2. * usb_new_device - perform initial device setup (usbcore-internal)

  3. * @udev: newly addressed device (in ADDRESS state)

  4. *

  5. * This is called with devices which have been detected but not fully

  6. * enumerated. The device descriptor is available, but not descriptors

  7. * for any device configuration. The caller must have locked either

  8. * the parent hub (if udev is a normal device) or else the

  9. * usb_bus_list_lock (if udev is a root hub). The parent's pointer to

  10. * udev has already been installed, but udev is not yet visible through

  11. * sysfs or other filesystem code.

  12. *

  13. * It will return if the device is configured properly or not. Zero if

  14. * the interface was registered with the driver core; else a negative

  15. * errno value.

  16. *

  17. * This call is synchronous, and may not be used in an interrupt context.

  18. *

  19. * Only the hub driver or root-hub registrar should ever call this.

  20. */

  21. int usb_new_device(struct usb_device *udev)

  22. {

  23. int err;

  24.  
  25. if (udev->parent) {

  26. /* Initialize non-root-hub device wakeup to disabled;

  27. * device (un)configuration controls wakeup capable

  28. * sysfs power/wakeup controls wakeup enabled/disabled

  29. */

  30. device_init_wakeup(&udev->dev, 0);

  31. }

  32.  
  33. /* Tell the runtime-PM framework the device is active */

  34. pm_runtime_set_active(&udev->dev);

  35. pm_runtime_get_noresume(&udev->dev);

  36. pm_runtime_use_autosuspend(&udev->dev);

  37. pm_runtime_enable(&udev->dev);

  38.  
  39. /* By default, forbid autosuspend for all devices. It will be

  40. * allowed for hubs during binding.

  41. */

  42. usb_disable_autosuspend(udev);

  43.  
  44. err = usb_enumerate_device(udev); /* Read descriptors */

  45. if (err < 0)

  46. goto fail;

  47. dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",

  48. udev->devnum, udev->bus->busnum,

  49. (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

  50. /* export the usbdev device-node for libusb */

  51. udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,

  52. (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

  53.  
  54. /* Tell the world! */

  55. announce_device(udev);

  56.  
  57. if (udev->serial)

  58. add_device_randomness(udev->serial, strlen(udev->serial));

  59. if (udev->product)

  60. add_device_randomness(udev->product, strlen(udev->product));

  61. if (udev->manufacturer)

  62. add_device_randomness(udev->manufacturer,

  63. strlen(udev->manufacturer));

  64.  
  65. device_enable_async_suspend(&udev->dev);

  66.  
  67. /*

  68. * check whether the hub marks this port as non-removable. Do it

  69. * now so that platform-specific data can override it in

  70. * device_add()

  71. */

  72. if (udev->parent)

  73. set_usb_port_removable(udev);

  74.  
  75. /* Register the device. The device driver is responsible

  76. * for configuring the device and invoking the add-device

  77. * notifier chain (used by usbfs and possibly others).

  78. */

  79. err = device_add(&udev->dev);

  80. if (err) {

  81. dev_err(&udev->dev, "can't device_add, error %d\n", err);

  82. goto fail;

  83. }

  84.  
  85. /* Create link files between child device and usb port device. */

  86. if (udev->parent) {

  87. struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);

  88. struct usb_port *port_dev;

  89.  
  90. if (!hub)

  91. goto fail;

  92.  
  93. port_dev = hub->ports[udev->portnum - 1];

  94. if (!port_dev)

  95. goto fail;

  96.  
  97. err = sysfs_create_link(&udev->dev.kobj,

  98. &port_dev->dev.kobj, "port");

  99. if (err)

  100. goto fail;

  101.  
  102. err = sysfs_create_link(&port_dev->dev.kobj,

  103. &udev->dev.kobj, "device");

  104. if (err) {

  105. sysfs_remove_link(&udev->dev.kobj, "port");

  106. goto fail;

  107. }

  108.  
  109. pm_runtime_get_sync(&port_dev->dev);

  110. }

  111.  
  112. (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);

  113. usb_mark_last_busy(udev);

  114. pm_runtime_put_sync_autosuspend(&udev->dev);

  115. return err;

  116.  
  117. fail:

  118. usb_set_device_state(udev, USB_STATE_NOTATTACHED);

  119. pm_runtime_disable(&udev->dev);

  120. pm_runtime_set_suspended(&udev->dev);

  121. return err;

  122. }


 

  • usb_new_device主是要获取usb设备的配置信息,然后将usb设备添加到系统中,这里usb_enumerate_device相对比较重要,就是它完成了配置信息获取及分配;

 
  1.  
  2.  
  3.  

 
  1. /**

  2. * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal)

  3. * @udev: newly addressed device (in ADDRESS state)

  4. *

  5. * This is only called by usb_new_device() and usb_authorize_device()

  6. * and FIXME -- all comments that apply to them apply here wrt to

  7. * environment.

  8. *

  9. * If the device is WUSB and not authorized, we don't attempt to read

  10. * the string descriptors, as they will be errored out by the device

  11. * until it has been authorized.

  12. */

  13. static int usb_enumerate_device(struct usb_device *udev)

  14. {

  15. int err;

  16.  
  17. if (udev->config == NULL) {

  18. err = usb_get_configuration(udev);

  19. if (err < 0) {

  20. if (err != -ENODEV)

  21. dev_err(&udev->dev, "can't read configurations, error %d\n",

  22. err);

  23. return err;

  24. }

  25. }

  26.  
  27. /* read the standard strings and cache them if present */

  28. udev->product = usb_cache_string(udev, udev->descriptor.iProduct);

  29. udev->manufacturer = usb_cache_string(udev,

  30. udev->descriptor.iManufacturer);

  31. udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);

  32.  
  33. err = usb_enumerate_device_otg(udev);

  34. if (err < 0)

  35. return err;

  36.  
  37. usb_detect_interface_quirks(udev);

  38.  
  39. return 0;

  40. }

通过usb_get_configuration获取和分配usb设备的配置,接口,端口信息


 
  1. /*

  2. * Get the USB config descriptors, cache and parse'em

  3. *

  4. * hub-only!! ... and only in reset path, or usb_new_device()

  5. * (used by real hubs and virtual root hubs)

  6. */

  7. int usb_get_configuration(struct usb_device *dev)

  8. {

  9. struct device *ddev = &dev->dev;

  10. int ncfg = dev->descriptor.bNumConfigurations;

  11. int result = 0;

  12. unsigned int cfgno, length;

  13. unsigned char *bigbuffer;

  14. struct usb_config_descriptor *desc;

  15.  
  16. cfgno = 0;

  17. result = -ENOMEM;

  18. //如果usb设备的配置个数大于最大允许配置数8,则发出警告,并把设备的配置个数改成最大允许配置数8

  19. if (ncfg > USB_MAXCONFIG) {

  20. dev_warn(ddev, "too many configurations: %d, "

  21. "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);

  22. dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;

  23. }

  24.  
  25. //如果usb设备没有配置,则不允许,直接返回错误信息

  26. if (ncfg < 1) {

  27. dev_err(ddev, "no configurations\n");

  28. return -EINVAL;

  29. }

  30.  
  31. //根据配置数,申请usb配置结构usb_host_config,并为用于存放配置结构的指针数据申请空间

  32. length = ncfg * sizeof(struct usb_host_config);

  33. dev->config = kzalloc(length, GFP_KERNEL);

  34. if (!dev->config)

  35. goto err2;

  36.  
  37. length = ncfg * sizeof(char *);

  38. dev->rawdescriptors = kzalloc(length, GFP_KERNEL);

  39. if (!dev->rawdescriptors)

  40. goto err2;

  41.  
  42. //申请用于暂时存放配置描述符的结构空间

  43. desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);

  44. if (!desc)

  45. goto err2;

  46.  
  47. result = 0;

  48. //依次获取usb设备的配置信息

  49. for (; cfgno < ncfg; cfgno++) {

  50. /* We grab just the first descriptor so we know how long

  51. * the whole configuration is */

  52. result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,

  53. desc, USB_DT_CONFIG_SIZE);

  54. if (result < 0) {

  55. dev_err(ddev, "unable to read config index %d "

  56. "descriptor/%s: %d\n", cfgno, "start", result);

  57. if (result != -EPIPE)

  58. goto err;

  59. dev_err(ddev, "chopping to %d config(s)\n", cfgno);

  60. dev->descriptor.bNumConfigurations = cfgno;

  61. break;

  62. } else if (result < 4) {

  63. dev_err(ddev, "config index %d descriptor too short "

  64. "(expected %i, got %i)\n", cfgno,

  65. USB_DT_CONFIG_SIZE, result);

  66. result = -EINVAL;

  67. goto err;

  68. }

  69. length = max((int) le16_to_cpu(desc->wTotalLength),

  70. USB_DT_CONFIG_SIZE);//得到wTotallLength

  71.  
  72. /* Now that we know the length, get the whole thing */

  73. //根据得到的wTotallLength,申请用于存放这些信息的内存空间

  74. bigbuffer = kmalloc(length, GFP_KERNEL);

  75. if (!bigbuffer) {

  76. result = -ENOMEM;

  77. goto err;

  78. }

  79.  
  80. if (dev->quirks & USB_QUIRK_DELAY_INIT)

  81. msleep(100);

  82.  
  83. //根据得到的wTotallLength,去获取完整的配置,接口,端口等描述符信息,把这些信息存放到bigbuffer里

  84. result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,

  85. bigbuffer, length);

  86. if (result < 0) {

  87. dev_err(ddev, "unable to read config index %d "

  88. "descriptor/%s\n", cfgno, "all");

  89. kfree(bigbuffer);

  90. goto err;

  91. }

  92. if (result < length) {

  93. dev_warn(ddev, "config index %d descriptor too short "

  94. "(expected %i, got %i)\n", cfgno, length, result);

  95. length = result;

  96. }

  97.  
  98. //把用于存放配置等信息的地址保存在之前申请的rawdescriptors里

  99. dev->rawdescriptors[cfgno] = bigbuffer;

  100.  
  101. //通过usb_parse_configuration函数,把获得的配置等信息按照类型进行分类

  102. result = usb_parse_configuration(dev, cfgno,

  103. &dev->config[cfgno], bigbuffer, length);

  104. if (result < 0) {

  105. ++cfgno;

  106. goto err;

  107. }

  108. }

  109. result = 0;

  110.  
  111. err:

  112. kfree(desc);

  113. dev->descriptor.bNumConfigurations = cfgno;

  114. err2:

  115. if (result == -ENOMEM)

  116. dev_err(ddev, "out of memory\n");

  117. return result;

  118. }

这个函数主要分成二部分,第一部分是向usb device侧获取设备的配置,接口,端口信息。首先,它为这些信息申请存放空间,然后像之前获取设备描述符一样,先发送一个9 个字节的请求,用来获取配置,接口,端口等描述符的总长度,最后根据得到的总长度去得到完成 的设备配置,接口,端口信息;第二部分是把获取到的这个信息按照类别分别进行分类,并存到相应的结构中;

通过usb_parse_configuration函数,把获得的配置等信息按照类型进行分类



 
  1. static int usb_parse_configuration(struct usb_device *dev, int cfgidx,

  2. struct usb_host_config *config, unsigned char *buffer, int size)

  3. {

  4. struct device *ddev = &dev->dev;

  5. unsigned char *buffer0 = buffer;

  6. int cfgno;

  7. int nintf, nintf_orig;

  8. int i, j, n;

  9. struct usb_interface_cache *intfc;

  10. unsigned char *buffer2;

  11. int size2;

  12. struct usb_descriptor_header *header;

  13. int len, retval;

  14. u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];

  15. unsigned iad_num = 0;

  16.  
  17. memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);

  18. if (config->desc.bDescriptorType != USB_DT_CONFIG ||

  19. config->desc.bLength < USB_DT_CONFIG_SIZE ||

  20. config->desc.bLength > size) {

  21. dev_err(ddev, "invalid descriptor for config index %d: "

  22. "type = 0x%X, length = %d\n", cfgidx,

  23. config->desc.bDescriptorType, config->desc.bLength);

  24. return -EINVAL;

  25. }

  26. cfgno = config->desc.bConfigurationValue;

  27.  
  28. buffer += config->desc.bLength;

  29. size -= config->desc.bLength;

  30.  
  31. nintf = nintf_orig = config->desc.bNumInterfaces;

  32. if (nintf > USB_MAXINTERFACES) {

  33. dev_warn(ddev, "config %d has too many interfaces: %d, "

  34. "using maximum allowed: %d\n",

  35. cfgno, nintf, USB_MAXINTERFACES);

  36. nintf = USB_MAXINTERFACES;

  37. }

  38.  
  39. /* Go through the descriptors, checking their length and counting the

  40. * number of altsettings for each interface */

  41. n = 0;

  42. for ((buffer2 = buffer, size2 = size);

  43. size2 > 0;

  44. (buffer2 += header->bLength, size2 -= header->bLength)) {

  45.  
  46. if (size2 < sizeof(struct usb_descriptor_header)) {

  47. dev_warn(ddev, "config %d descriptor has %d excess "

  48. "byte%s, ignoring\n",

  49. cfgno, size2, plural(size2));

  50. break;

  51. }

  52.  
  53. header = (struct usb_descriptor_header *) buffer2;

  54. if ((header->bLength > size2) || (header->bLength < 2)) {

  55. dev_warn(ddev, "config %d has an invalid descriptor "

  56. "of length %d, skipping remainder of the config\n",

  57. cfgno, header->bLength);

  58. break;

  59. }

  60.  
  61. if (header->bDescriptorType == USB_DT_INTERFACE) {

  62. struct usb_interface_descriptor *d;

  63. int inum;

  64.  
  65. d = (struct usb_interface_descriptor *) header;

  66. if (d->bLength < USB_DT_INTERFACE_SIZE) {

  67. dev_warn(ddev, "config %d has an invalid "

  68. "interface descriptor of length %d, "

  69. "skipping\n", cfgno, d->bLength);

  70. continue;

  71. }

  72.  
  73. inum = d->bInterfaceNumber;

  74.  
  75. if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&

  76. n >= nintf_orig) {

  77. dev_warn(ddev, "config %d has more interface "

  78. "descriptors, than it declares in "

  79. "bNumInterfaces, ignoring interface "

  80. "number: %d\n", cfgno, inum);

  81. continue;

  82. }

  83.  
  84. if (inum >= nintf_orig)

  85. dev_warn(ddev, "config %d has an invalid "

  86. "interface number: %d but max is %d\n",

  87. cfgno, inum, nintf_orig - 1);

  88.  
  89. /* Have we already encountered this interface?

  90. * Count its altsettings */

  91. for (i = 0; i < n; ++i) {

  92. if (inums[i] == inum)

  93. break;

  94. }

  95. if (i < n) {

  96. if (nalts[i] < 255)

  97. ++nalts[i];

  98. } else if (n < USB_MAXINTERFACES) {

  99. inums[n] = inum;

  100. nalts[n] = 1;

  101. ++n;

  102. }

  103.  
  104. } else if (header->bDescriptorType ==

  105. USB_DT_INTERFACE_ASSOCIATION) {

  106. if (iad_num == USB_MAXIADS) {

  107. dev_warn(ddev, "found more Interface "

  108. "Association Descriptors "

  109. "than allocated for in "

  110. "configuration %d\n", cfgno);

  111. } else {

  112. config->intf_assoc[iad_num] =

  113. (struct usb_interface_assoc_descriptor

  114. *)header;

  115. iad_num++;

  116. }

  117.  
  118. } else if (header->bDescriptorType == USB_DT_DEVICE ||

  119. header->bDescriptorType == USB_DT_CONFIG)

  120. dev_warn(ddev, "config %d contains an unexpected "

  121. "descriptor of type 0x%X, skipping\n",

  122. cfgno, header->bDescriptorType);

  123.  
  124. } /* for ((buffer2 = buffer, size2 = size); ...) */

  125. size = buffer2 - buffer;

  126. config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);

  127.  
  128. if (n != nintf)

  129. dev_warn(ddev, "config %d has %d interface%s, different from "

  130. "the descriptor's value: %d\n",

  131. cfgno, n, plural(n), nintf_orig);

  132. else if (n == 0)

  133. dev_warn(ddev, "config %d has no interfaces?\n", cfgno);

  134. config->desc.bNumInterfaces = nintf = n;

  135.  
  136. /* Check for missing interface numbers */

  137. for (i = 0; i < nintf; ++i) {

  138. for (j = 0; j < nintf; ++j) {

  139. if (inums[j] == i)

  140. break;

  141. }

  142. if (j >= nintf)

  143. dev_warn(ddev, "config %d has no interface number "

  144. "%d\n", cfgno, i);

  145. }

  146.  
  147. /* Allocate the usb_interface_caches and altsetting arrays */

  148. for (i = 0; i < nintf; ++i) {

  149. j = nalts[i];

  150. if (j > USB_MAXALTSETTING) {

  151. dev_warn(ddev, "too many alternate settings for "

  152. "config %d interface %d: %d, "

  153. "using maximum allowed: %d\n",

  154. cfgno, inums[i], j, USB_MAXALTSETTING);

  155. nalts[i] = j = USB_MAXALTSETTING;

  156. }

  157.  
  158. len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;

  159. config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);

  160. if (!intfc)

  161. return -ENOMEM;

  162. kref_init(&intfc->ref);

  163. }

  164.  
  165. /* FIXME: parse the BOS descriptor */

  166.  
  167. /* Skip over any Class Specific or Vendor Specific descriptors;

  168. * find the first interface descriptor */

  169. config->extra = buffer;

  170. i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,

  171. USB_DT_INTERFACE, &n);

  172. config->extralen = i;

  173. if (n > 0)

  174. dev_dbg(ddev, "skipped %d descriptor%s after %s\n",

  175. n, plural(n), "configuration");

  176. buffer += i;

  177. size -= i;

  178.  
  179. /* Parse all the interface/altsetting descriptors */

  180. while (size > 0) {

  181. retval = usb_parse_interface(ddev, cfgno, config,

  182. buffer, size, inums, nalts);

  183. if (retval < 0)

  184. return retval;

  185.  
  186. buffer += retval;

  187. size -= retval;

  188. }

  189.  
  190. /* Check for missing altsettings */

  191. for (i = 0; i < nintf; ++i) {

  192. intfc = config->intf_cache[i];

  193. for (j = 0; j < intfc->num_altsetting; ++j) {

  194. for (n = 0; n < intfc->num_altsetting; ++n) {

  195. if (intfc->altsetting[n].desc.

  196. bAlternateSetting == j)

  197. break;

  198. }

  199. if (n >= intfc->num_altsetting)

  200. dev_warn(ddev, "config %d interface %d has no "

  201. "altsetting %d\n", cfgno, inums[i], j);

  202. }

  203. }

  204.  
  205. return 0;

  206. }

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值