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