]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbEnumer.c
CommitLineData
e237e7ae 1/** @file\r
2\r
8616fc4c 3 Usb bus enumeration support.\r
4\r
d1102dba 5Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
e237e7ae 7\r
e237e7ae 8**/\r
9\r
10#include "UsbBus.h"\r
11\r
e237e7ae 12/**\r
8616fc4c 13 Return the endpoint descriptor in this interface.\r
e237e7ae 14\r
8616fc4c 15 @param UsbIf The interface to search in.\r
16 @param EpAddr The address of the endpoint to return.\r
e237e7ae 17\r
8616fc4c 18 @return The endpoint descriptor or NULL.\r
e237e7ae 19\r
20**/\r
21USB_ENDPOINT_DESC *\r
22UsbGetEndpointDesc (\r
1436aea4
MK
23 IN USB_INTERFACE *UsbIf,\r
24 IN UINT8 EpAddr\r
e237e7ae 25 )\r
26{\r
1436aea4
MK
27 USB_ENDPOINT_DESC *EpDesc;\r
28 UINT8 Index;\r
29 UINT8 NumEndpoints;\r
d1102dba 30\r
d17371e8 31 NumEndpoints = UsbIf->IfSetting->Desc.NumEndpoints;\r
d1102dba 32\r
d17371e8 33 for (Index = 0; Index < NumEndpoints; Index++) {\r
e237e7ae 34 EpDesc = UsbIf->IfSetting->Endpoints[Index];\r
35\r
36 if (EpDesc->Desc.EndpointAddress == EpAddr) {\r
37 return EpDesc;\r
38 }\r
39 }\r
40\r
41 return NULL;\r
42}\r
43\r
e237e7ae 44/**\r
8616fc4c 45 Free the resource used by USB interface.\r
e237e7ae 46\r
8616fc4c 47 @param UsbIf The USB interface to free.\r
e237e7ae 48\r
b659b503
RN
49 @retval EFI_ACCESS_DENIED The interface is still occupied.\r
50 @retval EFI_SUCCESS The interface is freed.\r
e237e7ae 51**/\r
b659b503 52EFI_STATUS\r
e237e7ae 53UsbFreeInterface (\r
1436aea4 54 IN USB_INTERFACE *UsbIf\r
e237e7ae 55 )\r
56{\r
1436aea4 57 EFI_STATUS Status;\r
e237e7ae 58\r
b659b503 59 UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
e237e7ae 60\r
b659b503
RN
61 Status = gBS->UninstallMultipleProtocolInterfaces (\r
62 UsbIf->Handle,\r
1436aea4
MK
63 &gEfiDevicePathProtocolGuid,\r
64 UsbIf->DevicePath,\r
65 &gEfiUsbIoProtocolGuid,\r
66 &UsbIf->UsbIo,\r
b659b503
RN
67 NULL\r
68 );\r
69 if (!EFI_ERROR (Status)) {\r
70 if (UsbIf->DevicePath != NULL) {\r
71 FreePool (UsbIf->DevicePath);\r
72 }\r
1436aea4 73\r
b659b503
RN
74 FreePool (UsbIf);\r
75 } else {\r
76 UsbOpenHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
e237e7ae 77 }\r
1436aea4 78\r
b659b503 79 return Status;\r
e237e7ae 80}\r
81\r
e237e7ae 82/**\r
83 Create an interface for the descriptor IfDesc. Each\r
84 device's configuration can have several interfaces.\r
85\r
8616fc4c 86 @param Device The device has the interface descriptor.\r
87 @param IfDesc The interface descriptor.\r
e237e7ae 88\r
89 @return The created USB interface for the descriptor, or NULL.\r
90\r
91**/\r
e237e7ae 92USB_INTERFACE *\r
93UsbCreateInterface (\r
1436aea4
MK
94 IN USB_DEVICE *Device,\r
95 IN USB_INTERFACE_DESC *IfDesc\r
e237e7ae 96 )\r
97{\r
1436aea4
MK
98 USB_DEVICE_PATH UsbNode;\r
99 USB_INTERFACE *UsbIf;\r
100 USB_INTERFACE *HubIf;\r
101 EFI_STATUS Status;\r
e237e7ae 102\r
103 UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
104\r
105 if (UsbIf == NULL) {\r
106 return NULL;\r
107 }\r
108\r
1436aea4
MK
109 UsbIf->Signature = USB_INTERFACE_SIGNATURE;\r
110 UsbIf->Device = Device;\r
111 UsbIf->IfDesc = IfDesc;\r
a1b749d0 112 ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r
1436aea4 113 UsbIf->IfSetting = IfDesc->Settings[IfDesc->ActiveIndex];\r
e61d30b0 114\r
115 CopyMem (\r
116 &(UsbIf->UsbIo),\r
117 &mUsbIoProtocol,\r
118 sizeof (EFI_USB_IO_PROTOCOL)\r
119 );\r
e237e7ae 120\r
121 //\r
122 // Install protocols for USBIO and device path\r
123 //\r
1436aea4
MK
124 UsbNode.Header.Type = MESSAGING_DEVICE_PATH;\r
125 UsbNode.Header.SubType = MSG_USB_DP;\r
126 UsbNode.ParentPortNumber = Device->ParentPort;\r
127 UsbNode.InterfaceNumber = UsbIf->IfSetting->Desc.InterfaceNumber;\r
e237e7ae 128\r
129 SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));\r
130\r
131 HubIf = Device->ParentIf;\r
132 ASSERT (HubIf != NULL);\r
133\r
134 UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);\r
135\r
136 if (UsbIf->DevicePath == NULL) {\r
87000d77 137 DEBUG ((DEBUG_ERROR, "UsbCreateInterface: failed to create device path\n"));\r
e237e7ae 138\r
139 Status = EFI_OUT_OF_RESOURCES;\r
140 goto ON_ERROR;\r
141 }\r
142\r
143 Status = gBS->InstallMultipleProtocolInterfaces (\r
144 &UsbIf->Handle,\r
145 &gEfiDevicePathProtocolGuid,\r
146 UsbIf->DevicePath,\r
147 &gEfiUsbIoProtocolGuid,\r
148 &UsbIf->UsbIo,\r
149 NULL\r
150 );\r
151\r
152 if (EFI_ERROR (Status)) {\r
87000d77 153 DEBUG ((DEBUG_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));\r
e237e7ae 154 goto ON_ERROR;\r
155 }\r
156\r
157 //\r
158 // Open USB Host Controller Protocol by Child\r
159 //\r
160 Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);\r
161\r
162 if (EFI_ERROR (Status)) {\r
163 gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 164 UsbIf->Handle,\r
e237e7ae 165 &gEfiDevicePathProtocolGuid,\r
166 UsbIf->DevicePath,\r
167 &gEfiUsbIoProtocolGuid,\r
168 &UsbIf->UsbIo,\r
169 NULL\r
170 );\r
171\r
87000d77 172 DEBUG ((DEBUG_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));\r
e237e7ae 173 goto ON_ERROR;\r
174 }\r
175\r
176 return UsbIf;\r
177\r
178ON_ERROR:\r
8616fc4c 179 if (UsbIf->DevicePath != NULL) {\r
d17371e8 180 FreePool (UsbIf->DevicePath);\r
e237e7ae 181 }\r
182\r
d17371e8 183 FreePool (UsbIf);\r
e237e7ae 184 return NULL;\r
185}\r
186\r
e237e7ae 187/**\r
8616fc4c 188 Free the resource used by this USB device.\r
e237e7ae 189\r
8616fc4c 190 @param Device The USB device to free.\r
e237e7ae 191\r
e237e7ae 192**/\r
e237e7ae 193VOID\r
194UsbFreeDevice (\r
1436aea4 195 IN USB_DEVICE *Device\r
e237e7ae 196 )\r
197{\r
198 if (Device->DevDesc != NULL) {\r
199 UsbFreeDevDesc (Device->DevDesc);\r
200 }\r
201\r
202 gBS->FreePool (Device);\r
203}\r
204\r
e237e7ae 205/**\r
206 Create a device which is on the parent's ParentPort port.\r
207\r
8616fc4c 208 @param ParentIf The parent HUB interface.\r
209 @param ParentPort The port on the HUB this device is connected to.\r
e237e7ae 210\r
8616fc4c 211 @return Created USB device, Or NULL.\r
e237e7ae 212\r
213**/\r
e237e7ae 214USB_DEVICE *\r
215UsbCreateDevice (\r
1436aea4
MK
216 IN USB_INTERFACE *ParentIf,\r
217 IN UINT8 ParentPort\r
e237e7ae 218 )\r
219{\r
1436aea4 220 USB_DEVICE *Device;\r
e237e7ae 221\r
222 ASSERT (ParentIf != NULL);\r
223\r
224 Device = AllocateZeroPool (sizeof (USB_DEVICE));\r
225\r
226 if (Device == NULL) {\r
227 return NULL;\r
228 }\r
229\r
1436aea4
MK
230 Device->Bus = ParentIf->Device->Bus;\r
231 Device->MaxPacket0 = 8;\r
232 Device->ParentAddr = ParentIf->Device->Address;\r
233 Device->ParentIf = ParentIf;\r
234 Device->ParentPort = ParentPort;\r
235 Device->Tier = (UINT8)(ParentIf->Device->Tier + 1);\r
e237e7ae 236 return Device;\r
237}\r
238\r
e237e7ae 239/**\r
240 Connect the USB interface with its driver. EFI USB bus will\r
d17371e8 241 create a USB interface for each separate interface descriptor.\r
e237e7ae 242\r
8616fc4c 243 @param UsbIf The interface to connect driver to.\r
e237e7ae 244\r
8616fc4c 245 @return EFI_SUCCESS Interface is managed by some driver.\r
246 @return Others Failed to locate a driver for this interface.\r
e237e7ae 247\r
248**/\r
e237e7ae 249EFI_STATUS\r
250UsbConnectDriver (\r
1436aea4 251 IN USB_INTERFACE *UsbIf\r
e237e7ae 252 )\r
253{\r
1436aea4
MK
254 EFI_STATUS Status;\r
255 EFI_TPL OldTpl;\r
e237e7ae 256\r
257 Status = EFI_SUCCESS;\r
258\r
259 //\r
260 // Hub is maintained by the USB bus driver. Otherwise try to\r
261 // connect drivers with this interface\r
262 //\r
263 if (UsbIsHubInterface (UsbIf)) {\r
87000d77 264 DEBUG ((DEBUG_INFO, "UsbConnectDriver: found a hub device\n"));\r
e237e7ae 265 Status = mUsbHubApi.Init (UsbIf);\r
e237e7ae 266 } else {\r
267 //\r
268 // This function is called in both UsbIoControlTransfer and\r
269 // the timer callback in hub enumeration. So, at least it is\r
270 // called at TPL_CALLBACK. Some driver sitting on USB has\r
271 // twisted TPL used. It should be no problem for us to connect\r
272 // or disconnect at CALLBACK.\r
273 //\r
d1102dba 274\r
ecb575d9 275 //\r
276 // Only recursively wanted usb child device\r
277 //\r
278 if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {\r
1436aea4 279 OldTpl = UsbGetCurrentTpl ();\r
87000d77 280 DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));\r
e237e7ae 281\r
ecb575d9 282 gBS->RestoreTPL (TPL_CALLBACK);\r
e237e7ae 283\r
1436aea4
MK
284 Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);\r
285 UsbIf->IsManaged = (BOOLEAN) !EFI_ERROR (Status);\r
e237e7ae 286\r
1436aea4 287 DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl ()));\r
ecb575d9 288 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
e237e7ae 289\r
ecb575d9 290 gBS->RaiseTPL (OldTpl);\r
291 }\r
e237e7ae 292 }\r
293\r
294 return Status;\r
295}\r
296\r
e237e7ae 297/**\r
298 Select an alternate setting for the interface.\r
299 Each interface can have several mutually exclusive\r
300 settings. Only one setting is active. It will\r
301 also reset its endpoints' toggle to zero.\r
302\r
8616fc4c 303 @param IfDesc The interface descriptor to set.\r
304 @param Alternate The alternate setting number to locate.\r
e237e7ae 305\r
8616fc4c 306 @retval EFI_NOT_FOUND There is no setting with this alternate index.\r
e237e7ae 307 @retval EFI_SUCCESS The interface is set to Alternate setting.\r
308\r
309**/\r
310EFI_STATUS\r
311UsbSelectSetting (\r
1436aea4
MK
312 IN USB_INTERFACE_DESC *IfDesc,\r
313 IN UINT8 Alternate\r
e237e7ae 314 )\r
315{\r
1436aea4
MK
316 USB_INTERFACE_SETTING *Setting;\r
317 UINTN Index;\r
e237e7ae 318\r
319 //\r
320 // Locate the active alternate setting\r
321 //\r
322 Setting = NULL;\r
323\r
324 for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {\r
a1b749d0 325 ASSERT (Index < USB_MAX_INTERFACE_SETTING);\r
e237e7ae 326 Setting = IfDesc->Settings[Index];\r
327\r
328 if (Setting->Desc.AlternateSetting == Alternate) {\r
329 break;\r
330 }\r
331 }\r
332\r
333 if (Index == IfDesc->NumOfSetting) {\r
334 return EFI_NOT_FOUND;\r
335 }\r
336\r
337 IfDesc->ActiveIndex = Index;\r
338\r
cb0b858d 339 ASSERT (Setting != NULL);\r
1436aea4
MK
340 DEBUG ((\r
341 DEBUG_INFO,\r
342 "UsbSelectSetting: setting %d selected for interface %d\n",\r
343 Alternate,\r
344 Setting->Desc.InterfaceNumber\r
345 ));\r
e237e7ae 346\r
347 //\r
348 // Reset the endpoint toggle to zero\r
349 //\r
350 for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {\r
351 Setting->Endpoints[Index]->Toggle = 0;\r
352 }\r
353\r
354 return EFI_SUCCESS;\r
355}\r
356\r
e237e7ae 357/**\r
358 Select a new configuration for the device. Each\r
359 device may support several configurations.\r
360\r
8616fc4c 361 @param Device The device to select configuration.\r
362 @param ConfigValue The index of the configuration ( != 0).\r
e237e7ae 363\r
8616fc4c 364 @retval EFI_NOT_FOUND There is no configuration with the index.\r
365 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
e237e7ae 366 @retval EFI_SUCCESS The configuration is selected.\r
367\r
368**/\r
369EFI_STATUS\r
370UsbSelectConfig (\r
1436aea4
MK
371 IN USB_DEVICE *Device,\r
372 IN UINT8 ConfigValue\r
e237e7ae 373 )\r
374{\r
1436aea4
MK
375 USB_DEVICE_DESC *DevDesc;\r
376 USB_CONFIG_DESC *ConfigDesc;\r
377 USB_INTERFACE_DESC *IfDesc;\r
378 USB_INTERFACE *UsbIf;\r
379 EFI_STATUS Status;\r
380 UINT8 Index;\r
e237e7ae 381\r
382 //\r
383 // Locate the active config, then set the device's pointer\r
384 //\r
1436aea4
MK
385 DevDesc = Device->DevDesc;\r
386 ConfigDesc = NULL;\r
e237e7ae 387\r
388 for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {\r
389 ConfigDesc = DevDesc->Configs[Index];\r
390\r
391 if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {\r
392 break;\r
393 }\r
394 }\r
395\r
396 if (Index == DevDesc->Desc.NumConfigurations) {\r
397 return EFI_NOT_FOUND;\r
398 }\r
399\r
400 Device->ActiveConfig = ConfigDesc;\r
401\r
1436aea4
MK
402 DEBUG ((\r
403 DEBUG_INFO,\r
404 "UsbSelectConfig: config %d selected for device %d\n",\r
405 ConfigValue,\r
406 Device->Address\r
407 ));\r
e237e7ae 408\r
409 //\r
410 // Create interfaces for each USB interface descriptor.\r
411 //\r
412 for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {\r
413 //\r
414 // First select the default interface setting, and reset\r
415 // the endpoint toggles to zero for its endpoints.\r
416 //\r
417 IfDesc = ConfigDesc->Interfaces[Index];\r
418 UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);\r
419\r
420 //\r
421 // Create a USB_INTERFACE and install USB_IO and other protocols\r
422 //\r
423 UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);\r
424\r
425 if (UsbIf == NULL) {\r
4d3d422d 426 Device->NumOfInterface = Index;\r
e237e7ae 427 return EFI_OUT_OF_RESOURCES;\r
428 }\r
429\r
a1b749d0 430 ASSERT (Index < USB_MAX_INTERFACE);\r
e237e7ae 431 Device->Interfaces[Index] = UsbIf;\r
432\r
433 //\r
434 // Connect the device to drivers, if it failed, ignore\r
435 // the error. Don't let the unsupported interfaces to block\r
436 // the supported interfaces.\r
437 //\r
438 Status = UsbConnectDriver (UsbIf);\r
439\r
440 if (EFI_ERROR (Status)) {\r
1dac45f5
LE
441 DEBUG ((\r
442 DEBUG_WARN,\r
46f51898 443 "UsbSelectConfig: failed to connect driver - %r, ignored\n",\r
1dac45f5
LE
444 Status\r
445 ));\r
e237e7ae 446 }\r
447 }\r
448\r
449 Device->NumOfInterface = Index;\r
450\r
451 return EFI_SUCCESS;\r
452}\r
453\r
e237e7ae 454/**\r
455 Disconnect the USB interface with its driver.\r
456\r
8616fc4c 457 @param UsbIf The interface to disconnect driver from.\r
e237e7ae 458\r
e237e7ae 459**/\r
127884c5 460EFI_STATUS\r
e237e7ae 461UsbDisconnectDriver (\r
1436aea4 462 IN USB_INTERFACE *UsbIf\r
e237e7ae 463 )\r
464{\r
1436aea4
MK
465 EFI_TPL OldTpl;\r
466 EFI_STATUS Status;\r
e237e7ae 467\r
468 //\r
469 // Release the hub if it's a hub controller, otherwise\r
470 // disconnect the driver if it is managed by other drivers.\r
471 //\r
127884c5 472 Status = EFI_SUCCESS;\r
e237e7ae 473 if (UsbIf->IsHub) {\r
127884c5 474 Status = UsbIf->HubApi->Release (UsbIf);\r
e237e7ae 475 } else if (UsbIf->IsManaged) {\r
476 //\r
477 // This function is called in both UsbIoControlTransfer and\r
478 // the timer callback in hub enumeration. So, at least it is\r
479 // called at TPL_CALLBACK. Some driver sitting on USB has\r
480 // twisted TPL used. It should be no problem for us to connect\r
481 // or disconnect at CALLBACK.\r
482 //\r
1436aea4 483 OldTpl = UsbGetCurrentTpl ();\r
87000d77 484 DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));\r
e237e7ae 485\r
486 gBS->RestoreTPL (TPL_CALLBACK);\r
487\r
a1b749d0 488 Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);\r
127884c5
FT
489 if (!EFI_ERROR (Status)) {\r
490 UsbIf->IsManaged = FALSE;\r
491 }\r
d1102dba 492\r
1436aea4 493 DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl (), Status));\r
e237e7ae 494 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
495\r
496 gBS->RaiseTPL (OldTpl);\r
497 }\r
d1102dba 498\r
127884c5 499 return Status;\r
e237e7ae 500}\r
501\r
e237e7ae 502/**\r
8616fc4c 503 Remove the current device configuration.\r
e237e7ae 504\r
8616fc4c 505 @param Device The USB device to remove configuration from.\r
e237e7ae 506\r
e237e7ae 507**/\r
127884c5 508EFI_STATUS\r
e237e7ae 509UsbRemoveConfig (\r
1436aea4 510 IN USB_DEVICE *Device\r
e237e7ae 511 )\r
512{\r
1436aea4
MK
513 USB_INTERFACE *UsbIf;\r
514 UINTN Index;\r
515 EFI_STATUS Status;\r
516 EFI_STATUS ReturnStatus;\r
e237e7ae 517\r
518 //\r
519 // Remove each interface of the device\r
520 //\r
127884c5 521 ReturnStatus = EFI_SUCCESS;\r
d1102dba 522 for (Index = 0; Index < Device->NumOfInterface; Index++) {\r
a1b749d0 523 ASSERT (Index < USB_MAX_INTERFACE);\r
e237e7ae 524 UsbIf = Device->Interfaces[Index];\r
525\r
526 if (UsbIf == NULL) {\r
527 continue;\r
528 }\r
529\r
127884c5
FT
530 Status = UsbDisconnectDriver (UsbIf);\r
531 if (!EFI_ERROR (Status)) {\r
b659b503
RN
532 Status = UsbFreeInterface (UsbIf);\r
533 if (EFI_ERROR (Status)) {\r
534 UsbConnectDriver (UsbIf);\r
535 }\r
536 }\r
537\r
538 if (!EFI_ERROR (Status)) {\r
127884c5
FT
539 Device->Interfaces[Index] = NULL;\r
540 } else {\r
541 ReturnStatus = Status;\r
542 }\r
e237e7ae 543 }\r
544\r
1436aea4 545 Device->ActiveConfig = NULL;\r
127884c5 546 return ReturnStatus;\r
e237e7ae 547}\r
548\r
e237e7ae 549/**\r
550 Remove the device and all its children from the bus.\r
551\r
8616fc4c 552 @param Device The device to remove.\r
e237e7ae 553\r
8616fc4c 554 @retval EFI_SUCCESS The device is removed.\r
e237e7ae 555\r
556**/\r
557EFI_STATUS\r
558UsbRemoveDevice (\r
1436aea4 559 IN USB_DEVICE *Device\r
e237e7ae 560 )\r
561{\r
1436aea4
MK
562 USB_BUS *Bus;\r
563 USB_DEVICE *Child;\r
564 EFI_STATUS Status;\r
565 EFI_STATUS ReturnStatus;\r
566 UINTN Index;\r
e237e7ae 567\r
568 Bus = Device->Bus;\r
569\r
570 //\r
571 // Remove all the devices on its downstream ports. Search from devices[1].\r
572 // Devices[0] is the root hub.\r
573 //\r
127884c5 574 ReturnStatus = EFI_SUCCESS;\r
a9292c13 575 for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
e237e7ae 576 Child = Bus->Devices[Index];\r
577\r
578 if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {\r
579 continue;\r
580 }\r
581\r
582 Status = UsbRemoveDevice (Child);\r
583\r
127884c5 584 if (!EFI_ERROR (Status)) {\r
e237e7ae 585 Bus->Devices[Index] = NULL;\r
127884c5
FT
586 } else {\r
587 Bus->Devices[Index]->DisconnectFail = TRUE;\r
1436aea4 588 ReturnStatus = Status;\r
87000d77 589 DEBUG ((DEBUG_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device));\r
e237e7ae 590 }\r
591 }\r
592\r
127884c5
FT
593 if (EFI_ERROR (ReturnStatus)) {\r
594 return ReturnStatus;\r
595 }\r
e237e7ae 596\r
127884c5 597 Status = UsbRemoveConfig (Device);\r
e237e7ae 598\r
127884c5 599 if (!EFI_ERROR (Status)) {\r
1436aea4 600 DEBUG ((DEBUG_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));\r
e237e7ae 601\r
127884c5
FT
602 ASSERT (Device->Address < Bus->MaxDevices);\r
603 Bus->Devices[Device->Address] = NULL;\r
604 UsbFreeDevice (Device);\r
605 } else {\r
606 Bus->Devices[Device->Address]->DisconnectFail = TRUE;\r
607 }\r
1436aea4 608\r
127884c5 609 return Status;\r
e237e7ae 610}\r
611\r
e237e7ae 612/**\r
8616fc4c 613 Find the child device on the hub's port.\r
e237e7ae 614\r
8616fc4c 615 @param HubIf The hub interface.\r
616 @param Port The port of the hub this child is connected to.\r
e237e7ae 617\r
8616fc4c 618 @return The device on the hub's port, or NULL if there is none.\r
e237e7ae 619\r
620**/\r
e237e7ae 621USB_DEVICE *\r
622UsbFindChild (\r
1436aea4
MK
623 IN USB_INTERFACE *HubIf,\r
624 IN UINT8 Port\r
e237e7ae 625 )\r
626{\r
1436aea4
MK
627 USB_DEVICE *Device;\r
628 USB_BUS *Bus;\r
629 UINTN Index;\r
e237e7ae 630\r
631 Bus = HubIf->Device->Bus;\r
632\r
633 //\r
634 // Start checking from device 1, device 0 is the root hub\r
635 //\r
a9292c13 636 for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
e237e7ae 637 Device = Bus->Devices[Index];\r
638\r
639 if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&\r
1436aea4
MK
640 (Device->ParentPort == Port))\r
641 {\r
e237e7ae 642 return Device;\r
643 }\r
644 }\r
645\r
646 return NULL;\r
647}\r
648\r
e237e7ae 649/**\r
650 Enumerate and configure the new device on the port of this HUB interface.\r
651\r
8616fc4c 652 @param HubIf The HUB that has the device connected.\r
653 @param Port The port index of the hub (started with zero).\r
bf4808d6 654 @param ResetIsNeeded The boolean to control whether skip the reset of the port.\r
e237e7ae 655\r
8616fc4c 656 @retval EFI_SUCCESS The device is enumerated (added or removed).\r
657 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.\r
658 @retval Others Failed to enumerate the device.\r
e237e7ae 659\r
660**/\r
e237e7ae 661EFI_STATUS\r
662UsbEnumerateNewDev (\r
1436aea4
MK
663 IN USB_INTERFACE *HubIf,\r
664 IN UINT8 Port,\r
665 IN BOOLEAN ResetIsNeeded\r
e237e7ae 666 )\r
667{\r
1436aea4
MK
668 USB_BUS *Bus;\r
669 USB_HUB_API *HubApi;\r
670 USB_DEVICE *Child;\r
671 USB_DEVICE *Parent;\r
672 EFI_USB_PORT_STATUS PortState;\r
673 UINTN Address;\r
674 UINT8 Config;\r
675 EFI_STATUS Status;\r
e237e7ae 676\r
e237e7ae 677 Parent = HubIf->Device;\r
678 Bus = Parent->Bus;\r
d1102dba 679 HubApi = HubIf->HubApi;\r
a9292c13 680 Address = Bus->MaxDevices;\r
681\r
41e8ff27 682 gBS->Stall (USB_WAIT_PORT_STABLE_STALL);\r
d1102dba 683\r
e237e7ae 684 //\r
685 // Hub resets the device for at least 10 milliseconds.\r
686 // Host learns device speed. If device is of low/full speed\r
687 // and the hub is a EHCI root hub, ResetPort will release\r
688 // the device to its companion UHCI and return an error.\r
689 //\r
bf4808d6
FT
690 if (ResetIsNeeded) {\r
691 Status = HubApi->ResetPort (HubIf, Port);\r
692 if (EFI_ERROR (Status)) {\r
87000d77 693 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));\r
d1102dba 694\r
bf4808d6
FT
695 return Status;\r
696 }\r
1436aea4
MK
697\r
698 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));\r
bf4808d6 699 } else {\r
1436aea4 700 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: hub port %d reset is skipped\n", Port));\r
e237e7ae 701 }\r
702\r
e237e7ae 703 Child = UsbCreateDevice (HubIf, Port);\r
704\r
705 if (Child == NULL) {\r
706 return EFI_OUT_OF_RESOURCES;\r
707 }\r
708\r
709 //\r
710 // OK, now identify the device speed. After reset, hub\r
711 // fully knows the actual device speed.\r
712 //\r
713 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
714\r
715 if (EFI_ERROR (Status)) {\r
87000d77 716 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));\r
e237e7ae 717 goto ON_ERROR;\r
718 }\r
719\r
92870c98 720 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
87000d77 721 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: No device present at port %d\n", Port));\r
1702e2ce 722 Status = EFI_NOT_FOUND;\r
92870c98 723 goto ON_ERROR;\r
1436aea4 724 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {\r
92870c98 725 Child->Speed = EFI_USB_SPEED_SUPER;\r
726 Child->MaxPacket0 = 512;\r
e237e7ae 727 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
92870c98 728 Child->Speed = EFI_USB_SPEED_HIGH;\r
729 Child->MaxPacket0 = 64;\r
730 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
731 Child->Speed = EFI_USB_SPEED_LOW;\r
732 Child->MaxPacket0 = 8;\r
e237e7ae 733 } else {\r
92870c98 734 Child->Speed = EFI_USB_SPEED_FULL;\r
735 Child->MaxPacket0 = 8;\r
e237e7ae 736 }\r
737\r
1436aea4 738 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));\r
e237e7ae 739\r
16d718a5 740 if (((Child->Speed == EFI_USB_SPEED_LOW) || (Child->Speed == EFI_USB_SPEED_FULL)) &&\r
1436aea4
MK
741 (Parent->Speed == EFI_USB_SPEED_HIGH))\r
742 {\r
e237e7ae 743 //\r
16d718a5 744 // If the child is a low or full speed device, it is necessary to\r
b4c24e2d 745 // set the transaction translator. Port TT is 1-based.\r
746 // This is quite simple:\r
e237e7ae 747 // 1. if parent is of high speed, then parent is our translator\r
748 // 2. otherwise use parent's translator.\r
749 //\r
1436aea4
MK
750 Child->Translator.TranslatorHubAddress = Parent->Address;\r
751 Child->Translator.TranslatorPortNumber = (UINT8)(Port + 1);\r
16d718a5 752 } else {\r
753 Child->Translator = Parent->Translator;\r
e237e7ae 754 }\r
1436aea4
MK
755\r
756 DEBUG ((\r
757 DEBUG_INFO,\r
758 "UsbEnumerateNewDev: device uses translator (%d, %d)\n",\r
759 Child->Translator.TranslatorHubAddress,\r
760 Child->Translator.TranslatorPortNumber\r
761 ));\r
e237e7ae 762\r
763 //\r
764 // After port is reset, hub establishes a signal path between\r
13a623cf 765 // the device and host (DEFAULT state). Device's registers are\r
e237e7ae 766 // reset, use default address 0 (host enumerates one device at\r
767 // a time) , and ready to respond to control transfer at EP 0.\r
768 //\r
769\r
e237e7ae 770 //\r
771 // Host assigns an address to the device. Device completes the\r
772 // status stage with default address, then switches to new address.\r
773 // ADDRESS state. Address zero is reserved for root hub.\r
774 //\r
a9292c13 775 ASSERT (Bus->MaxDevices <= 256);\r
776 for (Address = 1; Address < Bus->MaxDevices; Address++) {\r
e237e7ae 777 if (Bus->Devices[Address] == NULL) {\r
778 break;\r
779 }\r
780 }\r
781\r
a9292c13 782 if (Address >= Bus->MaxDevices) {\r
87000d77 783 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));\r
e237e7ae 784\r
785 Status = EFI_ACCESS_DENIED;\r
786 goto ON_ERROR;\r
787 }\r
788\r
92870c98 789 Status = UsbSetAddress (Child, (UINT8)Address);\r
790 Child->Address = (UINT8)Address;\r
e237e7ae 791 Bus->Devices[Address] = Child;\r
e237e7ae 792\r
793 if (EFI_ERROR (Status)) {\r
87000d77 794 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));\r
e237e7ae 795 goto ON_ERROR;\r
796 }\r
92870c98 797\r
41e8ff27 798 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
e237e7ae 799\r
87000d77 800 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));\r
e237e7ae 801\r
92870c98 802 //\r
803 // Host sends a Get_Descriptor request to learn the max packet\r
804 // size of default pipe (only part of the device's descriptor).\r
805 //\r
806 Status = UsbGetMaxPacketSize0 (Child);\r
807\r
808 if (EFI_ERROR (Status)) {\r
87000d77 809 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
92870c98 810 goto ON_ERROR;\r
811 }\r
812\r
1436aea4 813 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
92870c98 814\r
e237e7ae 815 //\r
ac644614 816 // Host learns about the device's abilities by requesting device's\r
e237e7ae 817 // entire descriptions.\r
818 //\r
819 Status = UsbBuildDescTable (Child);\r
820\r
821 if (EFI_ERROR (Status)) {\r
87000d77 822 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));\r
e237e7ae 823 goto ON_ERROR;\r
824 }\r
825\r
826 //\r
827 // Select a default configuration: UEFI must set the configuration\r
828 // before the driver can connect to the device.\r
829 //\r
830 Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;\r
831 Status = UsbSetConfig (Child, Config);\r
832\r
833 if (EFI_ERROR (Status)) {\r
87000d77 834 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));\r
e237e7ae 835 goto ON_ERROR;\r
836 }\r
837\r
1436aea4 838 DEBUG ((DEBUG_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));\r
e237e7ae 839\r
840 //\r
841 // Host assigns and loads a device driver.\r
842 //\r
843 Status = UsbSelectConfig (Child, Config);\r
844\r
845 if (EFI_ERROR (Status)) {\r
87000d77 846 DEBUG ((DEBUG_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));\r
e237e7ae 847 goto ON_ERROR;\r
848 }\r
849\r
37623a5c 850 //\r
851 // Report Status Code to indicate USB device has been detected by hotplug\r
852 //\r
853 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
854 EFI_PROGRESS_CODE,\r
855 (EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG),\r
856 Bus->DevicePath\r
857 );\r
e237e7ae 858 return EFI_SUCCESS;\r
859\r
860ON_ERROR:\r
7a4d52ad 861 //\r
862 // If reach here, it means the enumeration process on a given port is interrupted due to error.\r
863 // The s/w resources, including the assigned address(Address) and the allocated usb device data\r
864 // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when\r
865 // the device is unplugged from the port or DriverBindingStop() is invoked.\r
866 //\r
867 // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.\r
868 // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine\r
869 // to keep track of the mapping between actual address and request address. If the request address\r
870 // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI\r
871 // host controller driver will have wrong information, which will cause further transaction error.\r
872 //\r
873 // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.\r
874 //\r
e237e7ae 875 return Status;\r
876}\r
877\r
e237e7ae 878/**\r
879 Process the events on the port.\r
880\r
8616fc4c 881 @param HubIf The HUB that has the device connected.\r
882 @param Port The port index of the hub (started with zero).\r
e237e7ae 883\r
8616fc4c 884 @retval EFI_SUCCESS The device is enumerated (added or removed).\r
885 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device.\r
886 @retval Others Failed to enumerate the device.\r
e237e7ae 887\r
888**/\r
e237e7ae 889EFI_STATUS\r
890UsbEnumeratePort (\r
1436aea4
MK
891 IN USB_INTERFACE *HubIf,\r
892 IN UINT8 Port\r
e237e7ae 893 )\r
894{\r
1436aea4
MK
895 USB_HUB_API *HubApi;\r
896 USB_DEVICE *Child;\r
897 EFI_USB_PORT_STATUS PortState;\r
898 EFI_STATUS Status;\r
e237e7ae 899\r
1436aea4
MK
900 Child = NULL;\r
901 HubApi = HubIf->HubApi;\r
e237e7ae 902\r
903 //\r
904 // Host learns of the new device by polling the hub for port changes.\r
905 //\r
906 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
907\r
908 if (EFI_ERROR (Status)) {\r
87000d77 909 DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));\r
e237e7ae 910 return Status;\r
911 }\r
912\r
92870c98 913 //\r
914 // Only handle connection/enable/overcurrent/reset change.\r
915 // Usb super speed hub may report other changes, such as warm reset change. Ignore them.\r
916 //\r
917 if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
e237e7ae 918 return EFI_SUCCESS;\r
919 }\r
920\r
1436aea4
MK
921 DEBUG ((\r
922 DEBUG_INFO,\r
923 "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",\r
924 Port,\r
925 PortState.PortStatus,\r
926 PortState.PortChangeStatus,\r
927 HubIf\r
928 ));\r
e237e7ae 929\r
930 //\r
931 // This driver only process two kinds of events now: over current and\r
932 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.\r
933 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.\r
934 //\r
d1102dba
LG
935\r
936 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {\r
50fa1b3a 937 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
938 //\r
41e8ff27 939 // Case1:\r
d1102dba 940 // Both OverCurrent and OverCurrentChange set, means over current occurs,\r
41e8ff27 941 // which probably is caused by short circuit. It has to wait system hardware\r
942 // to perform recovery.\r
50fa1b3a 943 //\r
1096a9b0 944 DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: Critical Over Current (port %d)\n", Port));\r
50fa1b3a 945 return EFI_DEVICE_ERROR;\r
d1102dba 946 }\r
1436aea4 947\r
41e8ff27 948 //\r
949 // Case2:\r
d1102dba 950 // Only OverCurrentChange set, means system has been recoveried from\r
41e8ff27 951 // over current. As a result, all ports are nearly power-off, so\r
d1102dba 952 // it's necessary to detach and enumerate all ports again.\r
41e8ff27 953 //\r
1096a9b0 954 DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current (port %d)\n", Port));\r
50fa1b3a 955 }\r
e237e7ae 956\r
d1102dba 957 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {\r
e237e7ae 958 //\r
41e8ff27 959 // Case3:\r
960 // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart\r
d1102dba 961 // on 2.0 roothub does. When over-current has influence on 1.1 device, the port\r
41e8ff27 962 // would be disabled, so it's also necessary to detach and enumerate again.\r
e237e7ae 963 //\r
1096a9b0 964 DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current (port %d)\n", Port));\r
50fa1b3a 965 }\r
d1102dba 966\r
50fa1b3a 967 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
968 //\r
41e8ff27 969 // Case4:\r
d1102dba 970 // Device connected or disconnected normally.\r
50fa1b3a 971 //\r
1096a9b0 972 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: Device Connect/Disconnect Normally (port %d)\n", Port));\r
50fa1b3a 973 }\r
e237e7ae 974\r
d1102dba 975 //\r
41e8ff27 976 // Following as the above cases, it's safety to remove and create again.\r
50fa1b3a 977 //\r
978 Child = UsbFindChild (HubIf, Port);\r
d1102dba 979\r
50fa1b3a 980 if (Child != NULL) {\r
1436aea4 981 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf));\r
50fa1b3a 982 UsbRemoveDevice (Child);\r
e237e7ae 983 }\r
d1102dba 984\r
50fa1b3a 985 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
986 //\r
d1102dba 987 // Now, new device connected, enumerate and configure the device\r
50fa1b3a 988 //\r
1436aea4 989 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));\r
bf4808d6
FT
990 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
991 Status = UsbEnumerateNewDev (HubIf, Port, FALSE);\r
992 } else {\r
993 Status = UsbEnumerateNewDev (HubIf, Port, TRUE);\r
994 }\r
50fa1b3a 995 } else {\r
1436aea4 996 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
50fa1b3a 997 }\r
d1102dba 998\r
e237e7ae 999 HubApi->ClearPortChange (HubIf, Port);\r
1000 return Status;\r
1001}\r
1002\r
e237e7ae 1003/**\r
8616fc4c 1004 Enumerate all the changed hub ports.\r
e237e7ae 1005\r
8616fc4c 1006 @param Event The event that is triggered.\r
1007 @param Context The context to the event.\r
e237e7ae 1008\r
e237e7ae 1009**/\r
1010VOID\r
8616fc4c 1011EFIAPI\r
e237e7ae 1012UsbHubEnumeration (\r
1436aea4
MK
1013 IN EFI_EVENT Event,\r
1014 IN VOID *Context\r
e237e7ae 1015 )\r
1016{\r
1436aea4
MK
1017 USB_INTERFACE *HubIf;\r
1018 UINT8 Byte;\r
1019 UINT8 Bit;\r
1020 UINT8 Index;\r
1021 USB_DEVICE *Child;\r
d1102dba 1022\r
ec30be9e 1023 ASSERT (Context != NULL);\r
e237e7ae 1024\r
1436aea4 1025 HubIf = (USB_INTERFACE *)Context;\r
e237e7ae 1026\r
127884c5
FT
1027 for (Index = 0; Index < HubIf->NumOfPort; Index++) {\r
1028 Child = UsbFindChild (HubIf, Index);\r
1029 if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {\r
1436aea4 1030 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));\r
127884c5
FT
1031 UsbRemoveDevice (Child);\r
1032 }\r
1033 }\r
1034\r
e237e7ae 1035 if (HubIf->ChangeMap == NULL) {\r
1436aea4 1036 return;\r
e237e7ae 1037 }\r
1038\r
1039 //\r
1040 // HUB starts its port index with 1.\r
1041 //\r
1436aea4
MK
1042 Byte = 0;\r
1043 Bit = 1;\r
e237e7ae 1044\r
1045 for (Index = 0; Index < HubIf->NumOfPort; Index++) {\r
1046 if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {\r
1047 UsbEnumeratePort (HubIf, Index);\r
1048 }\r
1049\r
1050 USB_NEXT_BIT (Byte, Bit);\r
1051 }\r
1052\r
1053 UsbHubAckHubStatus (HubIf->Device);\r
1054\r
1055 gBS->FreePool (HubIf->ChangeMap);\r
1056 HubIf->ChangeMap = NULL;\r
1436aea4 1057 return;\r
e237e7ae 1058}\r
1059\r
e237e7ae 1060/**\r
8616fc4c 1061 Enumerate all the changed hub ports.\r
e237e7ae 1062\r
8616fc4c 1063 @param Event The event that is triggered.\r
1064 @param Context The context to the event.\r
e237e7ae 1065\r
e237e7ae 1066**/\r
1067VOID\r
eb1f5ab3 1068EFIAPI\r
e237e7ae 1069UsbRootHubEnumeration (\r
1436aea4
MK
1070 IN EFI_EVENT Event,\r
1071 IN VOID *Context\r
e237e7ae 1072 )\r
1073{\r
1436aea4
MK
1074 USB_INTERFACE *RootHub;\r
1075 UINT8 Index;\r
1076 USB_DEVICE *Child;\r
e237e7ae 1077\r
1436aea4 1078 RootHub = (USB_INTERFACE *)Context;\r
e237e7ae 1079\r
1080 for (Index = 0; Index < RootHub->NumOfPort; Index++) {\r
127884c5
FT
1081 Child = UsbFindChild (RootHub, Index);\r
1082 if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {\r
1436aea4 1083 DEBUG ((DEBUG_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));\r
127884c5
FT
1084 UsbRemoveDevice (Child);\r
1085 }\r
d1102dba 1086\r
e237e7ae 1087 UsbEnumeratePort (RootHub, Index);\r
1088 }\r
1089}\r