]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
fixed DMA not be stopped issue when gBS->ExitBootServices called.
[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
597f4ee2 5Copyright (c) 2006 - 2009, 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
597f4ee2 1439 EhcMonitorAsyncRequests,\r
913cb9dc 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
0428a6cb 1452/**\r
1453 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1454\r
1455 @param Event Pointer to this event\r
1456 @param Context Event hanlder private data\r
1457\r
1458**/\r
1459VOID\r
1460EFIAPI\r
1461EhcExitBootService (\r
1462 EFI_EVENT Event,\r
1463 VOID *Context\r
1464 )\r
1465\r
1466{\r
1467 USB2_HC_DEV *Ehc;\r
1468\r
1469 Ehc = (USB2_HC_DEV *) Context;\r
1470\r
1471 //\r
1472 // Stop the Host Controller\r
1473 //\r
1474 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1475\r
1476 return;\r
1477}\r
1478\r
913cb9dc 1479\r
1480/**\r
78c2ffb5 1481 Starting the Usb EHCI Driver.\r
913cb9dc 1482\r
1483 @param This Protocol instance pointer.\r
78c2ffb5 1484 @param Controller Handle of device to test.\r
1485 @param RemainingDevicePath Not used.\r
913cb9dc 1486\r
78c2ffb5 1487 @return EFI_SUCCESS supports this device.\r
1488 @return EFI_UNSUPPORTED do not support this device.\r
1489 @return EFI_DEVICE_ERROR cannot be started due to device Error.\r
1490 @return EFI_OUT_OF_RESOURCES cannot allocate resources.\r
913cb9dc 1491\r
1492**/\r
1493EFI_STATUS\r
1494EFIAPI\r
1495EhcDriverBindingStart (\r
1496 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1497 IN EFI_HANDLE Controller,\r
1498 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1499 )\r
1500{\r
1501 EFI_STATUS Status;\r
1502 USB2_HC_DEV *Ehc;\r
1503 EFI_PCI_IO_PROTOCOL *PciIo;\r
96f6af14 1504 UINT64 Supports;\r
68246fa8 1505 UINT64 OriginalPciAttributes;\r
6a6d955c 1506 BOOLEAN PciAttributesSaved;\r
913cb9dc 1507\r
1508 //\r
1509 // Open the PciIo Protocol, then enable the USB host controller\r
1510 //\r
1511 Status = gBS->OpenProtocol (\r
1512 Controller,\r
1513 &gEfiPciIoProtocolGuid,\r
c52fa98c 1514 (VOID **) &PciIo,\r
913cb9dc 1515 This->DriverBindingHandle,\r
1516 Controller,\r
1517 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1518 );\r
1519\r
1520 if (EFI_ERROR (Status)) {\r
1c619535 1521 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to open PCI_IO\n"));\r
913cb9dc 1522 return EFI_DEVICE_ERROR;\r
1523 }\r
1524\r
6a6d955c 1525 PciAttributesSaved = FALSE;\r
68246fa8 1526 //\r
1527 // Save original PCI attributes\r
1528 //\r
1529 Status = PciIo->Attributes (\r
1530 PciIo,\r
1531 EfiPciIoAttributeOperationGet,\r
1532 0,\r
1533 &OriginalPciAttributes\r
1534 );\r
1535\r
1536 if (EFI_ERROR (Status)) {\r
6a6d955c 1537 goto CLOSE_PCIIO;\r
68246fa8 1538 }\r
6a6d955c 1539 PciAttributesSaved = TRUE;\r
68246fa8 1540\r
913cb9dc 1541 Status = PciIo->Attributes (\r
1542 PciIo,\r
96f6af14
LG
1543 EfiPciIoAttributeOperationSupported,\r
1544 0,\r
1545 &Supports\r
913cb9dc 1546 );\r
96f6af14
LG
1547 if (!EFI_ERROR (Status)) {\r
1548 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1549 Status = PciIo->Attributes (\r
1550 PciIo,\r
1551 EfiPciIoAttributeOperationEnable,\r
1552 Supports,\r
1553 NULL\r
1554 );\r
1555 }\r
913cb9dc 1556\r
1557 if (EFI_ERROR (Status)) {\r
1c619535 1558 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));\r
913cb9dc 1559 goto CLOSE_PCIIO;\r
1560 }\r
1561\r
1562 //\r
1563 // Create then install USB2_HC_PROTOCOL\r
1564 //\r
68246fa8 1565 Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);\r
913cb9dc 1566\r
1567 if (Ehc == NULL) {\r
1c619535 1568 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));\r
913cb9dc 1569\r
1570 Status = EFI_OUT_OF_RESOURCES;\r
1571 goto CLOSE_PCIIO;\r
1572 }\r
1573\r
1574 Status = gBS->InstallProtocolInterface (\r
1575 &Controller,\r
1576 &gEfiUsb2HcProtocolGuid,\r
1577 EFI_NATIVE_INTERFACE,\r
1578 &Ehc->Usb2Hc\r
1579 );\r
1580\r
1581 if (EFI_ERROR (Status)) {\r
1c619535 1582 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
913cb9dc 1583 goto FREE_POOL;\r
1584 }\r
1585\r
1586 //\r
1587 // Robustnesss improvement such as for UoL\r
f0a83bb3 1588 // Default is not required.\r
913cb9dc 1589 //\r
cc582cff 1590 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
dd4047a5 1591 EhcClearLegacySupport (Ehc);\r
1592 }\r
41e8ff27 1593 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
913cb9dc 1594\r
1595 Status = EhcInitHC (Ehc);\r
1596\r
1597 if (EFI_ERROR (Status)) {\r
1c619535 1598 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));\r
913cb9dc 1599 goto UNINSTALL_USBHC;\r
1600 }\r
1601\r
1602 //\r
1603 // Start the asynchronous interrupt monitor\r
1604 //\r
41e8ff27 1605 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);\r
913cb9dc 1606\r
1607 if (EFI_ERROR (Status)) {\r
1c619535 1608 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
913cb9dc 1609\r
41e8ff27 1610 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
913cb9dc 1611 goto UNINSTALL_USBHC;\r
1612 }\r
1613\r
0428a6cb 1614 //\r
1615 // Create event to stop the HC when exit boot service.\r
1616 //\r
1617 Status = gBS->CreateEventEx (\r
1618 EVT_NOTIFY_SIGNAL,\r
1619 TPL_NOTIFY,\r
1620 EhcExitBootService,\r
1621 Ehc,\r
1622 &gEfiEventExitBootServicesGuid,\r
1623 &Ehc->ExitBootServiceEvent\r
1624 );\r
1625 if (EFI_ERROR (Status)) {\r
1626 goto UNINSTALL_USBHC;\r
1627 }\r
1628\r
913cb9dc 1629 //\r
1630 // Install the component name protocol, don't fail the start\r
1631 // because of something for display.\r
1632 //\r
f527bce3 1633 AddUnicodeString2 (\r
913cb9dc 1634 "eng",\r
1635 gEhciComponentName.SupportedLanguages,\r
1636 &Ehc->ControllerNameTable,\r
f527bce3 1637 L"Enhanced Host Controller (USB 2.0)",\r
1638 TRUE\r
913cb9dc 1639 );\r
f527bce3 1640 AddUnicodeString2 (\r
1641 "en",\r
1642 gEhciComponentName2.SupportedLanguages,\r
1643 &Ehc->ControllerNameTable,\r
1644 L"Enhanced Host Controller (USB 2.0)",\r
1645 FALSE\r
1646 );\r
1647\r
913cb9dc 1648\r
0e549d5b 1649 DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));\r
913cb9dc 1650 return EFI_SUCCESS;\r
1651\r
1652UNINSTALL_USBHC:\r
1653 gBS->UninstallProtocolInterface (\r
1654 Controller,\r
1655 &gEfiUsb2HcProtocolGuid,\r
1656 &Ehc->Usb2Hc\r
1657 );\r
1658\r
1659FREE_POOL:\r
1660 EhcFreeSched (Ehc);\r
1661 gBS->CloseEvent (Ehc->PollTimer);\r
1662 gBS->FreePool (Ehc);\r
1663\r
1664CLOSE_PCIIO:\r
a92d4e8a 1665 if (PciAttributesSaved) {\r
6a6d955c 1666 //\r
1667 // Restore original PCI attributes\r
1668 //\r
1669 PciIo->Attributes (\r
1670 PciIo,\r
1671 EfiPciIoAttributeOperationSet,\r
1672 OriginalPciAttributes,\r
1673 NULL\r
1674 );\r
1675 }\r
68246fa8 1676\r
913cb9dc 1677 gBS->CloseProtocol (\r
1678 Controller,\r
1679 &gEfiPciIoProtocolGuid,\r
1680 This->DriverBindingHandle,\r
1681 Controller\r
1682 );\r
1683\r
1684 return Status;\r
1685}\r
1686\r
1687\r
1688/**\r
1689 Stop this driver on ControllerHandle. Support stoping any child handles\r
1690 created by this driver.\r
1691\r
1692 @param This Protocol instance pointer.\r
78c2ffb5 1693 @param Controller Handle of device to stop driver on.\r
1694 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
913cb9dc 1695 @param ChildHandleBuffer List of handles for the children we need to stop.\r
1696\r
78c2ffb5 1697 @return EFI_SUCCESS Success.\r
1698 @return EFI_DEVICE_ERROR Fail.\r
913cb9dc 1699\r
1700**/\r
1701EFI_STATUS\r
1702EFIAPI\r
1703EhcDriverBindingStop (\r
1704 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1705 IN EFI_HANDLE Controller,\r
1706 IN UINTN NumberOfChildren,\r
1707 IN EFI_HANDLE *ChildHandleBuffer\r
1708 )\r
1709{\r
1710 EFI_STATUS Status;\r
1711 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1712 EFI_PCI_IO_PROTOCOL *PciIo;\r
1713 USB2_HC_DEV *Ehc;\r
1714\r
1715 //\r
1716 // Test whether the Controller handler passed in is a valid\r
1717 // Usb controller handle that should be supported, if not,\r
1718 // return the error status directly\r
1719 //\r
1720 Status = gBS->OpenProtocol (\r
1721 Controller,\r
1722 &gEfiUsb2HcProtocolGuid,\r
c52fa98c 1723 (VOID **) &Usb2Hc,\r
913cb9dc 1724 This->DriverBindingHandle,\r
1725 Controller,\r
1726 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1727 );\r
1728\r
1729 if (EFI_ERROR (Status)) {\r
1730 return Status;\r
1731 }\r
1732\r
1733 Ehc = EHC_FROM_THIS (Usb2Hc);\r
1734 PciIo = Ehc->PciIo;\r
1735\r
1736 //\r
1737 // Stop AsyncRequest Polling timer then stop the EHCI driver\r
1738 // and uninstall the EHCI protocl.\r
1739 //\r
41e8ff27 1740 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
1741 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
913cb9dc 1742\r
1743 Status = gBS->UninstallProtocolInterface (\r
1744 Controller,\r
1745 &gEfiUsb2HcProtocolGuid,\r
1746 Usb2Hc\r
1747 );\r
1748\r
1749 if (EFI_ERROR (Status)) {\r
1750 return Status;\r
1751 }\r
1752\r
1753 if (Ehc->PollTimer != NULL) {\r
1754 gBS->CloseEvent (Ehc->PollTimer);\r
1755 }\r
1756\r
0428a6cb 1757 if (Ehc->ExitBootServiceEvent != NULL) {\r
1758 gBS->CloseEvent (Ehc->ExitBootServiceEvent);\r
1759 }\r
1760\r
913cb9dc 1761 EhcFreeSched (Ehc);\r
1762\r
78c2ffb5 1763 if (Ehc->ControllerNameTable != NULL) {\r
913cb9dc 1764 FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
1765 }\r
1766\r
1767 //\r
68246fa8 1768 // Restore original PCI attributes\r
913cb9dc 1769 //\r
68246fa8 1770 PciIo->Attributes (\r
1771 PciIo,\r
1772 EfiPciIoAttributeOperationSet,\r
1773 Ehc->OriginalPciAttributes,\r
1774 NULL\r
1775 );\r
913cb9dc 1776\r
1777 gBS->CloseProtocol (\r
1778 Controller,\r
1779 &gEfiPciIoProtocolGuid,\r
1780 This->DriverBindingHandle,\r
1781 Controller\r
1782 );\r
1783\r
68246fa8 1784 FreePool (Ehc);\r
1785\r
96f6af14 1786 return EFI_SUCCESS;\r
913cb9dc 1787}\r
1788\r