9d181351a2fedd37a8020d74fe965ff04ea9f0bf
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 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     Ehci.c\r
15 \r
16 Abstract:\r
17 \r
18 \r
19 Revision History\r
20 \r
21 **/\r
22 \r
23 \r
24 #include "Ehci.h"\r
25 \r
26 //\r
27 // Two arrays used to translate the EHCI port state (change)\r
28 // to the UEFI protocol's port state (change).\r
29 //\r
30 USB_PORT_STATE_MAP  mUsbPortStateMap[] = {\r
31   {PORTSC_CONN,     USB_PORT_STAT_CONNECTION},\r
32   {PORTSC_ENABLED,  USB_PORT_STAT_ENABLE},\r
33   {PORTSC_SUSPEND,  USB_PORT_STAT_SUSPEND},\r
34   {PORTSC_OVERCUR,  USB_PORT_STAT_OVERCURRENT},\r
35   {PORTSC_RESET,    USB_PORT_STAT_RESET},\r
36   {PORTSC_POWER,    USB_PORT_STAT_POWER},\r
37   {PORTSC_OWNER,    USB_PORT_STAT_OWNER}\r
38 };\r
39 \r
40 USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {\r
41   {PORTSC_CONN_CHANGE,    USB_PORT_STAT_C_CONNECTION},\r
42   {PORTSC_ENABLE_CHANGE,  USB_PORT_STAT_C_ENABLE},\r
43   {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
44 };\r
45 \r
46 \r
47 /**\r
48   Retrieves the capablility of root hub ports.\r
49 \r
50   @param  This                 This EFI_USB_HC_PROTOCOL instance.\r
51   @param  MaxSpeed             Max speed supported by the controller\r
52   @param  PortNumber           Number of the root hub ports.\r
53   @param  Is64BitCapable       Whether the controller supports 64-bit memory\r
54                                addressing.\r
55 \r
56   @return EFI_SUCCESS           : host controller capability were retrieved successfully.\r
57   @return EFI_INVALID_PARAMETER : Either of the three capability pointer is NULL\r
58 \r
59 **/\r
60 STATIC\r
61 EFI_STATUS\r
62 EFIAPI\r
63 EhcGetCapability (\r
64   IN  EFI_USB2_HC_PROTOCOL  *This,\r
65   OUT UINT8                 *MaxSpeed,\r
66   OUT UINT8                 *PortNumber,\r
67   OUT UINT8                 *Is64BitCapable\r
68   )\r
69 {\r
70   USB2_HC_DEV             *Ehc;\r
71   EFI_TPL                 OldTpl;\r
72 \r
73   if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
74     return EFI_INVALID_PARAMETER;\r
75   }\r
76 \r
77   OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
78   Ehc             = EHC_FROM_THIS (This);\r
79 \r
80   *MaxSpeed       = EFI_USB_SPEED_HIGH;\r
81   *PortNumber     = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);\r
82   *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);\r
83 \r
84   DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
85 \r
86   gBS->RestoreTPL (OldTpl);\r
87   return EFI_SUCCESS;\r
88 }\r
89 \r
90 \r
91 /**\r
92   Provides software reset for the USB host controller.\r
93 \r
94   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
95   @param  Attributes           A bit mask of the reset operation to perform.\r
96 \r
97   @return EFI_SUCCESS           : The reset operation succeeded.\r
98   @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
99   @return EFI_UNSUPPOURTED      : The type of reset specified by Attributes is\r
100   @return not currently supported by the host controller.\r
101   @return EFI_DEVICE_ERROR      : Host controller isn't halted to reset.\r
102 \r
103 **/\r
104 STATIC\r
105 EFI_STATUS\r
106 EFIAPI\r
107 EhcReset (\r
108   IN EFI_USB2_HC_PROTOCOL *This,\r
109   IN UINT16               Attributes\r
110   )\r
111 {\r
112   USB2_HC_DEV             *Ehc;\r
113   EFI_TPL                 OldTpl;\r
114   EFI_STATUS              Status;\r
115 \r
116   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
117   Ehc     = EHC_FROM_THIS (This);\r
118 \r
119   switch (Attributes) {\r
120   case EFI_USB_HC_RESET_GLOBAL:\r
121   //\r
122   // Flow through, same behavior as Host Controller Reset\r
123   //\r
124   case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
125     //\r
126     // Host Controller must be Halt when Reset it\r
127     //\r
128     if (!EhcIsHalt (Ehc)) {\r
129       Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
130 \r
131       if (EFI_ERROR (Status)) {\r
132         Status = EFI_DEVICE_ERROR;\r
133         goto ON_EXIT;\r
134       }\r
135     }\r
136 \r
137     //\r
138     // Clean up the asynchronous transfers, currently only\r
139     // interrupt supports asynchronous operation.\r
140     //\r
141     EhciDelAllAsyncIntTransfers (Ehc);\r
142     EhcAckAllInterrupt (Ehc);\r
143     EhcFreeSched (Ehc);\r
144 \r
145     Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
146 \r
147     if (EFI_ERROR (Status)) {\r
148       goto ON_EXIT;\r
149     }\r
150 \r
151     Status = EhcInitHC (Ehc);\r
152     break;\r
153 \r
154   case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
155   case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
156     Status = EFI_UNSUPPORTED;\r
157     break;\r
158 \r
159   default:\r
160     Status = EFI_INVALID_PARAMETER;\r
161   }\r
162 \r
163 ON_EXIT:\r
164   DEBUG ((EFI_D_INFO, "EhcReset: exit status %r\n", Status));\r
165   gBS->RestoreTPL (OldTpl);\r
166   return Status;\r
167 }\r
168 \r
169 \r
170 /**\r
171   Retrieve the current state of the USB host controller.\r
172 \r
173   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
174   @param  State                Variable to return the current host controller\r
175                                state.\r
176 \r
177   @return EFI_SUCCESS           : Host controller state was returned in State.\r
178   @return EFI_INVALID_PARAMETER : State is NULL.\r
179   @return EFI_DEVICE_ERROR      : An error was encountered while attempting to\r
180   @return retrieve the host controller's current state.\r
181 \r
182 **/\r
183 STATIC\r
184 EFI_STATUS\r
185 EFIAPI\r
186 EhcGetState (\r
187   IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
188   OUT       EFI_USB_HC_STATE      *State\r
189   )\r
190 {\r
191   EFI_TPL                 OldTpl;\r
192   USB2_HC_DEV             *Ehc;\r
193 \r
194   if (State == NULL) {\r
195     return EFI_INVALID_PARAMETER;\r
196   }\r
197 \r
198   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
199   Ehc     = EHC_FROM_THIS (This);\r
200 \r
201   if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
202     *State = EfiUsbHcStateHalt;\r
203   } else {\r
204     *State = EfiUsbHcStateOperational;\r
205   }\r
206 \r
207   gBS->RestoreTPL (OldTpl);\r
208 \r
209   DEBUG ((EFI_D_INFO, "EhcGetState: current state %d\n", *State));\r
210   return EFI_SUCCESS;\r
211 }\r
212 \r
213 \r
214 /**\r
215   Sets the USB host controller to a specific state.\r
216 \r
217   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
218   @param  State                The state of the host controller that will be set.\r
219 \r
220   @return EFI_SUCCESS           : The USB host controller was successfully placed\r
221   @return in the state specified by State.\r
222   @return EFI_INVALID_PARAMETER : State is invalid.\r
223   @return EFI_DEVICE_ERROR      : Failed to set the state due to device error.\r
224 \r
225 **/\r
226 STATIC\r
227 EFI_STATUS\r
228 EFIAPI\r
229 EhcSetState (\r
230   IN EFI_USB2_HC_PROTOCOL *This,\r
231   IN EFI_USB_HC_STATE     State\r
232   )\r
233 {\r
234   USB2_HC_DEV             *Ehc;\r
235   EFI_TPL                 OldTpl;\r
236   EFI_STATUS              Status;\r
237   EFI_USB_HC_STATE        CurState;\r
238 \r
239   Status = EhcGetState (This, &CurState);\r
240 \r
241   if (EFI_ERROR (Status)) {\r
242     return EFI_DEVICE_ERROR;\r
243   }\r
244 \r
245   if (CurState == State) {\r
246     return EFI_SUCCESS;\r
247   }\r
248 \r
249   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
250   Ehc     = EHC_FROM_THIS (This);\r
251 \r
252   switch (State) {\r
253   case EfiUsbHcStateHalt:\r
254     Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
255     break;\r
256 \r
257   case EfiUsbHcStateOperational:\r
258     if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {\r
259       Status = EFI_DEVICE_ERROR;\r
260       break;\r
261     }\r
262 \r
263     //\r
264     // Software must not write a one to this field unless the host controller\r
265     // is in the Halted state. Doing so will yield undefined results.\r
266     // refers to Spec[EHCI1.0-2.3.1]\r
267     //\r
268     if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
269       Status = EFI_DEVICE_ERROR;\r
270       break;\r
271     }\r
272 \r
273     Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
274     break;\r
275 \r
276   case EfiUsbHcStateSuspend:\r
277     Status = EFI_UNSUPPORTED;\r
278     break;\r
279 \r
280   default:\r
281     Status = EFI_INVALID_PARAMETER;\r
282   }\r
283 \r
284   DEBUG ((EFI_D_INFO, "EhcSetState: exit status %r\n", Status));\r
285   gBS->RestoreTPL (OldTpl);\r
286   return Status;\r
287 }\r
288 \r
289 \r
290 /**\r
291   Retrieves the current status of a USB root hub port.\r
292 \r
293   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
294   @param  PortNumber           The root hub port to retrieve the state from.   This\r
295                                value is zero-based.\r
296   @param  PortStatus           Variable to receive the port state\r
297 \r
298   @return EFI_SUCCESS           : The status of the USB root hub port specified\r
299   @return by PortNumber was returned in PortStatus.\r
300   @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
301   @return EFI_DEVICE_ERROR      : Can't read register\r
302 \r
303 **/\r
304 STATIC\r
305 EFI_STATUS\r
306 EFIAPI\r
307 EhcGetRootHubPortStatus (\r
308   IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
309   IN  CONST UINT8                 PortNumber,\r
310   OUT       EFI_USB_PORT_STATUS   *PortStatus\r
311   )\r
312 {\r
313   USB2_HC_DEV             *Ehc;\r
314   EFI_TPL                 OldTpl;\r
315   UINT32                  Offset;\r
316   UINT32                  State;\r
317   UINT32                  TotalPort;\r
318   UINTN                   Index;\r
319   UINTN                   MapSize;\r
320   EFI_STATUS              Status;\r
321 \r
322   if (PortStatus == NULL) {\r
323     return EFI_INVALID_PARAMETER;\r
324   }\r
325 \r
326   OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
327 \r
328   Ehc       = EHC_FROM_THIS (This);\r
329   Status    = EFI_SUCCESS;\r
330 \r
331   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
332 \r
333   if (PortNumber >= TotalPort) {\r
334     Status = EFI_INVALID_PARAMETER;\r
335     goto ON_EXIT;\r
336   }\r
337 \r
338   Offset                        = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
339   PortStatus->PortStatus        = 0;\r
340   PortStatus->PortChangeStatus  = 0;\r
341 \r
342   State                         = EhcReadOpReg (Ehc, Offset);\r
343 \r
344   //\r
345   // Identify device speed. If in K state, it is low speed.\r
346   // If the port is enabled after reset, the device is of\r
347   // high speed. The USB bus driver should retrieve the actual\r
348   // port speed after reset.\r
349   //\r
350   if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {\r
351     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
352 \r
353   } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {\r
354     PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
355   }\r
356 \r
357   //\r
358   // Convert the EHCI port/port change state to UEFI status\r
359   //\r
360   MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
361 \r
362   for (Index = 0; Index < MapSize; Index++) {\r
363     if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
364       PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
365     }\r
366   }\r
367 \r
368   MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
369 \r
370   for (Index = 0; Index < MapSize; Index++) {\r
371     if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
372       PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
373     }\r
374   }\r
375 \r
376 ON_EXIT:\r
377   gBS->RestoreTPL (OldTpl);\r
378   return Status;\r
379 }\r
380 \r
381 \r
382 /**\r
383   Sets a feature for the specified root hub port.\r
384 \r
385   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
386   @param  PortNumber           Root hub port to set.\r
387   @param  PortFeature          Feature to set\r
388 \r
389   @return EFI_SUCCESS           : The feature specified by PortFeature was set\r
390   @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
391   @return EFI_DEVICE_ERROR      : Can't read register\r
392 \r
393 **/\r
394 STATIC\r
395 EFI_STATUS\r
396 EFIAPI\r
397 EhcSetRootHubPortFeature (\r
398   IN  EFI_USB2_HC_PROTOCOL  *This,\r
399   IN  UINT8                 PortNumber,\r
400   IN  EFI_USB_PORT_FEATURE  PortFeature\r
401   )\r
402 {\r
403   USB2_HC_DEV             *Ehc;\r
404   EFI_TPL                 OldTpl;\r
405   UINT32                  Offset;\r
406   UINT32                  State;\r
407   UINT32                  TotalPort;\r
408   EFI_STATUS              Status;\r
409 \r
410   OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
411   Ehc       = EHC_FROM_THIS (This);\r
412   Status    = EFI_SUCCESS;\r
413 \r
414   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
415 \r
416   if (PortNumber >= TotalPort) {\r
417     Status = EFI_INVALID_PARAMETER;\r
418     goto ON_EXIT;\r
419   }\r
420 \r
421   Offset  = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
422   State   = EhcReadOpReg (Ehc, Offset);\r
423 \r
424   //\r
425   // Mask off the port status change bits, these bits are\r
426   // write clean bit\r
427   //\r
428   State &= ~PORTSC_CHANGE_MASK;\r
429 \r
430   switch (PortFeature) {\r
431   case EfiUsbPortEnable:\r
432     //\r
433     // Sofeware can't set this bit, Port can only be enable by\r
434     // EHCI as a part of the reset and enable\r
435     //\r
436     State |= PORTSC_ENABLED;\r
437     EhcWriteOpReg (Ehc, Offset, State);\r
438     break;\r
439 \r
440   case EfiUsbPortSuspend:\r
441     State |= PORTSC_SUSPEND;\r
442     EhcWriteOpReg (Ehc, Offset, State);\r
443     break;\r
444 \r
445   case EfiUsbPortReset:\r
446     //\r
447     // Make sure Host Controller not halt before reset it\r
448     //\r
449     if (EhcIsHalt (Ehc)) {\r
450       Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
451 \r
452       if (EFI_ERROR (Status)) {\r
453         DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
454         break;\r
455       }\r
456     }\r
457 \r
458     //\r
459     // Set one to PortReset bit must also set zero to PortEnable bit\r
460     //\r
461     State |= PORTSC_RESET;\r
462     State &= ~PORTSC_ENABLED;\r
463     EhcWriteOpReg (Ehc, Offset, State);\r
464     break;\r
465 \r
466   case EfiUsbPortPower:\r
467     //\r
468     // Not supported, ignore the operation\r
469     //\r
470     Status = EFI_SUCCESS;\r
471     break;\r
472 \r
473   case EfiUsbPortOwner:\r
474     State |= PORTSC_OWNER;\r
475     EhcWriteOpReg (Ehc, Offset, State);\r
476     break;\r
477 \r
478   default:\r
479     Status = EFI_INVALID_PARAMETER;\r
480   }\r
481 \r
482 ON_EXIT:\r
483   DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));\r
484 \r
485   gBS->RestoreTPL (OldTpl);\r
486   return Status;\r
487 }\r
488 \r
489 \r
490 /**\r
491   Clears a feature for the specified root hub port.\r
492 \r
493   @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
494   @param  PortNumber           Specifies the root hub port whose feature is\r
495                                requested to be cleared.\r
496   @param  PortFeature          Indicates the feature selector associated with the\r
497                                feature clear request.\r
498 \r
499   @return EFI_SUCCESS           : The feature specified by PortFeature was cleared\r
500   @return for the USB root hub port specified by PortNumber.\r
501   @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
502   @return EFI_DEVICE_ERROR      : Can't read register\r
503 \r
504 **/\r
505 STATIC\r
506 EFI_STATUS\r
507 EFIAPI\r
508 EhcClearRootHubPortFeature (\r
509   IN  EFI_USB2_HC_PROTOCOL  *This,\r
510   IN  UINT8                 PortNumber,\r
511   IN  EFI_USB_PORT_FEATURE  PortFeature\r
512   )\r
513 {\r
514   USB2_HC_DEV             *Ehc;\r
515   EFI_TPL                 OldTpl;\r
516   UINT32                  Offset;\r
517   UINT32                  State;\r
518   UINT32                  TotalPort;\r
519   EFI_STATUS              Status;\r
520 \r
521   OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
522   Ehc       = EHC_FROM_THIS (This);\r
523   Status    = EFI_SUCCESS;\r
524 \r
525   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
526 \r
527   if (PortNumber >= TotalPort) {\r
528     Status = EFI_INVALID_PARAMETER;\r
529     goto ON_EXIT;\r
530   }\r
531 \r
532   Offset  = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
533   State   = EhcReadOpReg (Ehc, Offset);\r
534   State &= ~PORTSC_CHANGE_MASK;\r
535 \r
536   switch (PortFeature) {\r
537   case EfiUsbPortEnable:\r
538     //\r
539     // Clear PORT_ENABLE feature means disable port.\r
540     //\r
541     State &= ~PORTSC_ENABLED;\r
542     EhcWriteOpReg (Ehc, Offset, State);\r
543     break;\r
544 \r
545   case EfiUsbPortSuspend:\r
546     //\r
547     // A write of zero to this bit is ignored by the host\r
548     // controller. The host controller will unconditionally\r
549     // set this bit to a zero when:\r
550     //   1. software sets the Forct Port Resume bit to a zero from a one.\r
551     //   2. software sets the Port Reset bit to a one frome a zero.\r
552     //\r
553     State &= ~PORSTSC_RESUME;\r
554     EhcWriteOpReg (Ehc, Offset, State);\r
555     break;\r
556 \r
557   case EfiUsbPortReset:\r
558     //\r
559     // Clear PORT_RESET means clear the reset signal.\r
560     //\r
561     State &= ~PORTSC_RESET;\r
562     EhcWriteOpReg (Ehc, Offset, State);\r
563     break;\r
564 \r
565   case EfiUsbPortOwner:\r
566     //\r
567     // Clear port owner means this port owned by EHC\r
568     //\r
569     State &= ~PORTSC_OWNER;\r
570     EhcWriteOpReg (Ehc, Offset, State);\r
571     break;\r
572 \r
573   case EfiUsbPortConnectChange:\r
574     //\r
575     // Clear connect status change\r
576     //\r
577     State |= PORTSC_CONN_CHANGE;\r
578     EhcWriteOpReg (Ehc, Offset, State);\r
579     break;\r
580 \r
581   case EfiUsbPortEnableChange:\r
582     //\r
583     // Clear enable status change\r
584     //\r
585     State |= PORTSC_ENABLE_CHANGE;\r
586     EhcWriteOpReg (Ehc, Offset, State);\r
587     break;\r
588 \r
589   case EfiUsbPortOverCurrentChange:\r
590     //\r
591     // Clear PortOverCurrent change\r
592     //\r
593     State |= PORTSC_OVERCUR_CHANGE;\r
594     EhcWriteOpReg (Ehc, Offset, State);\r
595     break;\r
596 \r
597   case EfiUsbPortPower:\r
598   case EfiUsbPortSuspendChange:\r
599   case EfiUsbPortResetChange:\r
600     //\r
601     // Not supported or not related operation\r
602     //\r
603     break;\r
604 \r
605   default:\r
606     Status = EFI_INVALID_PARAMETER;\r
607     break;\r
608   }\r
609 \r
610 ON_EXIT:\r
611   DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));\r
612   gBS->RestoreTPL (OldTpl);\r
613   return Status;\r
614 }\r
615 \r
616 \r
617 /**\r
618   Submits control transfer to a target USB device.\r
619 \r
620   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
621   @param  DeviceAddress        The target device address\r
622   @param  DeviceSpeed          Target device speed.\r
623   @param  MaximumPacketLength  Maximum packet size the default control transfer\r
624                                endpoint is capable of sending or receiving.\r
625   @param  Request              USB device request to send\r
626   @param  TransferDirection    Specifies the data direction for the data stage\r
627   @param  Data                 Data buffer to be transmitted or received from USB\r
628                                device.\r
629   @param  DataLength           The size (in bytes) of the data buffer\r
630   @param  TimeOut              Indicates the maximum timeout, in millisecond,\r
631   @param  Translator           Transaction translator to be used by this device.\r
632   @param  TransferResult       Return the result of this control transfer.\r
633 \r
634   @return EFI_SUCCESS           : Transfer was completed successfully.\r
635   @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resources.\r
636   @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
637   @return EFI_TIMEOUT           : Transfer failed due to timeout.\r
638   @return EFI_DEVICE_ERROR      : Transfer failed due to host controller or device error.\r
639 \r
640 **/\r
641 STATIC\r
642 EFI_STATUS\r
643 EFIAPI\r
644 EhcControlTransfer (\r
645   IN  EFI_USB2_HC_PROTOCOL                *This,\r
646   IN  UINT8                               DeviceAddress,\r
647   IN  UINT8                               DeviceSpeed,\r
648   IN  UINTN                               MaximumPacketLength,\r
649   IN  EFI_USB_DEVICE_REQUEST              *Request,\r
650   IN  EFI_USB_DATA_DIRECTION              TransferDirection,\r
651   IN  OUT VOID                            *Data,\r
652   IN  OUT UINTN                           *DataLength,\r
653   IN  UINTN                               TimeOut,\r
654   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
655   OUT UINT32                              *TransferResult\r
656   )\r
657 {\r
658   USB2_HC_DEV             *Ehc;\r
659   URB                     *Urb;\r
660   EFI_TPL                 OldTpl;\r
661   UINT8                   Endpoint;\r
662   EFI_STATUS              Status;\r
663 \r
664   //\r
665   // Validate parameters\r
666   //\r
667   if ((Request == NULL) || (TransferResult == NULL)) {\r
668     return EFI_INVALID_PARAMETER;\r
669   }\r
670 \r
671   if ((TransferDirection != EfiUsbDataIn) &&\r
672       (TransferDirection != EfiUsbDataOut) &&\r
673       (TransferDirection != EfiUsbNoData)) {\r
674     return EFI_INVALID_PARAMETER;\r
675   }\r
676 \r
677   if ((TransferDirection == EfiUsbNoData) &&\r
678       ((Data != NULL) || (*DataLength != 0))) {\r
679     return EFI_INVALID_PARAMETER;\r
680   }\r
681 \r
682   if ((TransferDirection != EfiUsbNoData) &&\r
683      ((Data == NULL) || (*DataLength == 0))) {\r
684     return EFI_INVALID_PARAMETER;\r
685   }\r
686 \r
687   if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&\r
688       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
689     return EFI_INVALID_PARAMETER;\r
690   }\r
691 \r
692   if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
693     return EFI_INVALID_PARAMETER;\r
694   }\r
695 \r
696   OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
697   Ehc             = EHC_FROM_THIS (This);\r
698 \r
699   Status          = EFI_DEVICE_ERROR;\r
700   *TransferResult = EFI_USB_ERR_SYSTEM;\r
701 \r
702   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
703     DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n"));\r
704 \r
705     EhcAckAllInterrupt (Ehc);\r
706     goto ON_EXIT;\r
707   }\r
708 \r
709   EhcAckAllInterrupt (Ehc);\r
710 \r
711   //\r
712   // Create a new URB, insert it into the asynchronous\r
713   // schedule list, then poll the execution status.\r
714   //\r
715   //\r
716   // Encode the direction in address, although default control\r
717   // endpoint is bidirectional. EhcCreateUrb expects this\r
718   // combination of Ep addr and its direction.\r
719   //\r
720   Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
721   Urb = EhcCreateUrb (\r
722           Ehc,\r
723           DeviceAddress,\r
724           Endpoint,\r
725           DeviceSpeed,\r
726           0,\r
727           MaximumPacketLength,\r
728           Translator,\r
729           EHC_CTRL_TRANSFER,\r
730           Request,\r
731           Data,\r
732           *DataLength,\r
733           NULL,\r
734           NULL,\r
735           1\r
736           );\r
737 \r
738   if (Urb == NULL) {\r
739     DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB"));\r
740 \r
741     Status = EFI_OUT_OF_RESOURCES;\r
742     goto ON_EXIT;\r
743   }\r
744 \r
745   EhcLinkQhToAsync (Ehc, Urb->Qh);\r
746   Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
747   EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
748 \r
749   //\r
750   // Get the status from URB. The result is updated in EhcCheckUrbResult\r
751   // which is called by EhcExecTransfer\r
752   //\r
753   *TransferResult = Urb->Result;\r
754   *DataLength     = Urb->Completed;\r
755 \r
756   if (*TransferResult == EFI_USB_NOERROR) {\r
757     Status = EFI_SUCCESS;\r
758   }\r
759 \r
760   EhcAckAllInterrupt (Ehc);\r
761   EhcFreeUrb (Ehc, Urb);\r
762 \r
763 ON_EXIT:\r
764   Ehc->PciIo->Flush (Ehc->PciIo);\r
765   gBS->RestoreTPL (OldTpl);\r
766 \r
767   if (EFI_ERROR (Status)) {\r
768     DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
769   }\r
770 \r
771   return Status;\r
772 }\r
773 \r
774 \r
775 /**\r
776   Submits bulk transfer to a bulk endpoint of a USB device.\r
777 \r
778   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
779   @param  DeviceAddress        Target device address\r
780   @param  EndPointAddress      Endpoint number and its direction in bit 7. .\r
781   @param  DeviceSpeed          Device speed, Low speed device doesn't support  bulk\r
782                                transfer.\r
783   @param  MaximumPacketLength  Maximum packet size the endpoint is capable of\r
784                                sending or receiving.\r
785   @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\r
786   @param  Data                 Array of pointers to the buffers of data to transmit\r
787                                 from or receive into.\r
788   @param  DataLength           The lenght of the data buffer\r
789   @param  DataToggle           On input, the initial data toggle for the transfer;\r
790                                On output, it is updated to to next data toggle to\r
791                                use                        of the subsequent bulk\r
792                                transfer.\r
793   @param  Translator           A pointr to the transaction translator data.\r
794   @param  TimeOut              Indicates the maximum time, in millisecond, which\r
795                                the transfer is allowed to complete.\r
796   @param  TransferResult       A pointer to the detailed result information of the\r
797                                bulk transfer.\r
798 \r
799   @return EFI_SUCCESS           : The transfer was completed successfully.\r
800   @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resource.\r
801   @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
802   @return EFI_TIMEOUT           : The transfer failed due to timeout.\r
803   @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
804 \r
805 **/\r
806 STATIC\r
807 EFI_STATUS\r
808 EFIAPI\r
809 EhcBulkTransfer (\r
810   IN  EFI_USB2_HC_PROTOCOL                *This,\r
811   IN  UINT8                               DeviceAddress,\r
812   IN  UINT8                               EndPointAddress,\r
813   IN  UINT8                               DeviceSpeed,\r
814   IN  UINTN                               MaximumPacketLength,\r
815   IN  UINT8                               DataBuffersNumber,\r
816   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
817   IN  OUT UINTN                           *DataLength,\r
818   IN  OUT UINT8                           *DataToggle,\r
819   IN  UINTN                               TimeOut,\r
820   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
821   OUT UINT32                              *TransferResult\r
822   )\r
823 {\r
824   USB2_HC_DEV             *Ehc;\r
825   URB                     *Urb;\r
826   EFI_TPL                 OldTpl;\r
827   EFI_STATUS              Status;\r
828 \r
829   //\r
830   // Validate the parameters\r
831   //\r
832   if ((DataLength == NULL) || (*DataLength == 0) ||\r
833       (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
834     return EFI_INVALID_PARAMETER;\r
835   }\r
836 \r
837   if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
838     return EFI_INVALID_PARAMETER;\r
839   }\r
840 \r
841   if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
842       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
843       ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
844     return EFI_INVALID_PARAMETER;\r
845   }\r
846 \r
847   OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
848   Ehc             = EHC_FROM_THIS (This);\r
849 \r
850   *TransferResult = EFI_USB_ERR_SYSTEM;\r
851   Status          = EFI_DEVICE_ERROR;\r
852 \r
853   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
854     DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n"));\r
855 \r
856     EhcAckAllInterrupt (Ehc);\r
857     goto ON_EXIT;\r
858   }\r
859 \r
860   EhcAckAllInterrupt (Ehc);\r
861 \r
862   //\r
863   // Create a new URB, insert it into the asynchronous\r
864   // schedule list, then poll the execution status.\r
865   //\r
866   Urb = EhcCreateUrb (\r
867           Ehc,\r
868           DeviceAddress,\r
869           EndPointAddress,\r
870           DeviceSpeed,\r
871           *DataToggle,\r
872           MaximumPacketLength,\r
873           Translator,\r
874           EHC_BULK_TRANSFER,\r
875           NULL,\r
876           Data[0],\r
877           *DataLength,\r
878           NULL,\r
879           NULL,\r
880           1\r
881           );\r
882 \r
883   if (Urb == NULL) {\r
884     DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n"));\r
885 \r
886     Status = EFI_OUT_OF_RESOURCES;\r
887     goto ON_EXIT;\r
888   }\r
889 \r
890   EhcLinkQhToAsync (Ehc, Urb->Qh);\r
891   Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
892   EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
893 \r
894   *TransferResult = Urb->Result;\r
895   *DataLength     = Urb->Completed;\r
896   *DataToggle     = Urb->DataToggle;\r
897 \r
898   if (*TransferResult == EFI_USB_NOERROR) {\r
899     Status = EFI_SUCCESS;\r
900   }\r
901 \r
902   EhcAckAllInterrupt (Ehc);\r
903   EhcFreeUrb (Ehc, Urb);\r
904 \r
905 ON_EXIT:\r
906   Ehc->PciIo->Flush (Ehc->PciIo);\r
907   gBS->RestoreTPL (OldTpl);\r
908 \r
909   if (EFI_ERROR (Status)) {\r
910     DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
911   }\r
912 \r
913   return Status;\r
914 }\r
915 \r
916 \r
917 /**\r
918   Submits an asynchronous interrupt transfer to an\r
919   interrupt endpoint of a USB device.\r
920 \r
921   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
922   @param  DeviceAddress        Target device address\r
923   @param  EndPointAddress      Endpoint number and its direction encoded in bit 7\r
924   @param  DeviceSpeed          Indicates device speed.\r
925   @param  MaximumPacketLength  Maximum packet size the target endpoint is capable\r
926   @param  IsNewTransfer        If TRUE, to submit an new asynchronous interrupt\r
927                                transfer If FALSE, to remove the specified\r
928                                asynchronous interrupt\r
929   @param  DataToggle           On input, the initial data toggle to use; on output,\r
930                                it is updated to indicate the next data toggle\r
931   @param  PollingInterval      The he interval, in milliseconds, that the transfer\r
932                                is polled.\r
933   @param  DataLength           The length of data to receive at the rate specified\r
934                                by  PollingInterval.\r
935   @param  Translator           Transaction translator to use.\r
936   @param  CallBackFunction     Function to call at the rate specified by\r
937                                PollingInterval\r
938   @param  Context              Context to CallBackFunction.\r
939 \r
940   @return EFI_SUCCESS           : The request has been successfully submitted or canceled.\r
941   @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
942   @return EFI_OUT_OF_RESOURCES  : The request failed due to a lack of resources.\r
943   @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
944 \r
945 **/\r
946 STATIC\r
947 EFI_STATUS\r
948 EFIAPI\r
949 EhcAsyncInterruptTransfer (\r
950   IN  EFI_USB2_HC_PROTOCOL                  * This,\r
951   IN  UINT8                                 DeviceAddress,\r
952   IN  UINT8                                 EndPointAddress,\r
953   IN  UINT8                                 DeviceSpeed,\r
954   IN  UINTN                                 MaximumPacketLength,\r
955   IN  BOOLEAN                               IsNewTransfer,\r
956   IN  OUT UINT8                             *DataToggle,\r
957   IN  UINTN                                 PollingInterval,\r
958   IN  UINTN                                 DataLength,\r
959   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    * Translator,\r
960   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,\r
961   IN  VOID                                  *Context OPTIONAL\r
962   )\r
963 {\r
964   USB2_HC_DEV             *Ehc;\r
965   URB                     *Urb;\r
966   EFI_TPL                 OldTpl;\r
967   EFI_STATUS              Status;\r
968   UINT8                   *Data;\r
969 \r
970   //\r
971   // Validate parameters\r
972   //\r
973   if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
974     return EFI_INVALID_PARAMETER;\r
975   }\r
976 \r
977   if (IsNewTransfer) {\r
978     if (DataLength == 0) {\r
979       return EFI_INVALID_PARAMETER;\r
980     }\r
981 \r
982     if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
983       return EFI_INVALID_PARAMETER;\r
984     }\r
985 \r
986     if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
987       return EFI_INVALID_PARAMETER;\r
988     }\r
989   }\r
990 \r
991   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
992   Ehc     = EHC_FROM_THIS (This);\r
993 \r
994   //\r
995   // Delete Async interrupt transfer request. DataToggle will return\r
996   // the next data toggle to use.\r
997   //\r
998   if (!IsNewTransfer) {\r
999     Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
1000 \r
1001     DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
1002     goto ON_EXIT;\r
1003   }\r
1004 \r
1005   Status = EFI_SUCCESS;\r
1006 \r
1007   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1008     DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));\r
1009     EhcAckAllInterrupt (Ehc);\r
1010 \r
1011     Status = EFI_DEVICE_ERROR;\r
1012     goto ON_EXIT;\r
1013   }\r
1014 \r
1015   EhcAckAllInterrupt (Ehc);\r
1016 \r
1017   Data = AllocatePool (DataLength);\r
1018 \r
1019   if (Data == NULL) {\r
1020     DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
1021 \r
1022     Status = EFI_OUT_OF_RESOURCES;\r
1023     goto ON_EXIT;\r
1024   }\r
1025 \r
1026   Urb = EhcCreateUrb (\r
1027           Ehc,\r
1028           DeviceAddress,\r
1029           EndPointAddress,\r
1030           DeviceSpeed,\r
1031           *DataToggle,\r
1032           MaximumPacketLength,\r
1033           Translator,\r
1034           EHC_INT_TRANSFER_ASYNC,\r
1035           NULL,\r
1036           Data,\r
1037           DataLength,\r
1038           CallBackFunction,\r
1039           Context,\r
1040           PollingInterval\r
1041           );\r
1042 \r
1043   if (Urb == NULL) {\r
1044     DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to create URB\n"));\r
1045 \r
1046     gBS->FreePool (Data);\r
1047     Status = EFI_OUT_OF_RESOURCES;\r
1048     goto ON_EXIT;\r
1049   }\r
1050 \r
1051   //\r
1052   // New asynchronous transfer must inserted to the head.\r
1053   // Check the comments in EhcMoniteAsyncRequests\r
1054   //\r
1055   EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1056   InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
1057 \r
1058 ON_EXIT:\r
1059   Ehc->PciIo->Flush (Ehc->PciIo);\r
1060   gBS->RestoreTPL (OldTpl);\r
1061 \r
1062   return Status;\r
1063 }\r
1064 \r
1065 \r
1066 /**\r
1067   Submits synchronous interrupt transfer to an interrupt endpoint\r
1068   of a USB device.\r
1069 \r
1070   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
1071   @param  DeviceAddress        Target device address\r
1072   @param  EndPointAddress      Endpoint number and its direction encoded in bit 7\r
1073   @param  DeviceSpeed          Indicates device speed.\r
1074   @param  MaximumPacketLength  Maximum packet size the target endpoint is capable\r
1075                                of sending or receiving.\r
1076   @param  Data                 Buffer of data that will be transmitted to  USB\r
1077                                device or received from USB device.\r
1078   @param  DataLength           On input, the size, in bytes, of the data buffer; On\r
1079                                output, the number of bytes transferred.\r
1080   @param  DataToggle           On input, the initial data toggle to use; on output,\r
1081                                it is updated to indicate the next data toggle\r
1082   @param  TimeOut              Maximum time, in second, to complete\r
1083   @param  Translator           Transaction translator to use.\r
1084   @param  TransferResult       Variable to receive the transfer result\r
1085 \r
1086   @return EFI_SUCCESS           : The transfer was completed successfully.\r
1087   @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resource.\r
1088   @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
1089   @return EFI_TIMEOUT           : The transfer failed due to timeout.\r
1090   @return EFI_DEVICE_ERROR      : The failed due to host controller or device error\r
1091 \r
1092 **/\r
1093 STATIC\r
1094 EFI_STATUS\r
1095 EFIAPI\r
1096 EhcSyncInterruptTransfer (\r
1097   IN  EFI_USB2_HC_PROTOCOL                *This,\r
1098   IN  UINT8                               DeviceAddress,\r
1099   IN  UINT8                               EndPointAddress,\r
1100   IN  UINT8                               DeviceSpeed,\r
1101   IN  UINTN                               MaximumPacketLength,\r
1102   IN  OUT VOID                            *Data,\r
1103   IN  OUT UINTN                           *DataLength,\r
1104   IN  OUT UINT8                           *DataToggle,\r
1105   IN  UINTN                               TimeOut,\r
1106   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
1107   OUT UINT32                              *TransferResult\r
1108   )\r
1109 {\r
1110   USB2_HC_DEV             *Ehc;\r
1111   EFI_TPL                 OldTpl;\r
1112   URB                     *Urb;\r
1113   EFI_STATUS              Status;\r
1114 \r
1115   //\r
1116   // Validates parameters\r
1117   //\r
1118   if ((DataLength == NULL) || (*DataLength == 0) ||\r
1119       (Data == NULL) || (TransferResult == NULL)) {\r
1120     return EFI_INVALID_PARAMETER;\r
1121   }\r
1122 \r
1123   if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
1124     return EFI_INVALID_PARAMETER;\r
1125   }\r
1126 \r
1127   if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1128     return EFI_INVALID_PARAMETER;\r
1129   }\r
1130 \r
1131   if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8))  ||\r
1132       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1133       ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
1134     return EFI_INVALID_PARAMETER;\r
1135   }\r
1136 \r
1137   OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
1138   Ehc             = EHC_FROM_THIS (This);\r
1139 \r
1140   *TransferResult = EFI_USB_ERR_SYSTEM;\r
1141   Status          = EFI_DEVICE_ERROR;\r
1142 \r
1143   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1144     DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
1145 \r
1146     EhcAckAllInterrupt (Ehc);\r
1147     goto ON_EXIT;\r
1148   }\r
1149 \r
1150   EhcAckAllInterrupt (Ehc);\r
1151 \r
1152   Urb = EhcCreateUrb (\r
1153           Ehc,\r
1154           DeviceAddress,\r
1155           EndPointAddress,\r
1156           DeviceSpeed,\r
1157           *DataToggle,\r
1158           MaximumPacketLength,\r
1159           Translator,\r
1160           EHC_INT_TRANSFER_SYNC,\r
1161           NULL,\r
1162           Data,\r
1163           *DataLength,\r
1164           NULL,\r
1165           NULL,\r
1166           1\r
1167           );\r
1168 \r
1169   if (Urb == NULL) {\r
1170     DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));\r
1171 \r
1172     Status = EFI_OUT_OF_RESOURCES;\r
1173     goto ON_EXIT;\r
1174   }\r
1175 \r
1176   EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1177   Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
1178   EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
1179 \r
1180   *TransferResult = Urb->Result;\r
1181   *DataLength     = Urb->Completed;\r
1182   *DataToggle     = Urb->DataToggle;\r
1183 \r
1184   if (*TransferResult == EFI_USB_NOERROR) {\r
1185     Status = EFI_SUCCESS;\r
1186   }\r
1187 \r
1188 ON_EXIT:\r
1189   Ehc->PciIo->Flush (Ehc->PciIo);\r
1190   gBS->RestoreTPL (OldTpl);\r
1191 \r
1192   if (EFI_ERROR (Status)) {\r
1193     DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
1194   }\r
1195 \r
1196   return Status;\r
1197 }\r
1198 \r
1199 \r
1200 /**\r
1201   Submits isochronous transfer to a target USB device.\r
1202 \r
1203   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
1204   @param  DeviceAddress        Target device address\r
1205   @param  EndPointAddress      End point address with its direction\r
1206   @param  DeviceSpeed          Device speed, Low speed device doesn't support this\r
1207                                type.\r
1208   @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of\r
1209                                sending or receiving.\r
1210   @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\r
1211   @param  Data                 Array of pointers to the buffers of data that will\r
1212                                be transmitted to USB device or received from USB\r
1213                                device.\r
1214   @param  DataLength           The size, in bytes, of the data buffer\r
1215   @param  Translator           Transaction translator to use.\r
1216   @param  TransferResult       Variable to receive the transfer result\r
1217 \r
1218   @return EFI_UNSUPPORTED : Isochronous transfer is unsupported.\r
1219 \r
1220 **/\r
1221 STATIC\r
1222 EFI_STATUS\r
1223 EFIAPI\r
1224 EhcIsochronousTransfer (\r
1225   IN  EFI_USB2_HC_PROTOCOL                *This,\r
1226   IN  UINT8                               DeviceAddress,\r
1227   IN  UINT8                               EndPointAddress,\r
1228   IN  UINT8                               DeviceSpeed,\r
1229   IN  UINTN                               MaximumPacketLength,\r
1230   IN  UINT8                               DataBuffersNumber,\r
1231   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1232   IN  UINTN                               DataLength,\r
1233   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
1234   OUT UINT32                              *TransferResult\r
1235   )\r
1236 {\r
1237   return EFI_UNSUPPORTED;\r
1238 }\r
1239 \r
1240 \r
1241 /**\r
1242   Submits Async isochronous transfer to a target USB device.\r
1243 \r
1244   @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
1245   @param  DeviceAddress        Target device address\r
1246   @param  EndPointAddress      End point address with its direction\r
1247   @param  DeviceSpeed          Device speed, Low speed device doesn't support this\r
1248                                type.\r
1249   @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of\r
1250                                sending or receiving.\r
1251   @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\r
1252   @param  Data                 Array of pointers to the buffers of data that will\r
1253                                be transmitted to USB device or received from USB\r
1254                                device.\r
1255   @param  DataLength           The size, in bytes, of the data buffer\r
1256   @param  Translator           Transaction translator to use.\r
1257   @param  IsochronousCallBack  Function to be called when the transfer complete\r
1258   @param  Context              Context passed to the call back function as\r
1259                                parameter\r
1260 \r
1261   @return EFI_UNSUPPORTED : Isochronous transfer isn't supported\r
1262 \r
1263 **/\r
1264 STATIC\r
1265 EFI_STATUS\r
1266 EFIAPI\r
1267 EhcAsyncIsochronousTransfer (\r
1268   IN  EFI_USB2_HC_PROTOCOL                *This,\r
1269   IN  UINT8                               DeviceAddress,\r
1270   IN  UINT8                               EndPointAddress,\r
1271   IN  UINT8                               DeviceSpeed,\r
1272   IN  UINTN                               MaximumPacketLength,\r
1273   IN  UINT8                               DataBuffersNumber,\r
1274   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1275   IN  UINTN                               DataLength,\r
1276   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
1277   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
1278   IN  VOID                                *Context\r
1279   )\r
1280 {\r
1281   return EFI_UNSUPPORTED;\r
1282 }\r
1283 \r
1284 EFI_STATUS\r
1285 EFIAPI\r
1286 EhcDriverEntryPoint (\r
1287   IN EFI_HANDLE           ImageHandle,\r
1288   IN EFI_SYSTEM_TABLE     *SystemTable\r
1289   )\r
1290 /*++\r
1291 \r
1292 Routine Description:\r
1293 \r
1294   Entry point for EFI drivers.\r
1295 \r
1296 Arguments:\r
1297 \r
1298   ImageHandle - EFI_HANDLE\r
1299   SystemTable - EFI_SYSTEM_TABLE\r
1300 \r
1301 Returns:\r
1302 \r
1303   EFI_SUCCESS         Success\r
1304   EFI_DEVICE_ERROR    Fail\r
1305 \r
1306 --*/\r
1307 {\r
1308   return EfiLibInstallDriverBindingComponentName2 (\r
1309            ImageHandle,\r
1310            SystemTable,\r
1311            &gEhciDriverBinding,\r
1312            ImageHandle,\r
1313            &gEhciComponentName,\r
1314            &gEhciComponentName2\r
1315            );\r
1316 }\r
1317 \r
1318 \r
1319 /**\r
1320   Test to see if this driver supports ControllerHandle. Any\r
1321   ControllerHandle that has Usb2HcProtocol installed will\r
1322   be supported.\r
1323 \r
1324   @param  This                 Protocol instance pointer.\r
1325   @param  Controlle            Handle of device to test\r
1326   @param  RemainingDevicePath  Not used\r
1327 \r
1328   @return EFI_SUCCESS         : This driver supports this device.\r
1329   @return EFI_UNSUPPORTED     : This driver does not support this device.\r
1330 \r
1331 **/\r
1332 EFI_STATUS\r
1333 EFIAPI\r
1334 EhcDriverBindingSupported (\r
1335   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1336   IN EFI_HANDLE                  Controller,\r
1337   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
1338   )\r
1339 {\r
1340   EFI_STATUS              Status;\r
1341   EFI_PCI_IO_PROTOCOL     *PciIo;\r
1342   USB_CLASSC              UsbClassCReg;\r
1343 \r
1344   //\r
1345   // Test whether there is PCI IO Protocol attached on the controller handle.\r
1346   //\r
1347   Status = gBS->OpenProtocol (\r
1348                   Controller,\r
1349                   &gEfiPciIoProtocolGuid,\r
1350                   (VOID **) &PciIo,\r
1351                   This->DriverBindingHandle,\r
1352                   Controller,\r
1353                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1354                   );\r
1355 \r
1356   if (EFI_ERROR (Status)) {\r
1357     return EFI_UNSUPPORTED;\r
1358   }\r
1359 \r
1360   Status = PciIo->Pci.Read (\r
1361                         PciIo,\r
1362                         EfiPciIoWidthUint8,\r
1363                         EHC_PCI_CLASSC,\r
1364                         sizeof (USB_CLASSC) / sizeof (UINT8),\r
1365                         &UsbClassCReg\r
1366                         );\r
1367 \r
1368   if (EFI_ERROR (Status)) {\r
1369     Status = EFI_UNSUPPORTED;\r
1370     goto ON_EXIT;\r
1371   }\r
1372 \r
1373   //\r
1374   // Test whether the controller belongs to Ehci type\r
1375   //\r
1376   if ((UsbClassCReg.BaseCode     != PCI_CLASS_SERIAL) ||\r
1377       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1378       (UsbClassCReg.PI           != EHC_PCI_CLASSC_PI)) {\r
1379 \r
1380     Status = EFI_UNSUPPORTED;\r
1381   }\r
1382 \r
1383 ON_EXIT:\r
1384   gBS->CloseProtocol (\r
1385          Controller,\r
1386          &gEfiPciIoProtocolGuid,\r
1387          This->DriverBindingHandle,\r
1388          Controller\r
1389          );\r
1390 \r
1391   return Status;\r
1392 }\r
1393 \r
1394 \r
1395 /**\r
1396   Create and initialize a USB2_HC_DEV\r
1397 \r
1398   @param  PciIo                  The PciIo on this device\r
1399   @param  OriginalPciAttributes  Original PCI attributes\r
1400 \r
1401   @return The allocated and initialized USB2_HC_DEV structure\r
1402   @return if created, otherwise NULL.\r
1403 \r
1404 **/\r
1405 STATIC\r
1406 USB2_HC_DEV *\r
1407 EhcCreateUsb2Hc (\r
1408   IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
1409   IN UINT64               OriginalPciAttributes\r
1410   )\r
1411 {\r
1412   USB2_HC_DEV             *Ehc;\r
1413   EFI_STATUS              Status;\r
1414 \r
1415   Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
1416 \r
1417   if (Ehc == NULL) {\r
1418     return NULL;\r
1419   }\r
1420 \r
1421   //\r
1422   // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
1423   //\r
1424   Ehc->Signature                        = USB2_HC_DEV_SIGNATURE;\r
1425 \r
1426   Ehc->Usb2Hc.GetCapability             = EhcGetCapability;\r
1427   Ehc->Usb2Hc.Reset                     = EhcReset;\r
1428   Ehc->Usb2Hc.GetState                  = EhcGetState;\r
1429   Ehc->Usb2Hc.SetState                  = EhcSetState;\r
1430   Ehc->Usb2Hc.ControlTransfer           = EhcControlTransfer;\r
1431   Ehc->Usb2Hc.BulkTransfer              = EhcBulkTransfer;\r
1432   Ehc->Usb2Hc.AsyncInterruptTransfer    = EhcAsyncInterruptTransfer;\r
1433   Ehc->Usb2Hc.SyncInterruptTransfer     = EhcSyncInterruptTransfer;\r
1434   Ehc->Usb2Hc.IsochronousTransfer       = EhcIsochronousTransfer;\r
1435   Ehc->Usb2Hc.AsyncIsochronousTransfer  = EhcAsyncIsochronousTransfer;\r
1436   Ehc->Usb2Hc.GetRootHubPortStatus      = EhcGetRootHubPortStatus;\r
1437   Ehc->Usb2Hc.SetRootHubPortFeature     = EhcSetRootHubPortFeature;\r
1438   Ehc->Usb2Hc.ClearRootHubPortFeature   = EhcClearRootHubPortFeature;\r
1439   Ehc->Usb2Hc.MajorRevision             = 0x1;\r
1440   Ehc->Usb2Hc.MinorRevision             = 0x1;\r
1441 \r
1442   Ehc->PciIo                 = PciIo;\r
1443   Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
1444 \r
1445   InitializeListHead (&Ehc->AsyncIntTransfers);\r
1446 \r
1447   Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);\r
1448   Ehc->HcCapParams    = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
1449   Ehc->CapLen         = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
1450 \r
1451   DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
1452 \r
1453   //\r
1454   // Create AsyncRequest Polling Timer\r
1455   //\r
1456   Status = gBS->CreateEvent (\r
1457                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1458                   TPL_CALLBACK,\r
1459                   EhcMoniteAsyncRequests,\r
1460                   Ehc,\r
1461                   &Ehc->PollTimer\r
1462                   );\r
1463 \r
1464   if (EFI_ERROR (Status)) {\r
1465     gBS->FreePool (Ehc);\r
1466     return NULL;\r
1467   }\r
1468 \r
1469   return Ehc;\r
1470 }\r
1471 \r
1472 \r
1473 /**\r
1474   Starting the Usb EHCI Driver\r
1475 \r
1476   @param  This                 Protocol instance pointer.\r
1477   @param  Controller           Handle of device to test\r
1478   @param  RemainingDevicePath  Not used\r
1479 \r
1480   @return EFI_SUCCESS          : supports this device.\r
1481   @return EFI_UNSUPPORTED      : do not support this device.\r
1482   @return EFI_DEVICE_ERROR     : cannot be started due to device Error\r
1483   @return EFI_OUT_OF_RESOURCES : cannot allocate resources\r
1484 \r
1485 **/\r
1486 EFI_STATUS\r
1487 EFIAPI\r
1488 EhcDriverBindingStart (\r
1489   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1490   IN EFI_HANDLE                  Controller,\r
1491   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
1492   )\r
1493 {\r
1494   EFI_STATUS              Status;\r
1495   USB2_HC_DEV             *Ehc;\r
1496   EFI_PCI_IO_PROTOCOL     *PciIo;\r
1497   UINT64                  Supports;\r
1498   UINT64                  OriginalPciAttributes;\r
1499   BOOLEAN                 PciAttributesSaved;\r
1500 \r
1501   //\r
1502   // Open the PciIo Protocol, then enable the USB host controller\r
1503   //\r
1504   Status = gBS->OpenProtocol (\r
1505                   Controller,\r
1506                   &gEfiPciIoProtocolGuid,\r
1507                   (VOID **) &PciIo,\r
1508                   This->DriverBindingHandle,\r
1509                   Controller,\r
1510                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
1511                   );\r
1512 \r
1513   if (EFI_ERROR (Status)) {\r
1514     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to open PCI_IO\n"));\r
1515     return EFI_DEVICE_ERROR;\r
1516   }\r
1517 \r
1518   PciAttributesSaved = FALSE;\r
1519   //\r
1520   // Save original PCI attributes\r
1521   //\r
1522   Status = PciIo->Attributes (\r
1523                     PciIo,\r
1524                     EfiPciIoAttributeOperationGet,\r
1525                     0,\r
1526                     &OriginalPciAttributes\r
1527                     );\r
1528 \r
1529   if (EFI_ERROR (Status)) {\r
1530     goto CLOSE_PCIIO;\r
1531   }\r
1532   PciAttributesSaved = TRUE;\r
1533 \r
1534   Status = PciIo->Attributes (\r
1535                     PciIo,\r
1536                     EfiPciIoAttributeOperationSupported,\r
1537                     0,\r
1538                     &Supports\r
1539                     );\r
1540   if (!EFI_ERROR (Status)) {\r
1541     Supports &= EFI_PCI_DEVICE_ENABLE;\r
1542     Status = PciIo->Attributes (\r
1543                       PciIo,\r
1544                       EfiPciIoAttributeOperationEnable,\r
1545                       Supports,\r
1546                       NULL\r
1547                       );\r
1548   }\r
1549 \r
1550   if (EFI_ERROR (Status)) {\r
1551     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));\r
1552     goto CLOSE_PCIIO;\r
1553   }\r
1554 \r
1555   //\r
1556   // Create then install USB2_HC_PROTOCOL\r
1557   //\r
1558   Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);\r
1559 \r
1560   if (Ehc == NULL) {\r
1561     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));\r
1562 \r
1563     Status = EFI_OUT_OF_RESOURCES;\r
1564     goto CLOSE_PCIIO;\r
1565   }\r
1566 \r
1567   Status = gBS->InstallProtocolInterface (\r
1568                   &Controller,\r
1569                   &gEfiUsb2HcProtocolGuid,\r
1570                   EFI_NATIVE_INTERFACE,\r
1571                   &Ehc->Usb2Hc\r
1572                   );\r
1573 \r
1574   if (EFI_ERROR (Status)) {\r
1575     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
1576     goto FREE_POOL;\r
1577   }\r
1578 \r
1579   //\r
1580   // Robustnesss improvement such as for UoL\r
1581   // Default is not required.\r
1582   //\r
1583   if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
1584     EhcClearLegacySupport (Ehc);\r
1585   }\r
1586   EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
1587 \r
1588   Status = EhcInitHC (Ehc);\r
1589 \r
1590   if (EFI_ERROR (Status)) {\r
1591     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));\r
1592     goto UNINSTALL_USBHC;\r
1593   }\r
1594 \r
1595   //\r
1596   // Start the asynchronous interrupt monitor\r
1597   //\r
1598   Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);\r
1599 \r
1600   if (EFI_ERROR (Status)) {\r
1601     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
1602 \r
1603     EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1604     goto UNINSTALL_USBHC;\r
1605   }\r
1606 \r
1607   //\r
1608   // Install the component name protocol, don't fail the start\r
1609   // because of something for display.\r
1610   //\r
1611   AddUnicodeString2 (\r
1612     "eng",\r
1613     gEhciComponentName.SupportedLanguages,\r
1614     &Ehc->ControllerNameTable,\r
1615     L"Enhanced Host Controller (USB 2.0)",\r
1616     TRUE\r
1617     );\r
1618   AddUnicodeString2 (\r
1619     "en",\r
1620     gEhciComponentName2.SupportedLanguages,\r
1621     &Ehc->ControllerNameTable,\r
1622     L"Enhanced Host Controller (USB 2.0)",\r
1623     FALSE\r
1624     );\r
1625 \r
1626 \r
1627   DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
1628   return EFI_SUCCESS;\r
1629 \r
1630 UNINSTALL_USBHC:\r
1631   gBS->UninstallProtocolInterface (\r
1632          Controller,\r
1633          &gEfiUsb2HcProtocolGuid,\r
1634          &Ehc->Usb2Hc\r
1635          );\r
1636 \r
1637 FREE_POOL:\r
1638   EhcFreeSched (Ehc);\r
1639   gBS->CloseEvent (Ehc->PollTimer);\r
1640   gBS->FreePool (Ehc);\r
1641 \r
1642 CLOSE_PCIIO:\r
1643   if (PciAttributesSaved == TRUE) {\r
1644     //\r
1645     // Restore original PCI attributes\r
1646     //\r
1647     PciIo->Attributes (\r
1648                     PciIo,\r
1649                     EfiPciIoAttributeOperationSet,\r
1650                     OriginalPciAttributes,\r
1651                     NULL\r
1652                     );\r
1653   }\r
1654 \r
1655   gBS->CloseProtocol (\r
1656          Controller,\r
1657          &gEfiPciIoProtocolGuid,\r
1658          This->DriverBindingHandle,\r
1659          Controller\r
1660          );\r
1661 \r
1662   return Status;\r
1663 }\r
1664 \r
1665 \r
1666 /**\r
1667   Stop this driver on ControllerHandle. Support stoping any child handles\r
1668   created by this driver.\r
1669 \r
1670   @param  This                 Protocol instance pointer.\r
1671   @param  Controller           Handle of device to stop driver on\r
1672   @param  NumberOfChildren     Number of Children in the ChildHandleBuffer\r
1673   @param  ChildHandleBuffer    List of handles for the children we need to stop.\r
1674 \r
1675   @return EFI_SUCCESS         Success\r
1676   @return EFI_DEVICE_ERROR    Fail\r
1677 \r
1678 **/\r
1679 EFI_STATUS\r
1680 EFIAPI\r
1681 EhcDriverBindingStop (\r
1682   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1683   IN EFI_HANDLE                  Controller,\r
1684   IN UINTN                       NumberOfChildren,\r
1685   IN EFI_HANDLE                  *ChildHandleBuffer\r
1686   )\r
1687 {\r
1688   EFI_STATUS            Status;\r
1689   EFI_USB2_HC_PROTOCOL  *Usb2Hc;\r
1690   EFI_PCI_IO_PROTOCOL   *PciIo;\r
1691   USB2_HC_DEV           *Ehc;\r
1692 \r
1693   //\r
1694   // Test whether the Controller handler passed in is a valid\r
1695   // Usb controller handle that should be supported, if not,\r
1696   // return the error status directly\r
1697   //\r
1698   Status = gBS->OpenProtocol (\r
1699                   Controller,\r
1700                   &gEfiUsb2HcProtocolGuid,\r
1701                   (VOID **) &Usb2Hc,\r
1702                   This->DriverBindingHandle,\r
1703                   Controller,\r
1704                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1705                   );\r
1706 \r
1707   if (EFI_ERROR (Status)) {\r
1708     return Status;\r
1709   }\r
1710 \r
1711   Ehc   = EHC_FROM_THIS (Usb2Hc);\r
1712   PciIo = Ehc->PciIo;\r
1713 \r
1714   //\r
1715   // Stop AsyncRequest Polling timer then stop the EHCI driver\r
1716   // and uninstall the EHCI protocl.\r
1717   //\r
1718   gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
1719   EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1720 \r
1721   Status = gBS->UninstallProtocolInterface (\r
1722                   Controller,\r
1723                   &gEfiUsb2HcProtocolGuid,\r
1724                   Usb2Hc\r
1725                   );\r
1726 \r
1727   if (EFI_ERROR (Status)) {\r
1728     return Status;\r
1729   }\r
1730 \r
1731   if (Ehc->PollTimer != NULL) {\r
1732     gBS->CloseEvent (Ehc->PollTimer);\r
1733   }\r
1734 \r
1735   EhcFreeSched (Ehc);\r
1736 \r
1737   if (Ehc->ControllerNameTable) {\r
1738     FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
1739   }\r
1740 \r
1741   //\r
1742   // Restore original PCI attributes\r
1743   //\r
1744   PciIo->Attributes (\r
1745                   PciIo,\r
1746                   EfiPciIoAttributeOperationSet,\r
1747                   Ehc->OriginalPciAttributes,\r
1748                   NULL\r
1749                   );\r
1750 \r
1751   gBS->CloseProtocol (\r
1752          Controller,\r
1753          &gEfiPciIoProtocolGuid,\r
1754          This->DriverBindingHandle,\r
1755          Controller\r
1756          );\r
1757 \r
1758   FreePool (Ehc);\r
1759 \r
1760   return EFI_SUCCESS;\r
1761 }\r
1762 \r
1763 EFI_DRIVER_BINDING_PROTOCOL\r
1764 gEhciDriverBinding = {\r
1765   EhcDriverBindingSupported,\r
1766   EhcDriverBindingStart,\r
1767   EhcDriverBindingStop,\r
1768   0x10,\r
1769   NULL,\r
1770   NULL\r
1771 };\r