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