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