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