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