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