1 /** @file
2 
3   The UHCI driver model and HC protocol routines.
4 
5 Copyright (c) 2004 - 2015, 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 "Uhci.h"
17 
18 
19 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
20   UhciDriverBindingSupported,
21   UhciDriverBindingStart,
22   UhciDriverBindingStop,
23   0x20,
24   NULL,
25   NULL
26 };
27 
28 /**
29   Provides software reset for the USB host controller according to UEFI 2.0 spec.
30 
31   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
32   @param  Attributes             A bit mask of the reset operation to perform.  See
33                                  below for a list of the supported bit mask values.
34 
35   @return EFI_SUCCESS            The reset operation succeeded.
36   @return EFI_INVALID_PARAMETER  Attributes is not valid.
37   @return EFI_UNSUPPORTED        This type of reset is not currently supported.
38   @return EFI_DEVICE_ERROR       Other errors.
39 
40 **/
41 EFI_STATUS
42 EFIAPI
Uhci2Reset(IN EFI_USB2_HC_PROTOCOL * This,IN UINT16 Attributes)43 Uhci2Reset (
44   IN EFI_USB2_HC_PROTOCOL   *This,
45   IN UINT16                 Attributes
46   )
47 {
48   USB_HC_DEV          *Uhc;
49   EFI_TPL             OldTpl;
50 
51   if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
52       (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
53     return EFI_UNSUPPORTED;
54   }
55 
56   Uhc = UHC_FROM_USB2_HC_PROTO (This);
57 
58   if (Uhc->DevicePath != NULL) {
59     //
60     // Report Status Code to indicate reset happens
61     //
62     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
63       EFI_PROGRESS_CODE,
64       (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
65       Uhc->DevicePath
66       );
67   }
68 
69   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
70 
71   switch (Attributes) {
72   case EFI_USB_HC_RESET_GLOBAL:
73     //
74     // Stop schedule and set the Global Reset bit in the command register
75     //
76     UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
77     UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
78 
79     gBS->Stall (UHC_ROOT_PORT_RESET_STALL);
80 
81     //
82     // Clear the Global Reset bit to zero.
83     //
84     UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
85 
86     gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
87     break;
88 
89   case EFI_USB_HC_RESET_HOST_CONTROLLER:
90     //
91     // Stop schedule and set Host Controller Reset bit to 1
92     //
93     UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
94     UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
95 
96     gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
97     break;
98 
99   default:
100     goto ON_INVAILD_PARAMETER;
101   }
102 
103   //
104   // Delete all old transactions on the USB bus, then
105   // reinitialize the frame list
106   //
107   UhciFreeAllAsyncReq (Uhc);
108   UhciDestoryFrameList (Uhc);
109   UhciInitFrameList (Uhc);
110 
111   gBS->RestoreTPL (OldTpl);
112 
113   return EFI_SUCCESS;
114 
115 ON_INVAILD_PARAMETER:
116 
117   gBS->RestoreTPL (OldTpl);
118 
119   return EFI_INVALID_PARAMETER;
120 }
121 
122 
123 /**
124   Retrieves current state of the USB host controller according to UEFI 2.0 spec.
125 
126   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
127   @param  State                  Variable to receive current device state.
128 
129   @return EFI_SUCCESS            The state is returned.
130   @return EFI_INVALID_PARAMETER  State is not valid.
131   @return EFI_DEVICE_ERROR       Other errors.
132 
133 **/
134 EFI_STATUS
135 EFIAPI
Uhci2GetState(IN EFI_USB2_HC_PROTOCOL * This,OUT EFI_USB_HC_STATE * State)136 Uhci2GetState (
137   IN   EFI_USB2_HC_PROTOCOL   *This,
138   OUT  EFI_USB_HC_STATE       *State
139   )
140 {
141   USB_HC_DEV          *Uhc;
142   UINT16              UsbSts;
143   UINT16              UsbCmd;
144 
145   if (State == NULL) {
146     return EFI_INVALID_PARAMETER;
147   }
148 
149   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
150 
151   UsbCmd  = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
152   UsbSts  = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
153 
154   if ((UsbCmd & USBCMD_EGSM) !=0 ) {
155     *State = EfiUsbHcStateSuspend;
156 
157   } else if ((UsbSts & USBSTS_HCH) != 0) {
158     *State = EfiUsbHcStateHalt;
159 
160   } else {
161     *State = EfiUsbHcStateOperational;
162   }
163 
164   return EFI_SUCCESS;
165 }
166 
167 
168 /**
169   Sets the USB host controller to a specific state according to UEFI 2.0 spec.
170 
171   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
172   @param  State                  Indicates the state of the host controller that will
173                                  be set.
174 
175   @return EFI_SUCCESS            Host controller was successfully placed in the state.
176   @return EFI_INVALID_PARAMETER  State is invalid.
177   @return EFI_DEVICE_ERROR       Failed to set the state.
178 
179 **/
180 EFI_STATUS
181 EFIAPI
Uhci2SetState(IN EFI_USB2_HC_PROTOCOL * This,IN EFI_USB_HC_STATE State)182 Uhci2SetState (
183   IN EFI_USB2_HC_PROTOCOL    *This,
184   IN EFI_USB_HC_STATE        State
185   )
186 {
187   EFI_USB_HC_STATE    CurState;
188   USB_HC_DEV          *Uhc;
189   EFI_TPL             OldTpl;
190   EFI_STATUS          Status;
191   UINT16              UsbCmd;
192 
193   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
194   Status  = Uhci2GetState (This, &CurState);
195 
196   if (EFI_ERROR (Status)) {
197     return EFI_DEVICE_ERROR;
198   }
199 
200   if (CurState == State) {
201     return EFI_SUCCESS;
202   }
203 
204   Status  = EFI_SUCCESS;
205   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
206 
207   switch (State) {
208   case EfiUsbHcStateHalt:
209     Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
210     break;
211 
212   case EfiUsbHcStateOperational:
213     UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
214 
215     if (CurState == EfiUsbHcStateHalt) {
216       //
217       // Set Run/Stop bit to 1, also set the bandwidht reclamation
218       // point to 64 bytes
219       //
220       UsbCmd |= USBCMD_RS | USBCMD_MAXP;
221       UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
222 
223     } else if (CurState == EfiUsbHcStateSuspend) {
224       //
225       // If FGR(Force Global Resume) bit is 0, set it
226       //
227       if ((UsbCmd & USBCMD_FGR) == 0) {
228         UsbCmd |= USBCMD_FGR;
229         UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
230       }
231 
232       //
233       // wait 20ms to let resume complete (20ms is specified by UHCI spec)
234       //
235       gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);
236 
237       //
238       // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
239       //
240       UsbCmd &= ~USBCMD_FGR;
241       UsbCmd &= ~USBCMD_EGSM;
242       UsbCmd |= USBCMD_RS;
243       UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
244     }
245 
246     break;
247 
248   case EfiUsbHcStateSuspend:
249     Status = Uhci2SetState (This, EfiUsbHcStateHalt);
250 
251     if (EFI_ERROR (Status)) {
252       Status = EFI_DEVICE_ERROR;
253       goto ON_EXIT;
254     }
255 
256     //
257     // Set Enter Global Suspend Mode bit to 1.
258     //
259     UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
260     UsbCmd |= USBCMD_EGSM;
261     UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
262     break;
263 
264   default:
265     Status = EFI_INVALID_PARAMETER;
266     break;
267   }
268 
269 ON_EXIT:
270   gBS->RestoreTPL (OldTpl);
271   return Status;
272 }
273 
274 /**
275   Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
276 
277   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
278   @param  MaxSpeed               A pointer to the max speed USB host controller
279                                  supports.
280   @param  PortNumber             A pointer to the number of root hub ports.
281   @param  Is64BitCapable         A pointer to an integer to show whether USB host
282                                  controller supports 64-bit memory addressing.
283 
284   @return EFI_SUCCESS            capabilities were retrieved successfully.
285   @return EFI_INVALID_PARAMETER  MaxSpeed or PortNumber or Is64BitCapable is NULL.
286   @return EFI_DEVICE_ERROR       An error was encountered.
287 
288 **/
289 EFI_STATUS
290 EFIAPI
Uhci2GetCapability(IN EFI_USB2_HC_PROTOCOL * This,OUT UINT8 * MaxSpeed,OUT UINT8 * PortNumber,OUT UINT8 * Is64BitCapable)291 Uhci2GetCapability (
292   IN  EFI_USB2_HC_PROTOCOL  *This,
293   OUT UINT8                 *MaxSpeed,
294   OUT UINT8                 *PortNumber,
295   OUT UINT8                 *Is64BitCapable
296   )
297 {
298   USB_HC_DEV          *Uhc;
299   UINT32              Offset;
300   UINT16              PortSC;
301   UINT32              Index;
302 
303   Uhc = UHC_FROM_USB2_HC_PROTO (This);
304 
305   if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
306     return EFI_INVALID_PARAMETER;
307   }
308 
309   *MaxSpeed       = EFI_USB_SPEED_FULL;
310   *Is64BitCapable = (UINT8) FALSE;
311 
312   *PortNumber = 0;
313 
314   for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
315     Offset  = USBPORTSC_OFFSET + Index * 2;
316     PortSC  = UhciReadReg (Uhc->PciIo, Offset);
317 
318     //
319     // Port status's bit 7 is reserved and always returns 1 if
320     // the port number is valid. Intel's UHCI (in EHCI controller)
321     // returns 0 in this bit if port number is invalid. Also, if
322     // PciIo IoRead returns error, 0xFFFF is returned to caller.
323     //
324     if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {
325       break;
326     }
327     (*PortNumber)++;
328   }
329 
330   Uhc->RootPorts = *PortNumber;
331 
332   DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));
333   return EFI_SUCCESS;
334 }
335 
336 
337 /**
338   Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
339 
340   @param  This                    A pointer to the EFI_USB2_HC_PROTOCOL.
341   @param  PortNumber              The port to get status.
342   @param  PortStatus              A pointer to the current port status bits and  port
343                                   status change bits.
344 
345   @return EFI_SUCCESS             status of the USB root hub port was returned in PortStatus.
346   @return EFI_INVALID_PARAMETER   PortNumber is invalid.
347   @return EFI_DEVICE_ERROR        Can't read register.
348 
349 **/
350 EFI_STATUS
351 EFIAPI
Uhci2GetRootHubPortStatus(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,OUT EFI_USB_PORT_STATUS * PortStatus)352 Uhci2GetRootHubPortStatus (
353   IN   EFI_USB2_HC_PROTOCOL   *This,
354   IN   UINT8                  PortNumber,
355   OUT  EFI_USB_PORT_STATUS    *PortStatus
356   )
357 {
358   USB_HC_DEV          *Uhc;
359   UINT32              Offset;
360   UINT16              PortSC;
361 
362   Uhc = UHC_FROM_USB2_HC_PROTO (This);
363 
364   if (PortStatus == NULL) {
365     return EFI_INVALID_PARAMETER;
366   }
367 
368   if (PortNumber >= Uhc->RootPorts) {
369     return EFI_INVALID_PARAMETER;
370   }
371 
372   Offset                        = USBPORTSC_OFFSET + PortNumber * 2;
373   PortStatus->PortStatus        = 0;
374   PortStatus->PortChangeStatus  = 0;
375 
376   PortSC                        = UhciReadReg (Uhc->PciIo, Offset);
377 
378   if ((PortSC & USBPORTSC_CCS) != 0) {
379     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
380   }
381 
382   if ((PortSC & USBPORTSC_PED) != 0) {
383     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
384   }
385 
386   if ((PortSC & USBPORTSC_SUSP) != 0) {
387     DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));
388     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
389   }
390 
391   if ((PortSC & USBPORTSC_PR) != 0) {
392     PortStatus->PortStatus |= USB_PORT_STAT_RESET;
393   }
394 
395   if ((PortSC & USBPORTSC_LSDA) != 0) {
396     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
397   }
398 
399   //
400   // CHC will always return one in port owner bit
401   //
402   PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
403 
404   if ((PortSC & USBPORTSC_CSC) != 0) {
405     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
406   }
407 
408   if ((PortSC & USBPORTSC_PEDC) != 0) {
409     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
410   }
411 
412   return EFI_SUCCESS;
413 }
414 
415 
416 /**
417   Sets a feature for the specified root hub port according to UEFI 2.0 spec.
418 
419   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL.
420   @param  PortNumber             Specifies the root hub port whose feature  is
421                                  requested to be set.
422   @param  PortFeature            Indicates the feature selector associated  with the
423                                  feature set request.
424 
425   @return EFI_SUCCESS            PortFeature was set for the root port.
426   @return EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
427   @return EFI_DEVICE_ERROR       Can't read register.
428 
429 **/
430 EFI_STATUS
431 EFIAPI
Uhci2SetRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)432 Uhci2SetRootHubPortFeature (
433   IN EFI_USB2_HC_PROTOCOL    *This,
434   IN UINT8                   PortNumber,
435   IN EFI_USB_PORT_FEATURE    PortFeature
436   )
437 {
438   USB_HC_DEV          *Uhc;
439   EFI_TPL             OldTpl;
440   UINT32              Offset;
441   UINT16              PortSC;
442   UINT16              Command;
443 
444   Uhc = UHC_FROM_USB2_HC_PROTO (This);
445 
446   if (PortNumber >= Uhc->RootPorts) {
447     return EFI_INVALID_PARAMETER;
448   }
449 
450   Offset  = USBPORTSC_OFFSET + PortNumber * 2;
451 
452   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
453   PortSC  = UhciReadReg (Uhc->PciIo, Offset);
454 
455   switch (PortFeature) {
456   case EfiUsbPortSuspend:
457     Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
458     if ((Command & USBCMD_EGSM) == 0) {
459       //
460       // if global suspend is not active, can set port suspend
461       //
462       PortSC &= 0xfff5;
463       PortSC |= USBPORTSC_SUSP;
464     }
465     break;
466 
467   case EfiUsbPortReset:
468     PortSC &= 0xfff5;
469     PortSC |= USBPORTSC_PR;
470     break;
471 
472   case EfiUsbPortPower:
473     //
474     // No action
475     //
476     break;
477 
478   case EfiUsbPortEnable:
479     PortSC &= 0xfff5;
480     PortSC |= USBPORTSC_PED;
481     break;
482 
483   default:
484     gBS->RestoreTPL (OldTpl);
485     return EFI_INVALID_PARAMETER;
486   }
487 
488   UhciWriteReg (Uhc->PciIo, Offset, PortSC);
489   gBS->RestoreTPL (OldTpl);
490 
491   return EFI_SUCCESS;
492 }
493 
494 
495 /**
496   Clears a feature for the specified root hub port according to Uefi 2.0 spec.
497 
498   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
499   @param  PortNumber             Specifies the root hub port whose feature  is
500                                  requested to be cleared.
501   @param  PortFeature            Indicates the feature selector associated with the
502                                  feature clear request.
503 
504   @return EFI_SUCCESS            PortFeature was cleared for the USB root hub port.
505   @return EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
506   @return EFI_DEVICE_ERROR       Can't read register.
507 
508 **/
509 EFI_STATUS
510 EFIAPI
Uhci2ClearRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)511 Uhci2ClearRootHubPortFeature (
512   IN EFI_USB2_HC_PROTOCOL    *This,
513   IN UINT8                   PortNumber,
514   IN EFI_USB_PORT_FEATURE    PortFeature
515   )
516 {
517   USB_HC_DEV          *Uhc;
518   EFI_TPL             OldTpl;
519   UINT32              Offset;
520   UINT16              PortSC;
521 
522   Uhc = UHC_FROM_USB2_HC_PROTO (This);
523 
524   if (PortNumber >= Uhc->RootPorts) {
525     return EFI_INVALID_PARAMETER;
526   }
527 
528   Offset  = USBPORTSC_OFFSET + PortNumber * 2;
529 
530   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
531   PortSC  = UhciReadReg (Uhc->PciIo, Offset);
532 
533   switch (PortFeature) {
534   case EfiUsbPortEnable:
535     PortSC &= 0xfff5;
536     PortSC &= ~USBPORTSC_PED;
537     break;
538 
539   case EfiUsbPortSuspend:
540     //
541     // Cause a resume on the specified port if in suspend mode.
542     //
543     PortSC &= 0xfff5;
544     PortSC &= ~USBPORTSC_SUSP;
545     break;
546 
547   case EfiUsbPortPower:
548     //
549     // No action
550     //
551     break;
552 
553   case EfiUsbPortReset:
554     PortSC &= 0xfff5;
555     PortSC &= ~USBPORTSC_PR;
556     break;
557 
558   case EfiUsbPortConnectChange:
559     PortSC &= 0xfff5;
560     PortSC |= USBPORTSC_CSC;
561     break;
562 
563   case EfiUsbPortEnableChange:
564     PortSC &= 0xfff5;
565     PortSC |= USBPORTSC_PEDC;
566     break;
567 
568   case EfiUsbPortSuspendChange:
569     //
570     // Root hub does not support this
571     //
572     break;
573 
574   case EfiUsbPortOverCurrentChange:
575     //
576     // Root hub does not support this
577     //
578     break;
579 
580   case EfiUsbPortResetChange:
581     //
582     // Root hub does not support this
583     //
584     break;
585 
586   default:
587     gBS->RestoreTPL (OldTpl);
588     return EFI_INVALID_PARAMETER;
589   }
590 
591   UhciWriteReg (Uhc->PciIo, Offset, PortSC);
592   gBS->RestoreTPL (OldTpl);
593 
594   return EFI_SUCCESS;
595 }
596 
597 
598 /**
599   Submits control transfer to a target USB device according to UEFI 2.0 spec.
600 
601   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
602   @param  DeviceAddress          Target device address.
603   @param  DeviceSpeed            Device speed.
604   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
605   @param  Request                USB device request to send.
606   @param  TransferDirection      Data direction of the Data stage in control transfer.
607   @param  Data                   Data to transmit/receive in data stage.
608   @param  DataLength             Length of the data.
609   @param  TimeOut                Maximum time, in microseconds, for transfer to complete.
610   @param  Translator             Transaction translator to be used by this device.
611   @param  TransferResult         Variable to receive the transfer result.
612 
613   @return EFI_SUCCESS            The control transfer was completed successfully.
614   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
615   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
616   @return EFI_TIMEOUT            Failed due to timeout.
617   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
618 
619 **/
620 EFI_STATUS
621 EFIAPI
Uhci2ControlTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN EFI_USB_DEVICE_REQUEST * Request,IN EFI_USB_DATA_DIRECTION TransferDirection,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN UINTN TimeOut,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)622 Uhci2ControlTransfer (
623   IN     EFI_USB2_HC_PROTOCOL                 *This,
624   IN     UINT8                                DeviceAddress,
625   IN     UINT8                                DeviceSpeed,
626   IN     UINTN                                MaximumPacketLength,
627   IN     EFI_USB_DEVICE_REQUEST               *Request,
628   IN     EFI_USB_DATA_DIRECTION               TransferDirection,
629   IN OUT VOID                                 *Data,
630   IN OUT UINTN                                *DataLength,
631   IN     UINTN                                TimeOut,
632   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,
633   OUT    UINT32                               *TransferResult
634   )
635 {
636   USB_HC_DEV              *Uhc;
637   UHCI_TD_SW              *TDs;
638   EFI_TPL                 OldTpl;
639   EFI_STATUS              Status;
640   UHCI_QH_RESULT          QhResult;
641   UINT8                   PktId;
642   UINT8                   *RequestPhy;
643   VOID                    *RequestMap;
644   UINT8                   *DataPhy;
645   VOID                    *DataMap;
646   BOOLEAN                 IsSlowDevice;
647   UINTN                   TransferDataLength;
648 
649   Uhc         = UHC_FROM_USB2_HC_PROTO (This);
650   TDs         = NULL;
651   DataPhy     = NULL;
652   DataMap     = NULL;
653   RequestPhy  = NULL;
654   RequestMap  = NULL;
655 
656   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
657 
658   //
659   // Parameters Checking
660   //
661   if (Request == NULL || TransferResult == NULL) {
662     return EFI_INVALID_PARAMETER;
663   }
664 
665   if (IsSlowDevice && (MaximumPacketLength != 8)) {
666     return EFI_INVALID_PARAMETER;
667   }
668 
669   if ((MaximumPacketLength != 8) &&  (MaximumPacketLength != 16) &&
670       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
671 
672     return EFI_INVALID_PARAMETER;
673   }
674 
675   if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {
676     return EFI_INVALID_PARAMETER;
677   }
678 
679   if (TransferDirection == EfiUsbNoData) {
680     TransferDataLength = 0;
681   } else {
682     TransferDataLength = *DataLength;
683   }
684 
685   *TransferResult = EFI_USB_ERR_SYSTEM;
686   Status          = EFI_DEVICE_ERROR;
687 
688   //
689   // If errors exist that cause host controller halt,
690   // clear status then return EFI_DEVICE_ERROR.
691   //
692   UhciAckAllInterrupt (Uhc);
693 
694   if (!UhciIsHcWorking (Uhc->PciIo)) {
695     return EFI_DEVICE_ERROR;
696   }
697 
698   OldTpl = gBS->RaiseTPL (UHCI_TPL);
699 
700   //
701   // Map the Request and data for bus master access,
702   // then create a list of TD for this transfer
703   //
704   Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
705 
706   if (EFI_ERROR (Status)) {
707     goto ON_EXIT;
708   }
709 
710   Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
711 
712   if (EFI_ERROR (Status)) {
713     Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
714     goto ON_EXIT;
715   }
716 
717   TDs = UhciCreateCtrlTds (
718           Uhc,
719           DeviceAddress,
720           PktId,
721           (UINT8*)Request,
722           RequestPhy,
723           (UINT8*)Data,
724           DataPhy,
725           TransferDataLength,
726           (UINT8) MaximumPacketLength,
727           IsSlowDevice
728           );
729 
730   if (TDs == NULL) {
731     Status = EFI_OUT_OF_RESOURCES;
732     goto UNMAP_DATA;
733   }
734 
735   //
736   // According to the speed of the end point, link
737   // the TD to corrosponding queue head, then check
738   // the execution result
739   //
740   UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);
741   Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
742   UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
743 
744   Uhc->PciIo->Flush (Uhc->PciIo);
745 
746   *TransferResult = QhResult.Result;
747 
748   if (DataLength != NULL) {
749     *DataLength = QhResult.Complete;
750   }
751 
752   UhciDestoryTds (Uhc, TDs);
753 
754 UNMAP_DATA:
755   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
756   Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
757 
758 ON_EXIT:
759   gBS->RestoreTPL (OldTpl);
760   return Status;
761 }
762 
763 
764 /**
765   Submits bulk transfer to a bulk endpoint of a USB device.
766 
767   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
768   @param  DeviceAddress          Target device address.
769   @param  EndPointAddress        Endpoint number and direction.
770   @param  DeviceSpeed            Device speed.
771   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
772   @param  DataBuffersNumber      Number of data buffers prepared for the transfer.
773   @param  Data                   Array of pointers to the buffers of data.
774   @param  DataLength             On input, size of the data buffer, On output,
775                                  actually transferred data size.
776   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
777   @param  TimeOut                Maximum time out, in microseconds.
778   @param  Translator             A pointr to the transaction translator data.
779   @param  TransferResult         Variable to receive transfer result.
780 
781   @return EFI_SUCCESS            The bulk transfer was completed successfully.
782   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
783   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
784   @return EFI_TIMEOUT            Failed due to timeout.
785   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
786 
787 **/
788 EFI_STATUS
789 EFIAPI
Uhci2BulkTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_BULK_BUFFER_NUM],IN OUT UINTN * DataLength,IN OUT UINT8 * DataToggle,IN UINTN TimeOut,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)790 Uhci2BulkTransfer (
791   IN     EFI_USB2_HC_PROTOCOL               *This,
792   IN     UINT8                              DeviceAddress,
793   IN     UINT8                              EndPointAddress,
794   IN     UINT8                              DeviceSpeed,
795   IN     UINTN                              MaximumPacketLength,
796   IN     UINT8                              DataBuffersNumber,
797   IN OUT VOID                               *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
798   IN OUT UINTN                              *DataLength,
799   IN OUT UINT8                              *DataToggle,
800   IN     UINTN                              TimeOut,
801   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
802   OUT    UINT32                             *TransferResult
803   )
804 {
805   EFI_USB_DATA_DIRECTION  Direction;
806   EFI_TPL                 OldTpl;
807   USB_HC_DEV              *Uhc;
808   UHCI_TD_SW              *TDs;
809   UHCI_QH_SW              *BulkQh;
810   UHCI_QH_RESULT          QhResult;
811   EFI_STATUS              Status;
812   UINT8                   PktId;
813   UINT8                   *DataPhy;
814   VOID                    *DataMap;
815 
816   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
817   DataPhy = NULL;
818   DataMap = NULL;
819 
820   if (DeviceSpeed == EFI_USB_SPEED_LOW) {
821     return EFI_INVALID_PARAMETER;
822   }
823 
824   if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
825     return EFI_INVALID_PARAMETER;
826   }
827 
828   if ((*DataToggle != 1) && (*DataToggle != 0)) {
829     return EFI_INVALID_PARAMETER;
830   }
831 
832   if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
833       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
834     return EFI_INVALID_PARAMETER;
835   }
836 
837   *TransferResult = EFI_USB_ERR_SYSTEM;
838   Status          = EFI_OUT_OF_RESOURCES;
839 
840   //
841   // If has errors that cause host controller halt,
842   // then return EFI_DEVICE_ERROR directly.
843   //
844   UhciAckAllInterrupt (Uhc);
845 
846   if (!UhciIsHcWorking (Uhc->PciIo)) {
847     return EFI_DEVICE_ERROR;
848   }
849 
850   OldTpl = gBS->RaiseTPL (UHCI_TPL);
851 
852   //
853   // Map the source data buffer for bus master access,
854   // then create a list of TDs
855   //
856   if ((EndPointAddress & 0x80) != 0) {
857     Direction = EfiUsbDataIn;
858   } else {
859     Direction = EfiUsbDataOut;
860   }
861 
862   Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);
863 
864   if (EFI_ERROR (Status)) {
865     goto ON_EXIT;
866   }
867 
868   Status = EFI_OUT_OF_RESOURCES;
869   TDs    = UhciCreateBulkOrIntTds (
870              Uhc,
871              DeviceAddress,
872              EndPointAddress,
873              PktId,
874              (UINT8 *)*Data,
875              DataPhy,
876              *DataLength,
877              DataToggle,
878              (UINT8) MaximumPacketLength,
879              FALSE
880              );
881 
882   if (TDs == NULL) {
883     Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
884     goto ON_EXIT;
885   }
886 
887 
888   //
889   // Link the TDs to bulk queue head. According to the platfore
890   // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
891   // to do full speed bandwidth reclamation or not.
892   //
893   BulkQh = Uhc->BulkQh;
894 
895   UhciLinkTdToQh (Uhc, BulkQh, TDs);
896   Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
897   UhciUnlinkTdFromQh (BulkQh, TDs);
898 
899   Uhc->PciIo->Flush (Uhc->PciIo);
900 
901   *TransferResult = QhResult.Result;
902   *DataToggle     = QhResult.NextToggle;
903   *DataLength     = QhResult.Complete;
904 
905   UhciDestoryTds (Uhc, TDs);
906   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
907 
908 ON_EXIT:
909   gBS->RestoreTPL (OldTpl);
910   return Status;
911 }
912 
913 
914 /**
915   Submits an asynchronous interrupt transfer to an
916   interrupt endpoint of a USB device according to UEFI 2.0 spec.
917 
918   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
919   @param  DeviceAddress          Target device address.
920   @param  EndPointAddress        Endpoint number and direction.
921   @param  DeviceSpeed            Device speed.
922   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
923   @param  IsNewTransfer          If TRUE, submit a new transfer, if FALSE cancel old transfer.
924   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
925   @param  PollingInterval        Interrupt poll rate in milliseconds.
926   @param  DataLength             On input, size of the data buffer, On output,
927                                  actually transferred data size.
928   @param  Translator             A pointr to the transaction translator data.
929   @param  CallBackFunction       Function to call periodically.
930   @param  Context                User context.
931 
932   @return EFI_SUCCESS            Transfer was submitted.
933   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
934   @return EFI_OUT_OF_RESOURCES   Failed due to a lack of resources.
935   @return EFI_DEVICE_ERROR       Can't read register.
936 
937 **/
938 EFI_STATUS
939 EFIAPI
Uhci2AsyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN BOOLEAN IsNewTransfer,IN OUT UINT8 * DataToggle,IN UINTN PollingInterval,IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,IN VOID * Context)940 Uhci2AsyncInterruptTransfer (
941   IN     EFI_USB2_HC_PROTOCOL               *This,
942   IN     UINT8                              DeviceAddress,
943   IN     UINT8                              EndPointAddress,
944   IN     UINT8                              DeviceSpeed,
945   IN     UINTN                              MaximumPacketLength,
946   IN     BOOLEAN                            IsNewTransfer,
947   IN OUT UINT8                              *DataToggle,
948   IN     UINTN                              PollingInterval,
949   IN     UINTN                              DataLength,
950   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
951   IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    CallBackFunction,
952   IN     VOID                               *Context
953   )
954 {
955   USB_HC_DEV          *Uhc;
956   BOOLEAN             IsSlowDevice;
957   UHCI_QH_SW          *Qh;
958   UHCI_TD_SW          *IntTds;
959   EFI_TPL             OldTpl;
960   EFI_STATUS          Status;
961   UINT8               *DataPtr;
962   UINT8               *DataPhy;
963   UINT8               PktId;
964 
965   Uhc       = UHC_FROM_USB2_HC_PROTO (This);
966   Qh        = NULL;
967   IntTds    = NULL;
968   DataPtr   = NULL;
969   DataPhy   = NULL;
970 
971   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
972 
973   if ((EndPointAddress & 0x80) == 0) {
974     return EFI_INVALID_PARAMETER;
975   }
976 
977   //
978   // Delete Async interrupt transfer request
979   //
980   if (!IsNewTransfer) {
981     OldTpl = gBS->RaiseTPL (UHCI_TPL);
982     Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
983 
984     gBS->RestoreTPL (OldTpl);
985     return Status;
986   }
987 
988   if (PollingInterval < 1 || PollingInterval > 255) {
989     return EFI_INVALID_PARAMETER;
990   }
991 
992   if (DataLength == 0) {
993     return EFI_INVALID_PARAMETER;
994   }
995 
996   if ((*DataToggle != 1) && (*DataToggle != 0)) {
997     return EFI_INVALID_PARAMETER;
998   }
999 
1000   //
1001   // If has errors that cause host controller halt,
1002   // then return EFI_DEVICE_ERROR directly.
1003   //
1004   UhciAckAllInterrupt (Uhc);
1005 
1006   if (!UhciIsHcWorking (Uhc->PciIo)) {
1007     return EFI_DEVICE_ERROR;
1008   }
1009 
1010   if ((EndPointAddress & 0x80) == 0) {
1011     PktId = OUTPUT_PACKET_ID;
1012   } else {
1013     PktId = INPUT_PACKET_ID;
1014   }
1015 
1016   //
1017   // Allocate and map source data buffer for bus master access.
1018   //
1019   DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);
1020 
1021   if (DataPtr == NULL) {
1022     return EFI_OUT_OF_RESOURCES;
1023   }
1024 
1025   DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Uhc->MemPool, DataPtr, DataLength);
1026 
1027   OldTpl = gBS->RaiseTPL (UHCI_TPL);
1028 
1029   Qh = UhciCreateQh (Uhc, PollingInterval);
1030 
1031   if (Qh == NULL) {
1032     Status = EFI_OUT_OF_RESOURCES;
1033     goto FREE_DATA;
1034   }
1035 
1036   IntTds = UhciCreateBulkOrIntTds (
1037              Uhc,
1038              DeviceAddress,
1039              EndPointAddress,
1040              PktId,
1041              DataPtr,
1042              DataPhy,
1043              DataLength,
1044              DataToggle,
1045              (UINT8) MaximumPacketLength,
1046              IsSlowDevice
1047              );
1048 
1049   if (IntTds == NULL) {
1050     Status = EFI_OUT_OF_RESOURCES;
1051     goto DESTORY_QH;
1052   }
1053 
1054   UhciLinkTdToQh (Uhc, Qh, IntTds);
1055 
1056   //
1057   // Save QH-TD structures to async Interrupt transfer list,
1058   // for monitor interrupt transfer execution routine use.
1059   //
1060   Status = UhciCreateAsyncReq (
1061              Uhc,
1062              Qh,
1063              IntTds,
1064              DeviceAddress,
1065              EndPointAddress,
1066              DataLength,
1067              PollingInterval,
1068              DataPtr,
1069              CallBackFunction,
1070              Context,
1071              IsSlowDevice
1072              );
1073 
1074   if (EFI_ERROR (Status)) {
1075     goto DESTORY_QH;
1076   }
1077 
1078   UhciLinkQhToFrameList (Uhc, Qh);
1079 
1080   gBS->RestoreTPL (OldTpl);
1081   return EFI_SUCCESS;
1082 
1083 DESTORY_QH:
1084   UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
1085 
1086 FREE_DATA:
1087   UsbHcFreeMem (Uhc->MemPool, DataPtr, DataLength);
1088   Uhc->PciIo->Flush (Uhc->PciIo);
1089 
1090   gBS->RestoreTPL (OldTpl);
1091   return Status;
1092 }
1093 
1094 /**
1095   Submits synchronous interrupt transfer to an interrupt endpoint
1096   of a USB device according to UEFI 2.0 spec.
1097 
1098 
1099   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
1100   @param  DeviceAddress          Target device address.
1101   @param  EndPointAddress        Endpoint number and direction.
1102   @param  DeviceSpeed            Device speed.
1103   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
1104   @param  Data                   Array of pointers to the buffers of data.
1105   @param  DataLength             On input, size of the data buffer, On output,
1106                                  actually transferred data size.
1107   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
1108   @param  TimeOut                Maximum time out, in microseconds.
1109   @param  Translator             A pointr to the transaction translator data.
1110   @param  TransferResult         Variable to receive transfer result.
1111 
1112   @return EFI_SUCCESS            The transfer was completed successfully.
1113   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
1114   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
1115   @return EFI_TIMEOUT            Failed due to timeout.
1116   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
1117 
1118 **/
1119 EFI_STATUS
1120 EFIAPI
Uhci2SyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN OUT UINT8 * DataToggle,IN UINTN TimeOut,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1121 Uhci2SyncInterruptTransfer (
1122   IN     EFI_USB2_HC_PROTOCOL                      *This,
1123   IN     UINT8                                     DeviceAddress,
1124   IN     UINT8                                     EndPointAddress,
1125   IN     UINT8                                     DeviceSpeed,
1126   IN     UINTN                                     MaximumPacketLength,
1127   IN OUT VOID                                      *Data,
1128   IN OUT UINTN                                     *DataLength,
1129   IN OUT UINT8                                     *DataToggle,
1130   IN     UINTN                                     TimeOut,
1131   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR        *Translator,
1132   OUT    UINT32                                    *TransferResult
1133   )
1134 {
1135   EFI_STATUS          Status;
1136   USB_HC_DEV          *Uhc;
1137   UHCI_TD_SW          *TDs;
1138   UHCI_QH_RESULT      QhResult;
1139   EFI_TPL             OldTpl;
1140   UINT8               *DataPhy;
1141   VOID                *DataMap;
1142   UINT8               PktId;
1143   BOOLEAN             IsSlowDevice;
1144 
1145   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
1146   DataPhy = NULL;
1147   DataMap = NULL;
1148   TDs     = NULL;
1149 
1150   if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1151     return EFI_INVALID_PARAMETER;
1152   }
1153 
1154   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1155 
1156   if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
1157     return EFI_INVALID_PARAMETER;
1158   }
1159 
1160   if ((*DataToggle != 1) && (*DataToggle != 0)) {
1161     return EFI_INVALID_PARAMETER;
1162   }
1163 
1164   if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
1165     return EFI_INVALID_PARAMETER;
1166   }
1167 
1168   if (IsSlowDevice && (MaximumPacketLength > 8)) {
1169     return EFI_INVALID_PARAMETER;
1170   }
1171 
1172   *TransferResult = EFI_USB_ERR_SYSTEM;
1173   Status          = EFI_DEVICE_ERROR;
1174 
1175 
1176   UhciAckAllInterrupt (Uhc);
1177 
1178   if (!UhciIsHcWorking (Uhc->PciIo)) {
1179     return Status;
1180   }
1181 
1182   OldTpl = gBS->RaiseTPL (UHCI_TPL);
1183 
1184   //
1185   // Map the source data buffer for bus master access.
1186   // Create Tds list, then link it to the UHC's interrupt list
1187   //
1188   Status = UhciMapUserData (
1189              Uhc,
1190              EfiUsbDataIn,
1191              Data,
1192              DataLength,
1193              &PktId,
1194              &DataPhy,
1195              &DataMap
1196              );
1197 
1198   if (EFI_ERROR (Status)) {
1199     goto ON_EXIT;
1200   }
1201 
1202   TDs = UhciCreateBulkOrIntTds (
1203           Uhc,
1204           DeviceAddress,
1205           EndPointAddress,
1206           PktId,
1207           (UINT8 *)Data,
1208           DataPhy,
1209           *DataLength,
1210           DataToggle,
1211           (UINT8) MaximumPacketLength,
1212           IsSlowDevice
1213           );
1214 
1215   if (TDs == NULL) {
1216     Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1217 
1218     Status = EFI_OUT_OF_RESOURCES;
1219     goto ON_EXIT;
1220   }
1221 
1222 
1223   UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
1224 
1225   Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
1226 
1227   UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
1228   Uhc->PciIo->Flush (Uhc->PciIo);
1229 
1230   *TransferResult = QhResult.Result;
1231   *DataToggle     = QhResult.NextToggle;
1232   *DataLength     = QhResult.Complete;
1233 
1234   UhciDestoryTds (Uhc, TDs);
1235   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1236 
1237 ON_EXIT:
1238   gBS->RestoreTPL (OldTpl);
1239   return Status;
1240 }
1241 
1242 
1243 /**
1244   Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
1245 
1246   @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
1247   @param  DeviceAddress         Target device address.
1248   @param  EndPointAddress       Endpoint number and direction.
1249   @param  DeviceSpeed           Device speed.
1250   @param  MaximumPacketLength   Maximum packet size of the target endpoint.
1251   @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
1252   @param  Data                  Array of pointers to the buffers of data.
1253   @param  DataLength            On input, size of the data buffer, On output,
1254                                 actually transferred data size.
1255   @param  Translator            A pointr to the transaction translator data.
1256   @param  TransferResult        Variable to receive transfer result.
1257 
1258   @return EFI_UNSUPPORTED
1259 
1260 **/
1261 EFI_STATUS
1262 EFIAPI
Uhci2IsochronousTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_ISO_BUFFER_NUM],IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1263 Uhci2IsochronousTransfer (
1264   IN     EFI_USB2_HC_PROTOCOL               *This,
1265   IN     UINT8                              DeviceAddress,
1266   IN     UINT8                              EndPointAddress,
1267   IN     UINT8                              DeviceSpeed,
1268   IN     UINTN                              MaximumPacketLength,
1269   IN     UINT8                              DataBuffersNumber,
1270   IN OUT VOID                               *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1271   IN     UINTN                              DataLength,
1272   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1273   OUT    UINT32                             *TransferResult
1274   )
1275 {
1276   return EFI_UNSUPPORTED;
1277 }
1278 
1279 
1280 /**
1281   Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
1282 
1283   @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
1284   @param  DeviceAddress         Target device address.
1285   @param  EndPointAddress       Endpoint number and direction.
1286   @param  DeviceSpeed           Device speed.
1287   @param  MaximumPacketLength   Maximum packet size of the target endpoint.
1288   @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
1289   @param  Data                  Array of pointers to the buffers of data.
1290   @param  DataLength            On input, size of the data buffer, On output,
1291                                 actually transferred data size.
1292   @param  Translator            A pointr to the transaction translator data.
1293   @param  IsochronousCallBack   Function to call when the transfer complete.
1294   @param  Context               Pass to the call back function as parameter.
1295 
1296   @return EFI_UNSUPPORTED
1297 
1298 **/
1299 EFI_STATUS
1300 EFIAPI
Uhci2AsyncIsochronousTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_ISO_BUFFER_NUM],IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,IN VOID * Context)1301 Uhci2AsyncIsochronousTransfer (
1302   IN     EFI_USB2_HC_PROTOCOL                *This,
1303   IN     UINT8                               DeviceAddress,
1304   IN     UINT8                               EndPointAddress,
1305   IN     UINT8                               DeviceSpeed,
1306   IN     UINTN                               MaximumPacketLength,
1307   IN     UINT8                               DataBuffersNumber,
1308   IN OUT VOID                                *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1309   IN     UINTN                               DataLength,
1310   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1311   IN     EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
1312   IN     VOID                                *Context
1313   )
1314 {
1315   return EFI_UNSUPPORTED;
1316 }
1317 
1318 /**
1319   Entry point for EFI drivers.
1320 
1321   @param  ImageHandle      EFI_HANDLE.
1322   @param  SystemTable      EFI_SYSTEM_TABLE.
1323 
1324   @retval EFI_SUCCESS      Driver is successfully loaded.
1325   @return Others           Failed.
1326 
1327 **/
1328 EFI_STATUS
1329 EFIAPI
UhciDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1330 UhciDriverEntryPoint (
1331   IN EFI_HANDLE           ImageHandle,
1332   IN EFI_SYSTEM_TABLE     *SystemTable
1333   )
1334 {
1335   return EfiLibInstallDriverBindingComponentName2 (
1336            ImageHandle,
1337            SystemTable,
1338            &gUhciDriverBinding,
1339            ImageHandle,
1340            &gUhciComponentName,
1341            &gUhciComponentName2
1342            );
1343 }
1344 
1345 
1346 /**
1347   Test to see if this driver supports ControllerHandle. Any
1348   ControllerHandle that has UsbHcProtocol installed will be supported.
1349 
1350   @param  This                 Protocol instance pointer.
1351   @param  Controller           Handle of device to test.
1352   @param  RemainingDevicePath  Not used.
1353 
1354   @return EFI_SUCCESS          This driver supports this device.
1355   @return EFI_UNSUPPORTED      This driver does not support this device.
1356 
1357 **/
1358 EFI_STATUS
1359 EFIAPI
UhciDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1360 UhciDriverBindingSupported (
1361   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
1362   IN EFI_HANDLE                      Controller,
1363   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
1364   )
1365 {
1366   EFI_STATUS            OpenStatus;
1367   EFI_STATUS            Status;
1368   EFI_PCI_IO_PROTOCOL   *PciIo;
1369   USB_CLASSC            UsbClassCReg;
1370 
1371   //
1372   // Test whether there is PCI IO Protocol attached on the controller handle.
1373   //
1374   OpenStatus = gBS->OpenProtocol (
1375                       Controller,
1376                       &gEfiPciIoProtocolGuid,
1377                       (VOID **) &PciIo,
1378                       This->DriverBindingHandle,
1379                       Controller,
1380                       EFI_OPEN_PROTOCOL_BY_DRIVER
1381                       );
1382 
1383   if (EFI_ERROR (OpenStatus)) {
1384     return OpenStatus;
1385   }
1386 
1387   Status = PciIo->Pci.Read (
1388                         PciIo,
1389                         EfiPciIoWidthUint8,
1390                         PCI_CLASSCODE_OFFSET,
1391                         sizeof (USB_CLASSC) / sizeof (UINT8),
1392                         &UsbClassCReg
1393                         );
1394 
1395   if (EFI_ERROR (Status)) {
1396     Status = EFI_UNSUPPORTED;
1397     goto ON_EXIT;
1398   }
1399 
1400   //
1401   // Test whether the controller belongs to UHCI type
1402   //
1403   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1404       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1405       (UsbClassCReg.ProgInterface != PCI_IF_UHCI)
1406       ) {
1407 
1408     Status = EFI_UNSUPPORTED;
1409   }
1410 
1411 ON_EXIT:
1412   gBS->CloseProtocol (
1413          Controller,
1414          &gEfiPciIoProtocolGuid,
1415          This->DriverBindingHandle,
1416          Controller
1417          );
1418 
1419   return Status;
1420 
1421 }
1422 
1423 
1424 /**
1425   Allocate and initialize the empty UHCI device.
1426 
1427   @param  PciIo                  The PCIIO to use.
1428   @param  DevicePath             The device path of host controller.
1429   @param  OriginalPciAttributes  The original PCI attributes.
1430 
1431   @return Allocated UHCI device. If err, return NULL.
1432 
1433 **/
1434 USB_HC_DEV *
UhciAllocateDev(IN EFI_PCI_IO_PROTOCOL * PciIo,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINT64 OriginalPciAttributes)1435 UhciAllocateDev (
1436   IN EFI_PCI_IO_PROTOCOL       *PciIo,
1437   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
1438   IN UINT64                    OriginalPciAttributes
1439   )
1440 {
1441   USB_HC_DEV  *Uhc;
1442   EFI_STATUS  Status;
1443 
1444   Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1445 
1446   if (Uhc == NULL) {
1447     return NULL;
1448   }
1449 
1450   //
1451   // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1452   // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1453   //
1454   Uhc->Signature                        = USB_HC_DEV_SIGNATURE;
1455   Uhc->Usb2Hc.GetCapability             = Uhci2GetCapability;
1456   Uhc->Usb2Hc.Reset                     = Uhci2Reset;
1457   Uhc->Usb2Hc.GetState                  = Uhci2GetState;
1458   Uhc->Usb2Hc.SetState                  = Uhci2SetState;
1459   Uhc->Usb2Hc.ControlTransfer           = Uhci2ControlTransfer;
1460   Uhc->Usb2Hc.BulkTransfer              = Uhci2BulkTransfer;
1461   Uhc->Usb2Hc.AsyncInterruptTransfer    = Uhci2AsyncInterruptTransfer;
1462   Uhc->Usb2Hc.SyncInterruptTransfer     = Uhci2SyncInterruptTransfer;
1463   Uhc->Usb2Hc.IsochronousTransfer       = Uhci2IsochronousTransfer;
1464   Uhc->Usb2Hc.AsyncIsochronousTransfer  = Uhci2AsyncIsochronousTransfer;
1465   Uhc->Usb2Hc.GetRootHubPortStatus      = Uhci2GetRootHubPortStatus;
1466   Uhc->Usb2Hc.SetRootHubPortFeature     = Uhci2SetRootHubPortFeature;
1467   Uhc->Usb2Hc.ClearRootHubPortFeature   = Uhci2ClearRootHubPortFeature;
1468   Uhc->Usb2Hc.MajorRevision             = 0x1;
1469   Uhc->Usb2Hc.MinorRevision             = 0x1;
1470 
1471   Uhc->PciIo                 = PciIo;
1472   Uhc->DevicePath            = DevicePath;
1473   Uhc->OriginalPciAttributes = OriginalPciAttributes;
1474   Uhc->MemPool               = UsbHcInitMemPool (PciIo, TRUE, 0);
1475 
1476   if (Uhc->MemPool == NULL) {
1477     Status = EFI_OUT_OF_RESOURCES;
1478     goto ON_ERROR;
1479   }
1480 
1481   InitializeListHead (&Uhc->AsyncIntList);
1482 
1483   Status = gBS->CreateEvent (
1484                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
1485                   TPL_NOTIFY,
1486                   UhciMonitorAsyncReqList,
1487                   Uhc,
1488                   &Uhc->AsyncIntMonitor
1489                   );
1490 
1491   if (EFI_ERROR (Status)) {
1492     UsbHcFreeMemPool (Uhc->MemPool);
1493     goto ON_ERROR;
1494   }
1495 
1496   return Uhc;
1497 
1498 ON_ERROR:
1499   FreePool (Uhc);
1500   return NULL;
1501 }
1502 
1503 
1504 /**
1505   Free the UHCI device and release its associated resources.
1506 
1507   @param  Uhc     The UHCI device to release.
1508 
1509 **/
1510 VOID
UhciFreeDev(IN USB_HC_DEV * Uhc)1511 UhciFreeDev (
1512   IN USB_HC_DEV           *Uhc
1513   )
1514 {
1515   if (Uhc->AsyncIntMonitor != NULL) {
1516     gBS->CloseEvent (Uhc->AsyncIntMonitor);
1517   }
1518 
1519   if (Uhc->ExitBootServiceEvent != NULL) {
1520     gBS->CloseEvent (Uhc->ExitBootServiceEvent);
1521   }
1522 
1523   if (Uhc->MemPool != NULL) {
1524     UsbHcFreeMemPool (Uhc->MemPool);
1525   }
1526 
1527   if (Uhc->CtrlNameTable != NULL) {
1528     FreeUnicodeStringTable (Uhc->CtrlNameTable);
1529   }
1530 
1531   FreePool (Uhc);
1532 }
1533 
1534 
1535 /**
1536   Uninstall all Uhci Interface.
1537 
1538   @param  Controller           Controller handle.
1539   @param  This                 Protocol instance pointer.
1540 
1541 **/
1542 VOID
UhciCleanDevUp(IN EFI_HANDLE Controller,IN EFI_USB2_HC_PROTOCOL * This)1543 UhciCleanDevUp (
1544   IN  EFI_HANDLE           Controller,
1545   IN  EFI_USB2_HC_PROTOCOL *This
1546   )
1547 {
1548   USB_HC_DEV          *Uhc;
1549   EFI_STATUS          Status;
1550 
1551   //
1552   // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
1553   //
1554   Uhc = UHC_FROM_USB2_HC_PROTO (This);
1555 
1556 
1557   Status = gBS->UninstallProtocolInterface (
1558                   Controller,
1559                   &gEfiUsb2HcProtocolGuid,
1560                   &Uhc->Usb2Hc
1561                   );
1562   if (EFI_ERROR (Status)) {
1563     return ;
1564   }
1565 
1566   UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1567   UhciFreeAllAsyncReq (Uhc);
1568   UhciDestoryFrameList (Uhc);
1569 
1570   //
1571   // Restore original PCI attributes
1572   //
1573   Uhc->PciIo->Attributes (
1574                   Uhc->PciIo,
1575                   EfiPciIoAttributeOperationSet,
1576                   Uhc->OriginalPciAttributes,
1577                   NULL
1578                   );
1579 
1580   UhciFreeDev (Uhc);
1581 }
1582 
1583 /**
1584   One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1585 
1586   @param  Event                   Pointer to this event
1587   @param  Context                 Event handler private data
1588 
1589 **/
1590 VOID
1591 EFIAPI
UhcExitBootService(EFI_EVENT Event,VOID * Context)1592 UhcExitBootService (
1593   EFI_EVENT                      Event,
1594   VOID                           *Context
1595   )
1596 {
1597   USB_HC_DEV   *Uhc;
1598 
1599   Uhc = (USB_HC_DEV *) Context;
1600 
1601   //
1602   // Stop the Host Controller
1603   //
1604   UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1605 
1606   //
1607   // Reset the Host Controller
1608   //
1609   UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
1610   gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
1611 }
1612 
1613 /**
1614   Starting the Usb UHCI Driver.
1615 
1616   @param  This                 Protocol instance pointer.
1617   @param  Controller           Handle of device to test.
1618   @param  RemainingDevicePath  Not used.
1619 
1620   @retval EFI_SUCCESS          This driver supports this device.
1621   @retval EFI_UNSUPPORTED      This driver does not support this device.
1622   @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
1623                                EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
1624 
1625 **/
1626 EFI_STATUS
1627 EFIAPI
UhciDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1628 UhciDriverBindingStart (
1629   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
1630   IN EFI_HANDLE                      Controller,
1631   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
1632   )
1633 {
1634   EFI_STATUS          Status;
1635   EFI_PCI_IO_PROTOCOL *PciIo;
1636   USB_HC_DEV          *Uhc;
1637   UINT64              Supports;
1638   UINT64              OriginalPciAttributes;
1639   BOOLEAN             PciAttributesSaved;
1640   EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath;
1641 
1642   //
1643   // Open PCIIO, then enable the EHC device and turn off emulation
1644   //
1645   Uhc = NULL;
1646   Status = gBS->OpenProtocol (
1647                   Controller,
1648                   &gEfiPciIoProtocolGuid,
1649                   (VOID **) &PciIo,
1650                   This->DriverBindingHandle,
1651                   Controller,
1652                   EFI_OPEN_PROTOCOL_BY_DRIVER
1653                   );
1654 
1655   if (EFI_ERROR (Status)) {
1656     return Status;
1657   }
1658 
1659   //
1660   // Open Device Path Protocol for on USB host controller
1661   //
1662   HcDevicePath = NULL;
1663   Status = gBS->OpenProtocol (
1664                   Controller,
1665                   &gEfiDevicePathProtocolGuid,
1666                   (VOID **) &HcDevicePath,
1667                   This->DriverBindingHandle,
1668                   Controller,
1669                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1670                   );
1671 
1672   PciAttributesSaved = FALSE;
1673   //
1674   // Save original PCI attributes
1675   //
1676   Status = PciIo->Attributes (
1677                     PciIo,
1678                     EfiPciIoAttributeOperationGet,
1679                     0,
1680                     &OriginalPciAttributes
1681                     );
1682 
1683   if (EFI_ERROR (Status)) {
1684     goto CLOSE_PCIIO;
1685   }
1686   PciAttributesSaved = TRUE;
1687 
1688   //
1689   // Robustnesss improvement such as for UoL
1690   // Default is not required.
1691   //
1692   if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1693     UhciTurnOffUsbEmulation (PciIo);
1694   }
1695 
1696   Status = PciIo->Attributes (
1697                     PciIo,
1698                     EfiPciIoAttributeOperationSupported,
1699                     0,
1700                     &Supports
1701                     );
1702   if (!EFI_ERROR (Status)) {
1703     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1704     Status = PciIo->Attributes (
1705                       PciIo,
1706                       EfiPciIoAttributeOperationEnable,
1707                       Supports,
1708                       NULL
1709                       );
1710   }
1711 
1712   if (EFI_ERROR (Status)) {
1713     goto CLOSE_PCIIO;
1714   }
1715 
1716   Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);
1717 
1718   if (Uhc == NULL) {
1719     Status = EFI_OUT_OF_RESOURCES;
1720     goto CLOSE_PCIIO;
1721   }
1722 
1723   //
1724   // Allocate and Init Host Controller's Frame List Entry
1725   //
1726   Status = UhciInitFrameList (Uhc);
1727 
1728   if (EFI_ERROR (Status)) {
1729     Status = EFI_OUT_OF_RESOURCES;
1730     goto FREE_UHC;
1731   }
1732 
1733   Status = gBS->SetTimer (
1734                   Uhc->AsyncIntMonitor,
1735                   TimerPeriodic,
1736                   UHC_ASYNC_POLL_INTERVAL
1737                   );
1738 
1739   if (EFI_ERROR (Status)) {
1740     goto FREE_UHC;
1741   }
1742 
1743   //
1744   // Install USB2_HC_PROTOCOL
1745   //
1746   Status = gBS->InstallMultipleProtocolInterfaces (
1747                   &Controller,
1748                   &gEfiUsb2HcProtocolGuid,
1749                   &Uhc->Usb2Hc,
1750                   NULL
1751                   );
1752 
1753   if (EFI_ERROR (Status)) {
1754     goto FREE_UHC;
1755   }
1756 
1757   //
1758   // Create event to stop the HC when exit boot service.
1759   //
1760   Status = gBS->CreateEventEx (
1761                   EVT_NOTIFY_SIGNAL,
1762                   TPL_NOTIFY,
1763                   UhcExitBootService,
1764                   Uhc,
1765                   &gEfiEventExitBootServicesGuid,
1766                   &Uhc->ExitBootServiceEvent
1767                   );
1768   if (EFI_ERROR (Status)) {
1769     goto UNINSTALL_USBHC;
1770   }
1771 
1772   //
1773   // Install the component name protocol
1774   //
1775   Uhc->CtrlNameTable = NULL;
1776 
1777   AddUnicodeString2 (
1778     "eng",
1779     gUhciComponentName.SupportedLanguages,
1780     &Uhc->CtrlNameTable,
1781     L"Usb Universal Host Controller",
1782     TRUE
1783     );
1784   AddUnicodeString2 (
1785     "en",
1786     gUhciComponentName2.SupportedLanguages,
1787     &Uhc->CtrlNameTable,
1788     L"Usb Universal Host Controller",
1789     FALSE
1790     );
1791 
1792 
1793   //
1794   // Start the UHCI hardware, also set its reclamation point to 64 bytes
1795   //
1796   UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
1797 
1798   return EFI_SUCCESS;
1799 
1800 UNINSTALL_USBHC:
1801   gBS->UninstallMultipleProtocolInterfaces (
1802          Controller,
1803          &gEfiUsb2HcProtocolGuid,
1804          &Uhc->Usb2Hc,
1805          NULL
1806          );
1807 
1808 FREE_UHC:
1809   UhciFreeDev (Uhc);
1810 
1811 CLOSE_PCIIO:
1812   if (PciAttributesSaved) {
1813     //
1814     // Restore original PCI attributes
1815     //
1816     PciIo->Attributes (
1817                     PciIo,
1818                     EfiPciIoAttributeOperationSet,
1819                     OriginalPciAttributes,
1820                     NULL
1821                     );
1822   }
1823 
1824   gBS->CloseProtocol (
1825         Controller,
1826         &gEfiPciIoProtocolGuid,
1827         This->DriverBindingHandle,
1828         Controller
1829         );
1830 
1831   return Status;
1832 }
1833 
1834 
1835 /**
1836   Stop this driver on ControllerHandle. Support stoping any child handles
1837   created by this driver.
1838 
1839   @param  This                 Protocol instance pointer.
1840   @param  Controller           Handle of device to stop driver on.
1841   @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
1842   @param  ChildHandleBuffer    List of handles for the children we need to stop.
1843 
1844   @return EFI_SUCCESS
1845   @return others
1846 
1847 **/
1848 EFI_STATUS
1849 EFIAPI
UhciDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)1850 UhciDriverBindingStop (
1851   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
1852   IN EFI_HANDLE                      Controller,
1853   IN UINTN                           NumberOfChildren,
1854   IN EFI_HANDLE                      *ChildHandleBuffer
1855   )
1856 {
1857   EFI_USB2_HC_PROTOCOL  *Usb2Hc;
1858   EFI_STATUS            Status;
1859 
1860    Status = gBS->OpenProtocol (
1861                   Controller,
1862                   &gEfiUsb2HcProtocolGuid,
1863                   (VOID **) &Usb2Hc,
1864                   This->DriverBindingHandle,
1865                   Controller,
1866                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1867                   );
1868 
1869   //
1870   // Test whether the Controller handler passed in is a valid
1871   // Usb controller handle that should be supported, if not,
1872   // return the error status directly
1873   //
1874   if (EFI_ERROR (Status)) {
1875     return Status;
1876   }
1877 
1878   UhciCleanDevUp (Controller, Usb2Hc);
1879 
1880   gBS->CloseProtocol (
1881         Controller,
1882         &gEfiPciIoProtocolGuid,
1883         This->DriverBindingHandle,
1884         Controller
1885         );
1886 
1887   return EFI_SUCCESS;
1888 }
1889 
1890