• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   @param  ResetIsNeeded         The boolean to control whether skip the reset of the port.
647 
648   @retval EFI_SUCCESS           The device is enumerated (added or removed).
649   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.
650   @retval Others                Failed to enumerate the device.
651 
652 **/
653 EFI_STATUS
UsbEnumerateNewDev(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN BOOLEAN ResetIsNeeded)654 UsbEnumerateNewDev (
655   IN USB_INTERFACE        *HubIf,
656   IN UINT8                Port,
657   IN BOOLEAN              ResetIsNeeded
658   )
659 {
660   USB_BUS                 *Bus;
661   USB_HUB_API             *HubApi;
662   USB_DEVICE              *Child;
663   USB_DEVICE              *Parent;
664   EFI_USB_PORT_STATUS     PortState;
665   UINTN                   Address;
666   UINT8                   Config;
667   EFI_STATUS              Status;
668 
669   Parent  = HubIf->Device;
670   Bus     = Parent->Bus;
671   HubApi  = HubIf->HubApi;
672   Address = Bus->MaxDevices;
673 
674   gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
675 
676   //
677   // Hub resets the device for at least 10 milliseconds.
678   // Host learns device speed. If device is of low/full speed
679   // and the hub is a EHCI root hub, ResetPort will release
680   // the device to its companion UHCI and return an error.
681   //
682   if (ResetIsNeeded) {
683     Status = HubApi->ResetPort (HubIf, Port);
684     if (EFI_ERROR (Status)) {
685       DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
686 
687       return Status;
688     }
689     DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
690   } else {
691     DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d reset is skipped\n", Port));
692   }
693 
694   Child = UsbCreateDevice (HubIf, Port);
695 
696   if (Child == NULL) {
697     return EFI_OUT_OF_RESOURCES;
698   }
699 
700   //
701   // OK, now identify the device speed. After reset, hub
702   // fully knows the actual device speed.
703   //
704   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
705 
706   if (EFI_ERROR (Status)) {
707     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
708     goto ON_ERROR;
709   }
710 
711   if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
712     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: No device present at port %d\n", Port));
713     goto ON_ERROR;
714   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
715     Child->Speed      = EFI_USB_SPEED_SUPER;
716     Child->MaxPacket0 = 512;
717   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
718     Child->Speed      = EFI_USB_SPEED_HIGH;
719     Child->MaxPacket0 = 64;
720   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
721     Child->Speed      = EFI_USB_SPEED_LOW;
722     Child->MaxPacket0 = 8;
723   } else {
724     Child->Speed      = EFI_USB_SPEED_FULL;
725     Child->MaxPacket0 = 8;
726   }
727 
728   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
729 
730   if (((Child->Speed == EFI_USB_SPEED_LOW) || (Child->Speed == EFI_USB_SPEED_FULL)) &&
731       (Parent->Speed == EFI_USB_SPEED_HIGH)) {
732     //
733     // If the child is a low or full speed device, it is necessary to
734     // set the transaction translator. Port TT is 1-based.
735     // This is quite simple:
736     //  1. if parent is of high speed, then parent is our translator
737     //  2. otherwise use parent's translator.
738     //
739     Child->Translator.TranslatorHubAddress  = Parent->Address;
740     Child->Translator.TranslatorPortNumber  = (UINT8) (Port + 1);
741   } else {
742     Child->Translator = Parent->Translator;
743   }
744   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
745            Child->Translator.TranslatorHubAddress,
746            Child->Translator.TranslatorPortNumber));
747 
748   //
749   // After port is reset, hub establishes a signal path between
750   // the device and host (DEFALUT state). Device's registers are
751   // reset, use default address 0 (host enumerates one device at
752   // a time) , and ready to respond to control transfer at EP 0.
753   //
754 
755   //
756   // Host assigns an address to the device. Device completes the
757   // status stage with default address, then switches to new address.
758   // ADDRESS state. Address zero is reserved for root hub.
759   //
760   ASSERT (Bus->MaxDevices <= 256);
761   for (Address = 1; Address < Bus->MaxDevices; Address++) {
762     if (Bus->Devices[Address] == NULL) {
763       break;
764     }
765   }
766 
767   if (Address >= Bus->MaxDevices) {
768     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
769 
770     Status = EFI_ACCESS_DENIED;
771     goto ON_ERROR;
772   }
773 
774   Status                = UsbSetAddress (Child, (UINT8)Address);
775   Child->Address        = (UINT8)Address;
776   Bus->Devices[Address] = Child;
777 
778   if (EFI_ERROR (Status)) {
779     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
780     goto ON_ERROR;
781   }
782 
783   gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
784 
785   DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
786 
787   //
788   // Host sends a Get_Descriptor request to learn the max packet
789   // size of default pipe (only part of the device's descriptor).
790   //
791   Status = UsbGetMaxPacketSize0 (Child);
792 
793   if (EFI_ERROR (Status)) {
794     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
795     goto ON_ERROR;
796   }
797 
798   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
799 
800   //
801   // Host learns about the device's abilities by requesting device's
802   // entire descriptions.
803   //
804   Status = UsbBuildDescTable (Child);
805 
806   if (EFI_ERROR (Status)) {
807     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
808     goto ON_ERROR;
809   }
810 
811   //
812   // Select a default configuration: UEFI must set the configuration
813   // before the driver can connect to the device.
814   //
815   Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
816   Status = UsbSetConfig (Child, Config);
817 
818   if (EFI_ERROR (Status)) {
819     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
820     goto ON_ERROR;
821   }
822 
823   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
824 
825   //
826   // Host assigns and loads a device driver.
827   //
828   Status = UsbSelectConfig (Child, Config);
829 
830   if (EFI_ERROR (Status)) {
831     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
832     goto ON_ERROR;
833   }
834 
835   //
836   // Report Status Code to indicate USB device has been detected by hotplug
837   //
838   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
839     EFI_PROGRESS_CODE,
840     (EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG),
841     Bus->DevicePath
842     );
843   return EFI_SUCCESS;
844 
845 ON_ERROR:
846   //
847   // If reach here, it means the enumeration process on a given port is interrupted due to error.
848   // The s/w resources, including the assigned address(Address) and the allocated usb device data
849   // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when
850   // the device is unplugged from the port or DriverBindingStop() is invoked.
851   //
852   // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.
853   // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine
854   // to keep track of the mapping between actual address and request address. If the request address
855   // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI
856   // host controller driver will have wrong information, which will cause further transaction error.
857   //
858   // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.
859   //
860   return Status;
861 }
862 
863 
864 /**
865   Process the events on the port.
866 
867   @param  HubIf                 The HUB that has the device connected.
868   @param  Port                  The port index of the hub (started with zero).
869 
870   @retval EFI_SUCCESS           The device is enumerated (added or removed).
871   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.
872   @retval Others                Failed to enumerate the device.
873 
874 **/
875 EFI_STATUS
UsbEnumeratePort(IN USB_INTERFACE * HubIf,IN UINT8 Port)876 UsbEnumeratePort (
877   IN USB_INTERFACE        *HubIf,
878   IN UINT8                Port
879   )
880 {
881   USB_HUB_API             *HubApi;
882   USB_DEVICE              *Child;
883   EFI_USB_PORT_STATUS     PortState;
884   EFI_STATUS              Status;
885 
886   Child   = NULL;
887   HubApi  = HubIf->HubApi;
888 
889   //
890   // Host learns of the new device by polling the hub for port changes.
891   //
892   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
893 
894   if (EFI_ERROR (Status)) {
895     DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
896     return Status;
897   }
898 
899   //
900   // Only handle connection/enable/overcurrent/reset change.
901   // Usb super speed hub may report other changes, such as warm reset change. Ignore them.
902   //
903   if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
904     return EFI_SUCCESS;
905   }
906 
907   DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
908               Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));
909 
910   //
911   // This driver only process two kinds of events now: over current and
912   // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
913   // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
914   //
915 
916   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
917 
918     if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
919       //
920       // Case1:
921       //   Both OverCurrent and OverCurrentChange set, means over current occurs,
922       //   which probably is caused by short circuit. It has to wait system hardware
923       //   to perform recovery.
924       //
925       DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
926       return EFI_DEVICE_ERROR;
927 
928     }
929     //
930     // Case2:
931     //   Only OverCurrentChange set, means system has been recoveried from
932     //   over current. As a result, all ports are nearly power-off, so
933     //   it's necessary to detach and enumerate all ports again.
934     //
935     DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
936   }
937 
938   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
939     //
940     // Case3:
941     //   1.1 roothub port reg doesn't reflect over-current state, while its counterpart
942     //   on 2.0 roothub does. When over-current has influence on 1.1 device, the port
943     //   would be disabled, so it's also necessary to detach and enumerate again.
944     //
945     DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
946   }
947 
948   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
949     //
950     // Case4:
951     //   Device connected or disconnected normally.
952     //
953     DEBUG ((EFI_D_INFO, "UsbEnumeratePort: Device Connect/Disconnect Normally\n", Port));
954   }
955 
956   //
957   // Following as the above cases, it's safety to remove and create again.
958   //
959   Child = UsbFindChild (HubIf, Port);
960 
961   if (Child != NULL) {
962     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf));
963     UsbRemoveDevice (Child);
964   }
965 
966   if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
967     //
968     // Now, new device connected, enumerate and configure the device
969     //
970     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
971     if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
972       Status = UsbEnumerateNewDev (HubIf, Port, FALSE);
973     } else {
974       Status = UsbEnumerateNewDev (HubIf, Port, TRUE);
975     }
976 
977   } else {
978     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
979   }
980 
981   HubApi->ClearPortChange (HubIf, Port);
982   return Status;
983 }
984 
985 
986 /**
987   Enumerate all the changed hub ports.
988 
989   @param  Event                 The event that is triggered.
990   @param  Context               The context to the event.
991 
992 **/
993 VOID
994 EFIAPI
UsbHubEnumeration(IN EFI_EVENT Event,IN VOID * Context)995 UsbHubEnumeration (
996   IN EFI_EVENT            Event,
997   IN VOID                 *Context
998   )
999 {
1000   USB_INTERFACE           *HubIf;
1001   UINT8                   Byte;
1002   UINT8                   Bit;
1003   UINT8                   Index;
1004   USB_DEVICE              *Child;
1005 
1006   ASSERT (Context != NULL);
1007 
1008   HubIf = (USB_INTERFACE *) Context;
1009 
1010   for (Index = 0; Index < HubIf->NumOfPort; Index++) {
1011     Child = UsbFindChild (HubIf, Index);
1012     if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
1013       DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));
1014       UsbRemoveDevice (Child);
1015     }
1016   }
1017 
1018   if (HubIf->ChangeMap == NULL) {
1019     return ;
1020   }
1021 
1022   //
1023   // HUB starts its port index with 1.
1024   //
1025   Byte  = 0;
1026   Bit   = 1;
1027 
1028   for (Index = 0; Index < HubIf->NumOfPort; Index++) {
1029     if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
1030       UsbEnumeratePort (HubIf, Index);
1031     }
1032 
1033     USB_NEXT_BIT (Byte, Bit);
1034   }
1035 
1036   UsbHubAckHubStatus (HubIf->Device);
1037 
1038   gBS->FreePool (HubIf->ChangeMap);
1039   HubIf->ChangeMap = NULL;
1040   return ;
1041 }
1042 
1043 
1044 /**
1045   Enumerate all the changed hub ports.
1046 
1047   @param  Event                 The event that is triggered.
1048   @param  Context               The context to the event.
1049 
1050 **/
1051 VOID
1052 EFIAPI
UsbRootHubEnumeration(IN EFI_EVENT Event,IN VOID * Context)1053 UsbRootHubEnumeration (
1054   IN EFI_EVENT            Event,
1055   IN VOID                 *Context
1056   )
1057 {
1058   USB_INTERFACE           *RootHub;
1059   UINT8                   Index;
1060   USB_DEVICE              *Child;
1061 
1062   RootHub = (USB_INTERFACE *) Context;
1063 
1064   for (Index = 0; Index < RootHub->NumOfPort; Index++) {
1065     Child = UsbFindChild (RootHub, Index);
1066     if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
1067       DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));
1068       UsbRemoveDevice (Child);
1069     }
1070 
1071     UsbEnumeratePort (RootHub, Index);
1072   }
1073 }
1074