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