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