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