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