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