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