]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
Move SmmCoreSmmServicesTableLib from MdePkg to MdeModulePkg.
[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
1ccdbf2a 13Copyright (c) 2006 - 2010, Intel Corporation\r
913cb9dc 14All rights reserved. This program and the accompanying materials\r
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
194 IN CONST EFI_USB2_HC_PROTOCOL *This,\r
195 OUT EFI_USB_HC_STATE *State\r
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
313 IN CONST EFI_USB2_HC_PROTOCOL *This,\r
314 IN CONST UINT8 PortNumber,\r
315 OUT EFI_USB_PORT_STATUS *PortStatus\r
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
472 // Not supported, ignore the operation\r
473 //\r
474 Status = EFI_SUCCESS;\r
475 break;\r
476\r
477 case EfiUsbPortOwner:\r
478 State |= PORTSC_OWNER;\r
479 EhcWriteOpReg (Ehc, Offset, State);\r
480 break;\r
481\r
482 default:\r
483 Status = EFI_INVALID_PARAMETER;\r
484 }\r
485\r
486ON_EXIT:\r
1c619535 487 DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));\r
913cb9dc 488\r
489 gBS->RestoreTPL (OldTpl);\r
490 return Status;\r
491}\r
492\r
493\r
494/**\r
495 Clears a feature for the specified root hub port.\r
496\r
78c2ffb5 497 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
498 @param PortNumber Specifies the root hub port whose feature is\r
499 requested to be cleared.\r
500 @param PortFeature Indicates the feature selector associated with the\r
501 feature clear request.\r
913cb9dc 502\r
78c2ffb5 503 @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
504 for the USB root hub port specified by PortNumber.\r
505 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
506 @retval EFI_DEVICE_ERROR Can't read register.\r
913cb9dc 507\r
508**/\r
913cb9dc 509EFI_STATUS\r
510EFIAPI\r
511EhcClearRootHubPortFeature (\r
512 IN EFI_USB2_HC_PROTOCOL *This,\r
513 IN UINT8 PortNumber,\r
514 IN EFI_USB_PORT_FEATURE PortFeature\r
515 )\r
516{\r
517 USB2_HC_DEV *Ehc;\r
518 EFI_TPL OldTpl;\r
519 UINT32 Offset;\r
520 UINT32 State;\r
521 UINT32 TotalPort;\r
522 EFI_STATUS Status;\r
523\r
524 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
525 Ehc = EHC_FROM_THIS (This);\r
526 Status = EFI_SUCCESS;\r
527\r
528 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
529\r
530 if (PortNumber >= TotalPort) {\r
531 Status = EFI_INVALID_PARAMETER;\r
532 goto ON_EXIT;\r
533 }\r
534\r
535 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
536 State = EhcReadOpReg (Ehc, Offset);\r
537 State &= ~PORTSC_CHANGE_MASK;\r
538\r
539 switch (PortFeature) {\r
540 case EfiUsbPortEnable:\r
541 //\r
542 // Clear PORT_ENABLE feature means disable port.\r
543 //\r
544 State &= ~PORTSC_ENABLED;\r
545 EhcWriteOpReg (Ehc, Offset, State);\r
546 break;\r
547\r
548 case EfiUsbPortSuspend:\r
549 //\r
550 // A write of zero to this bit is ignored by the host\r
551 // controller. The host controller will unconditionally\r
552 // set this bit to a zero when:\r
553 // 1. software sets the Forct Port Resume bit to a zero from a one.\r
554 // 2. software sets the Port Reset bit to a one frome a zero.\r
555 //\r
556 State &= ~PORSTSC_RESUME;\r
557 EhcWriteOpReg (Ehc, Offset, State);\r
558 break;\r
559\r
560 case EfiUsbPortReset:\r
561 //\r
562 // Clear PORT_RESET means clear the reset signal.\r
563 //\r
564 State &= ~PORTSC_RESET;\r
565 EhcWriteOpReg (Ehc, Offset, State);\r
566 break;\r
567\r
568 case EfiUsbPortOwner:\r
569 //\r
570 // Clear port owner means this port owned by EHC\r
571 //\r
572 State &= ~PORTSC_OWNER;\r
573 EhcWriteOpReg (Ehc, Offset, State);\r
574 break;\r
575\r
576 case EfiUsbPortConnectChange:\r
577 //\r
578 // Clear connect status change\r
579 //\r
580 State |= PORTSC_CONN_CHANGE;\r
581 EhcWriteOpReg (Ehc, Offset, State);\r
582 break;\r
583\r
584 case EfiUsbPortEnableChange:\r
585 //\r
586 // Clear enable status change\r
587 //\r
588 State |= PORTSC_ENABLE_CHANGE;\r
589 EhcWriteOpReg (Ehc, Offset, State);\r
590 break;\r
591\r
592 case EfiUsbPortOverCurrentChange:\r
593 //\r
594 // Clear PortOverCurrent change\r
595 //\r
596 State |= PORTSC_OVERCUR_CHANGE;\r
597 EhcWriteOpReg (Ehc, Offset, State);\r
598 break;\r
599\r
600 case EfiUsbPortPower:\r
601 case EfiUsbPortSuspendChange:\r
602 case EfiUsbPortResetChange:\r
603 //\r
604 // Not supported or not related operation\r
605 //\r
606 break;\r
607\r
608 default:\r
609 Status = EFI_INVALID_PARAMETER;\r
610 break;\r
611 }\r
612\r
613ON_EXIT:\r
1c619535 614 DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));\r
913cb9dc 615 gBS->RestoreTPL (OldTpl);\r
616 return Status;\r
617}\r
618\r
619\r
620/**\r
621 Submits control transfer to a target USB device.\r
622\r
78c2ffb5 623 @param This This EFI_USB2_HC_PROTOCOL instance.\r
624 @param DeviceAddress The target device address.\r
625 @param DeviceSpeed Target device speed.\r
626 @param MaximumPacketLength Maximum packet size the default control transfer\r
627 endpoint is capable of sending or receiving.\r
628 @param Request USB device request to send.\r
629 @param TransferDirection Specifies the data direction for the data stage\r
630 @param Data Data buffer to be transmitted or received from USB\r
631 device.\r
632 @param DataLength The size (in bytes) of the data buffer.\r
633 @param TimeOut Indicates the maximum timeout, in millisecond.\r
634 @param Translator Transaction translator to be used by this device.\r
635 @param TransferResult Return the result of this control transfer.\r
636\r
637 @retval EFI_SUCCESS Transfer was completed successfully.\r
638 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
639 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
640 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
641 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
913cb9dc 642\r
643**/\r
913cb9dc 644EFI_STATUS\r
645EFIAPI\r
646EhcControlTransfer (\r
647 IN EFI_USB2_HC_PROTOCOL *This,\r
648 IN UINT8 DeviceAddress,\r
649 IN UINT8 DeviceSpeed,\r
650 IN UINTN MaximumPacketLength,\r
651 IN EFI_USB_DEVICE_REQUEST *Request,\r
652 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
653 IN OUT VOID *Data,\r
654 IN OUT UINTN *DataLength,\r
655 IN UINTN TimeOut,\r
656 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
657 OUT UINT32 *TransferResult\r
658 )\r
659{\r
660 USB2_HC_DEV *Ehc;\r
661 URB *Urb;\r
662 EFI_TPL OldTpl;\r
663 UINT8 Endpoint;\r
664 EFI_STATUS Status;\r
665\r
666 //\r
667 // Validate parameters\r
668 //\r
669 if ((Request == NULL) || (TransferResult == NULL)) {\r
670 return EFI_INVALID_PARAMETER;\r
671 }\r
672\r
673 if ((TransferDirection != EfiUsbDataIn) &&\r
674 (TransferDirection != EfiUsbDataOut) &&\r
675 (TransferDirection != EfiUsbNoData)) {\r
676 return EFI_INVALID_PARAMETER;\r
677 }\r
678\r
679 if ((TransferDirection == EfiUsbNoData) &&\r
680 ((Data != NULL) || (*DataLength != 0))) {\r
681 return EFI_INVALID_PARAMETER;\r
682 }\r
683\r
684 if ((TransferDirection != EfiUsbNoData) &&\r
685 ((Data == NULL) || (*DataLength == 0))) {\r
686 return EFI_INVALID_PARAMETER;\r
687 }\r
688\r
689 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
690 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
691 return EFI_INVALID_PARAMETER;\r
692 }\r
693\r
694 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
695 return EFI_INVALID_PARAMETER;\r
696 }\r
697\r
698 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
699 Ehc = EHC_FROM_THIS (This);\r
700\r
701 Status = EFI_DEVICE_ERROR;\r
702 *TransferResult = EFI_USB_ERR_SYSTEM;\r
703\r
704 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1c619535 705 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n"));\r
913cb9dc 706\r
707 EhcAckAllInterrupt (Ehc);\r
708 goto ON_EXIT;\r
709 }\r
710\r
711 EhcAckAllInterrupt (Ehc);\r
712\r
713 //\r
714 // Create a new URB, insert it into the asynchronous\r
715 // schedule list, then poll the execution status.\r
716 //\r
717 //\r
718 // Encode the direction in address, although default control\r
719 // endpoint is bidirectional. EhcCreateUrb expects this\r
720 // combination of Ep addr and its direction.\r
721 //\r
c52fa98c 722 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
913cb9dc 723 Urb = EhcCreateUrb (\r
724 Ehc,\r
725 DeviceAddress,\r
726 Endpoint,\r
727 DeviceSpeed,\r
728 0,\r
729 MaximumPacketLength,\r
730 Translator,\r
731 EHC_CTRL_TRANSFER,\r
732 Request,\r
733 Data,\r
734 *DataLength,\r
735 NULL,\r
736 NULL,\r
737 1\r
738 );\r
739\r
740 if (Urb == NULL) {\r
1c619535 741 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB"));\r
913cb9dc 742\r
743 Status = EFI_OUT_OF_RESOURCES;\r
744 goto ON_EXIT;\r
745 }\r
746\r
747 EhcLinkQhToAsync (Ehc, Urb->Qh);\r
748 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
749 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
750\r
751 //\r
752 // Get the status from URB. The result is updated in EhcCheckUrbResult\r
753 // which is called by EhcExecTransfer\r
754 //\r
755 *TransferResult = Urb->Result;\r
756 *DataLength = Urb->Completed;\r
757\r
758 if (*TransferResult == EFI_USB_NOERROR) {\r
759 Status = EFI_SUCCESS;\r
760 }\r
761\r
762 EhcAckAllInterrupt (Ehc);\r
763 EhcFreeUrb (Ehc, Urb);\r
764\r
765ON_EXIT:\r
766 Ehc->PciIo->Flush (Ehc->PciIo);\r
767 gBS->RestoreTPL (OldTpl);\r
768\r
769 if (EFI_ERROR (Status)) {\r
1c619535 770 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
913cb9dc 771 }\r
772\r
773 return Status;\r
774}\r
775\r
776\r
777/**\r
778 Submits bulk transfer to a bulk endpoint of a USB device.\r
779\r
78c2ffb5 780 @param This This EFI_USB2_HC_PROTOCOL instance.\r
781 @param DeviceAddress Target device address.\r
782 @param EndPointAddress Endpoint number and its direction in bit 7.\r
783 @param DeviceSpeed Device speed, Low speed device doesn't support bulk\r
784 transfer.\r
785 @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
786 sending or receiving.\r
787 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
788 @param Data Array of pointers to the buffers of data to transmit\r
913cb9dc 789 from or receive into.\r
78c2ffb5 790 @param DataLength The lenght of the data buffer.\r
791 @param DataToggle On input, the initial data toggle for the transfer;\r
792 On output, it is updated to to next data toggle to\r
793 use of the subsequent bulk transfer.\r
794 @param TimeOut Indicates the maximum time, in millisecond, which\r
795 the transfer is allowed to complete.\r
796 @param Translator A pointr to the transaction translator data.\r
797 @param TransferResult A pointer to the detailed result information of the\r
798 bulk transfer.\r
799\r
800 @retval EFI_SUCCESS The transfer was completed successfully.\r
801 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
802 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
803 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
804 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
913cb9dc 805\r
806**/\r
913cb9dc 807EFI_STATUS\r
808EFIAPI\r
809EhcBulkTransfer (\r
810 IN EFI_USB2_HC_PROTOCOL *This,\r
811 IN UINT8 DeviceAddress,\r
812 IN UINT8 EndPointAddress,\r
813 IN UINT8 DeviceSpeed,\r
814 IN UINTN MaximumPacketLength,\r
815 IN UINT8 DataBuffersNumber,\r
816 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
817 IN OUT UINTN *DataLength,\r
818 IN OUT UINT8 *DataToggle,\r
819 IN UINTN TimeOut,\r
820 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
821 OUT UINT32 *TransferResult\r
822 )\r
823{\r
824 USB2_HC_DEV *Ehc;\r
825 URB *Urb;\r
826 EFI_TPL OldTpl;\r
827 EFI_STATUS Status;\r
828\r
829 //\r
830 // Validate the parameters\r
831 //\r
832 if ((DataLength == NULL) || (*DataLength == 0) ||\r
833 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
834 return EFI_INVALID_PARAMETER;\r
835 }\r
836\r
837 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
838 return EFI_INVALID_PARAMETER;\r
839 }\r
840\r
841 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
842 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
843 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
844 return EFI_INVALID_PARAMETER;\r
845 }\r
846\r
847 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
848 Ehc = EHC_FROM_THIS (This);\r
849\r
850 *TransferResult = EFI_USB_ERR_SYSTEM;\r
851 Status = EFI_DEVICE_ERROR;\r
852\r
853 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1c619535 854 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n"));\r
913cb9dc 855\r
856 EhcAckAllInterrupt (Ehc);\r
857 goto ON_EXIT;\r
858 }\r
859\r
860 EhcAckAllInterrupt (Ehc);\r
861\r
862 //\r
863 // Create a new URB, insert it into the asynchronous\r
864 // schedule list, then poll the execution status.\r
865 //\r
866 Urb = EhcCreateUrb (\r
867 Ehc,\r
868 DeviceAddress,\r
869 EndPointAddress,\r
870 DeviceSpeed,\r
871 *DataToggle,\r
872 MaximumPacketLength,\r
873 Translator,\r
874 EHC_BULK_TRANSFER,\r
875 NULL,\r
876 Data[0],\r
877 *DataLength,\r
878 NULL,\r
879 NULL,\r
880 1\r
881 );\r
882\r
883 if (Urb == NULL) {\r
1c619535 884 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n"));\r
913cb9dc 885\r
886 Status = EFI_OUT_OF_RESOURCES;\r
887 goto ON_EXIT;\r
888 }\r
889\r
890 EhcLinkQhToAsync (Ehc, Urb->Qh);\r
891 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
892 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
893\r
894 *TransferResult = Urb->Result;\r
895 *DataLength = Urb->Completed;\r
896 *DataToggle = Urb->DataToggle;\r
897\r
898 if (*TransferResult == EFI_USB_NOERROR) {\r
899 Status = EFI_SUCCESS;\r
900 }\r
901\r
902 EhcAckAllInterrupt (Ehc);\r
903 EhcFreeUrb (Ehc, Urb);\r
904\r
905ON_EXIT:\r
906 Ehc->PciIo->Flush (Ehc->PciIo);\r
907 gBS->RestoreTPL (OldTpl);\r
908\r
909 if (EFI_ERROR (Status)) {\r
1c619535 910 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
913cb9dc 911 }\r
912\r
913 return Status;\r
914}\r
915\r
916\r
917/**\r
918 Submits an asynchronous interrupt transfer to an\r
919 interrupt endpoint of a USB device.\r
920\r
78c2ffb5 921 @param This This EFI_USB2_HC_PROTOCOL instance.\r
922 @param DeviceAddress Target device address.\r
923 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
924 @param DeviceSpeed Indicates device speed.\r
925 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
926 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
927 transfer If FALSE, to remove the specified\r
928 asynchronous interrupt.\r
929 @param DataToggle On input, the initial data toggle to use; on output,\r
930 it is updated to indicate the next data toggle.\r
931 @param PollingInterval The he interval, in milliseconds, that the transfer\r
932 is polled.\r
933 @param DataLength The length of data to receive at the rate specified\r
934 by PollingInterval.\r
935 @param Translator Transaction translator to use.\r
936 @param CallBackFunction Function to call at the rate specified by\r
937 PollingInterval.\r
938 @param Context Context to CallBackFunction.\r
939\r
940 @retval EFI_SUCCESS The request has been successfully submitted or canceled.\r
941 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
942 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.\r
943 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
913cb9dc 944\r
945**/\r
913cb9dc 946EFI_STATUS\r
947EFIAPI\r
948EhcAsyncInterruptTransfer (\r
949 IN EFI_USB2_HC_PROTOCOL * This,\r
950 IN UINT8 DeviceAddress,\r
951 IN UINT8 EndPointAddress,\r
952 IN UINT8 DeviceSpeed,\r
953 IN UINTN MaximumPacketLength,\r
954 IN BOOLEAN IsNewTransfer,\r
955 IN OUT UINT8 *DataToggle,\r
956 IN UINTN PollingInterval,\r
957 IN UINTN DataLength,\r
958 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,\r
959 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
960 IN VOID *Context OPTIONAL\r
961 )\r
962{\r
963 USB2_HC_DEV *Ehc;\r
964 URB *Urb;\r
965 EFI_TPL OldTpl;\r
966 EFI_STATUS Status;\r
967 UINT8 *Data;\r
968\r
969 //\r
970 // Validate parameters\r
971 //\r
592b87a4 972 if (!(EndPointAddress >= 0x01 && EndPointAddress <= 0x0F)\r
973 && !(EndPointAddress >= 0x81 && EndPointAddress <= 0x8F)) {\r
913cb9dc 974 return EFI_INVALID_PARAMETER;\r
975 }\r
976\r
977 if (IsNewTransfer) {\r
978 if (DataLength == 0) {\r
979 return EFI_INVALID_PARAMETER;\r
980 }\r
981\r
982 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
983 return EFI_INVALID_PARAMETER;\r
984 }\r
985\r
986 if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
987 return EFI_INVALID_PARAMETER;\r
988 }\r
989 }\r
990\r
991 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
992 Ehc = EHC_FROM_THIS (This);\r
993\r
994 //\r
995 // Delete Async interrupt transfer request. DataToggle will return\r
996 // the next data toggle to use.\r
997 //\r
998 if (!IsNewTransfer) {\r
999 Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
1000\r
1c619535 1001 DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
913cb9dc 1002 goto ON_EXIT;\r
1003 }\r
1004\r
1005 Status = EFI_SUCCESS;\r
1006\r
1007 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1c619535 1008 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));\r
913cb9dc 1009 EhcAckAllInterrupt (Ehc);\r
1010\r
1011 Status = EFI_DEVICE_ERROR;\r
1012 goto ON_EXIT;\r
1013 }\r
1014\r
1015 EhcAckAllInterrupt (Ehc);\r
1016\r
1017 Data = AllocatePool (DataLength);\r
1018\r
1019 if (Data == NULL) {\r
1c619535 1020 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
913cb9dc 1021\r
1022 Status = EFI_OUT_OF_RESOURCES;\r
1023 goto ON_EXIT;\r
1024 }\r
1025\r
1026 Urb = EhcCreateUrb (\r
1027 Ehc,\r
1028 DeviceAddress,\r
1029 EndPointAddress,\r
1030 DeviceSpeed,\r
1031 *DataToggle,\r
1032 MaximumPacketLength,\r
1033 Translator,\r
1034 EHC_INT_TRANSFER_ASYNC,\r
1035 NULL,\r
1036 Data,\r
1037 DataLength,\r
1038 CallBackFunction,\r
1039 Context,\r
1040 PollingInterval\r
1041 );\r
1042\r
1043 if (Urb == NULL) {\r
1c619535 1044 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to create URB\n"));\r
913cb9dc 1045\r
1046 gBS->FreePool (Data);\r
1047 Status = EFI_OUT_OF_RESOURCES;\r
1048 goto ON_EXIT;\r
1049 }\r
1050\r
1051 //\r
1052 // New asynchronous transfer must inserted to the head.\r
1053 // Check the comments in EhcMoniteAsyncRequests\r
1054 //\r
1055 EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1056 InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
1057\r
1058ON_EXIT:\r
1059 Ehc->PciIo->Flush (Ehc->PciIo);\r
1060 gBS->RestoreTPL (OldTpl);\r
1061\r
1062 return Status;\r
1063}\r
1064\r
1065\r
1066/**\r
1067 Submits synchronous interrupt transfer to an interrupt endpoint\r
1068 of a USB device.\r
1069\r
78c2ffb5 1070 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1071 @param DeviceAddress Target device address.\r
1072 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1073 @param DeviceSpeed Indicates device speed.\r
1074 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1075 of sending or receiving.\r
1076 @param Data Buffer of data that will be transmitted to USB\r
1077 device or received from USB device.\r
1078 @param DataLength On input, the size, in bytes, of the data buffer; On\r
1079 output, the number of bytes transferred.\r
1080 @param DataToggle On input, the initial data toggle to use; on output,\r
1081 it is updated to indicate the next data toggle.\r
1082 @param TimeOut Maximum time, in second, to complete.\r
1083 @param Translator Transaction translator to use.\r
1084 @param TransferResult Variable to receive the transfer result.\r
1085\r
1086 @return EFI_SUCCESS The transfer was completed successfully.\r
1087 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
1088 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
1089 @return EFI_TIMEOUT The transfer failed due to timeout.\r
1090 @return EFI_DEVICE_ERROR The failed due to host controller or device error\r
913cb9dc 1091\r
1092**/\r
913cb9dc 1093EFI_STATUS\r
1094EFIAPI\r
1095EhcSyncInterruptTransfer (\r
1096 IN EFI_USB2_HC_PROTOCOL *This,\r
1097 IN UINT8 DeviceAddress,\r
1098 IN UINT8 EndPointAddress,\r
1099 IN UINT8 DeviceSpeed,\r
1100 IN UINTN MaximumPacketLength,\r
1101 IN OUT VOID *Data,\r
1102 IN OUT UINTN *DataLength,\r
1103 IN OUT UINT8 *DataToggle,\r
1104 IN UINTN TimeOut,\r
1105 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1106 OUT UINT32 *TransferResult\r
1107 )\r
1108{\r
1109 USB2_HC_DEV *Ehc;\r
1110 EFI_TPL OldTpl;\r
1111 URB *Urb;\r
1112 EFI_STATUS Status;\r
1113\r
1114 //\r
1115 // Validates parameters\r
1116 //\r
1117 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1118 (Data == NULL) || (TransferResult == NULL)) {\r
1119 return EFI_INVALID_PARAMETER;\r
1120 }\r
1121\r
592b87a4 1122 if (!(EndPointAddress >= 0x01 && EndPointAddress <= 0x0F)\r
1123 && !(EndPointAddress >= 0x81 && EndPointAddress <= 0x8F)) {\r
913cb9dc 1124 return EFI_INVALID_PARAMETER;\r
1125 }\r
1126\r
1127 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1128 return EFI_INVALID_PARAMETER;\r
1129 }\r
1130\r
1131 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
1132 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1133 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
1134 return EFI_INVALID_PARAMETER;\r
1135 }\r
1136\r
1137 OldTpl = gBS->RaiseTPL (EHC_TPL);\r
1138 Ehc = EHC_FROM_THIS (This);\r
1139\r
1140 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1141 Status = EFI_DEVICE_ERROR;\r
1142\r
1143 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
1c619535 1144 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
913cb9dc 1145\r
1146 EhcAckAllInterrupt (Ehc);\r
1147 goto ON_EXIT;\r
1148 }\r
1149\r
1150 EhcAckAllInterrupt (Ehc);\r
1151\r
1152 Urb = EhcCreateUrb (\r
1153 Ehc,\r
1154 DeviceAddress,\r
1155 EndPointAddress,\r
1156 DeviceSpeed,\r
1157 *DataToggle,\r
1158 MaximumPacketLength,\r
1159 Translator,\r
1160 EHC_INT_TRANSFER_SYNC,\r
1161 NULL,\r
1162 Data,\r
1163 *DataLength,\r
1164 NULL,\r
1165 NULL,\r
1166 1\r
1167 );\r
1168\r
1169 if (Urb == NULL) {\r
1c619535 1170 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));\r
913cb9dc 1171\r
1172 Status = EFI_OUT_OF_RESOURCES;\r
1173 goto ON_EXIT;\r
1174 }\r
1175\r
1176 EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
1177 Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
1178 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
1179\r
1180 *TransferResult = Urb->Result;\r
1181 *DataLength = Urb->Completed;\r
1182 *DataToggle = Urb->DataToggle;\r
1183\r
1184 if (*TransferResult == EFI_USB_NOERROR) {\r
1185 Status = EFI_SUCCESS;\r
1186 }\r
1187\r
1188ON_EXIT:\r
1189 Ehc->PciIo->Flush (Ehc->PciIo);\r
1190 gBS->RestoreTPL (OldTpl);\r
1191\r
1192 if (EFI_ERROR (Status)) {\r
1c619535 1193 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
913cb9dc 1194 }\r
1195\r
1196 return Status;\r
1197}\r
1198\r
1199\r
1200/**\r
1201 Submits isochronous transfer to a target USB device.\r
1202\r
1203 @param This This EFI_USB2_HC_PROTOCOL instance.\r
78c2ffb5 1204 @param DeviceAddress Target device address.\r
1205 @param EndPointAddress End point address with its direction.\r
913cb9dc 1206 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1207 type.\r
1208 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1209 sending or receiving.\r
1210 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1211 @param Data Array of pointers to the buffers of data that will\r
1212 be transmitted to USB device or received from USB\r
1213 device.\r
78c2ffb5 1214 @param DataLength The size, in bytes, of the data buffer.\r
913cb9dc 1215 @param Translator Transaction translator to use.\r
78c2ffb5 1216 @param TransferResult Variable to receive the transfer result.\r
913cb9dc 1217\r
78c2ffb5 1218 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.\r
913cb9dc 1219\r
1220**/\r
913cb9dc 1221EFI_STATUS\r
1222EFIAPI\r
1223EhcIsochronousTransfer (\r
1224 IN EFI_USB2_HC_PROTOCOL *This,\r
1225 IN UINT8 DeviceAddress,\r
1226 IN UINT8 EndPointAddress,\r
1227 IN UINT8 DeviceSpeed,\r
1228 IN UINTN MaximumPacketLength,\r
1229 IN UINT8 DataBuffersNumber,\r
1230 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1231 IN UINTN DataLength,\r
1232 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1233 OUT UINT32 *TransferResult\r
1234 )\r
1235{\r
1236 return EFI_UNSUPPORTED;\r
1237}\r
1238\r
1239\r
1240/**\r
1241 Submits Async isochronous transfer to a target USB device.\r
1242\r
1243 @param This This EFI_USB2_HC_PROTOCOL instance.\r
78c2ffb5 1244 @param DeviceAddress Target device address.\r
1245 @param EndPointAddress End point address with its direction.\r
913cb9dc 1246 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1247 type.\r
1248 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1249 sending or receiving.\r
1250 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1251 @param Data Array of pointers to the buffers of data that will\r
1252 be transmitted to USB device or received from USB\r
1253 device.\r
78c2ffb5 1254 @param DataLength The size, in bytes, of the data buffer.\r
913cb9dc 1255 @param Translator Transaction translator to use.\r
78c2ffb5 1256 @param IsochronousCallBack Function to be called when the transfer complete.\r
913cb9dc 1257 @param Context Context passed to the call back function as\r
78c2ffb5 1258 parameter.\r
913cb9dc 1259\r
78c2ffb5 1260 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.\r
913cb9dc 1261\r
1262**/\r
913cb9dc 1263EFI_STATUS\r
1264EFIAPI\r
1265EhcAsyncIsochronousTransfer (\r
1266 IN EFI_USB2_HC_PROTOCOL *This,\r
1267 IN UINT8 DeviceAddress,\r
1268 IN UINT8 EndPointAddress,\r
1269 IN UINT8 DeviceSpeed,\r
1270 IN UINTN MaximumPacketLength,\r
1271 IN UINT8 DataBuffersNumber,\r
1272 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1273 IN UINTN DataLength,\r
1274 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1275 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1276 IN VOID *Context\r
1277 )\r
1278{\r
1279 return EFI_UNSUPPORTED;\r
1280}\r
1281\r
78c2ffb5 1282/**\r
1283 Entry point for EFI drivers.\r
1284\r
1285 @param ImageHandle EFI_HANDLE.\r
1286 @param SystemTable EFI_SYSTEM_TABLE.\r
1287\r
1288 @return EFI_SUCCESS Success.\r
1289 EFI_DEVICE_ERROR Fail.\r
1290\r
1291**/\r
913cb9dc 1292EFI_STATUS\r
1293EFIAPI\r
1294EhcDriverEntryPoint (\r
1295 IN EFI_HANDLE ImageHandle,\r
1296 IN EFI_SYSTEM_TABLE *SystemTable\r
1297 )\r
913cb9dc 1298{\r
f527bce3 1299 return EfiLibInstallDriverBindingComponentName2 (\r
913cb9dc 1300 ImageHandle,\r
1301 SystemTable,\r
1302 &gEhciDriverBinding,\r
1303 ImageHandle,\r
1304 &gEhciComponentName,\r
f527bce3 1305 &gEhciComponentName2\r
913cb9dc 1306 );\r
1307}\r
1308\r
1309\r
1310/**\r
1311 Test to see if this driver supports ControllerHandle. Any\r
1312 ControllerHandle that has Usb2HcProtocol installed will\r
1313 be supported.\r
1314\r
1315 @param This Protocol instance pointer.\r
78c2ffb5 1316 @param Controller Handle of device to test.\r
1317 @param RemainingDevicePath Not used.\r
913cb9dc 1318\r
78c2ffb5 1319 @return EFI_SUCCESS This driver supports this device.\r
1320 @return EFI_UNSUPPORTED This driver does not support this device.\r
913cb9dc 1321\r
1322**/\r
1323EFI_STATUS\r
1324EFIAPI\r
1325EhcDriverBindingSupported (\r
1326 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1327 IN EFI_HANDLE Controller,\r
1328 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1329 )\r
1330{\r
1331 EFI_STATUS Status;\r
1332 EFI_PCI_IO_PROTOCOL *PciIo;\r
1333 USB_CLASSC UsbClassCReg;\r
1334\r
1335 //\r
1336 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1337 //\r
1338 Status = gBS->OpenProtocol (\r
1339 Controller,\r
1340 &gEfiPciIoProtocolGuid,\r
c52fa98c 1341 (VOID **) &PciIo,\r
913cb9dc 1342 This->DriverBindingHandle,\r
1343 Controller,\r
1344 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1345 );\r
1346\r
1347 if (EFI_ERROR (Status)) {\r
1348 return EFI_UNSUPPORTED;\r
1349 }\r
1350\r
1351 Status = PciIo->Pci.Read (\r
1352 PciIo,\r
1353 EfiPciIoWidthUint8,\r
a261044c 1354 PCI_CLASSCODE_OFFSET,\r
913cb9dc 1355 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1356 &UsbClassCReg\r
1357 );\r
1358\r
1359 if (EFI_ERROR (Status)) {\r
1360 Status = EFI_UNSUPPORTED;\r
1361 goto ON_EXIT;\r
1362 }\r
1363\r
1364 //\r
1365 // Test whether the controller belongs to Ehci type\r
1366 //\r
cd92e3fb 1367 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)\r
1ccdbf2a 1368 || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface !=PCI_IF_UHCI))) {\r
913cb9dc 1369\r
1370 Status = EFI_UNSUPPORTED;\r
1371 }\r
1372\r
1373ON_EXIT:\r
1374 gBS->CloseProtocol (\r
1375 Controller,\r
1376 &gEfiPciIoProtocolGuid,\r
1377 This->DriverBindingHandle,\r
1378 Controller\r
1379 );\r
1380\r
1381 return Status;\r
1382}\r
1383\r
1384\r
1385/**\r
78c2ffb5 1386 Create and initialize a USB2_HC_DEV.\r
913cb9dc 1387\r
78c2ffb5 1388 @param PciIo The PciIo on this device.\r
1389 @param OriginalPciAttributes Original PCI attributes.\r
913cb9dc 1390\r
78c2ffb5 1391 @return The allocated and initialized USB2_HC_DEV structure if created,\r
1392 otherwise NULL.\r
913cb9dc 1393\r
1394**/\r
913cb9dc 1395USB2_HC_DEV *\r
1396EhcCreateUsb2Hc (\r
68246fa8 1397 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1398 IN UINT64 OriginalPciAttributes\r
913cb9dc 1399 )\r
1400{\r
1401 USB2_HC_DEV *Ehc;\r
1402 EFI_STATUS Status;\r
1403\r
1404 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
1405\r
1406 if (Ehc == NULL) {\r
1407 return NULL;\r
1408 }\r
1409\r
1410 //\r
1411 // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
1412 //\r
1413 Ehc->Signature = USB2_HC_DEV_SIGNATURE;\r
1414\r
1415 Ehc->Usb2Hc.GetCapability = EhcGetCapability;\r
1416 Ehc->Usb2Hc.Reset = EhcReset;\r
1417 Ehc->Usb2Hc.GetState = EhcGetState;\r
1418 Ehc->Usb2Hc.SetState = EhcSetState;\r
1419 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;\r
1420 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;\r
1421 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;\r
1422 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;\r
1423 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;\r
1424 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;\r
1425 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;\r
1426 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;\r
1427 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;\r
b4c24e2d 1428 Ehc->Usb2Hc.MajorRevision = 0x2;\r
1429 Ehc->Usb2Hc.MinorRevision = 0x0;\r
913cb9dc 1430\r
68246fa8 1431 Ehc->PciIo = PciIo;\r
1432 Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
913cb9dc 1433\r
1434 InitializeListHead (&Ehc->AsyncIntTransfers);\r
1435\r
1436 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);\r
1437 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
1438 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
1439\r
1c619535 1440 DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
913cb9dc 1441\r
1442 //\r
1443 // Create AsyncRequest Polling Timer\r
1444 //\r
1445 Status = gBS->CreateEvent (\r
1446 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1447 TPL_CALLBACK,\r
597f4ee2 1448 EhcMonitorAsyncRequests,\r
913cb9dc 1449 Ehc,\r
1450 &Ehc->PollTimer\r
1451 );\r
1452\r
1453 if (EFI_ERROR (Status)) {\r
1454 gBS->FreePool (Ehc);\r
1455 return NULL;\r
1456 }\r
1457\r
1458 return Ehc;\r
1459}\r
1460\r
0428a6cb 1461/**\r
1462 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1463\r
1464 @param Event Pointer to this event\r
1465 @param Context Event hanlder private data\r
1466\r
1467**/\r
1468VOID\r
1469EFIAPI\r
1470EhcExitBootService (\r
1471 EFI_EVENT Event,\r
1472 VOID *Context\r
1473 )\r
1474\r
1475{\r
1476 USB2_HC_DEV *Ehc;\r
1477\r
1478 Ehc = (USB2_HC_DEV *) Context;\r
1479\r
1480 //\r
1481 // Stop the Host Controller\r
1482 //\r
1483 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
1484\r
1485 return;\r
1486}\r
1487\r
913cb9dc 1488\r
1489/**\r
78c2ffb5 1490 Starting the Usb EHCI Driver.\r
913cb9dc 1491\r
1492 @param This Protocol instance pointer.\r
78c2ffb5 1493 @param Controller Handle of device to test.\r
1494 @param RemainingDevicePath Not used.\r
913cb9dc 1495\r
78c2ffb5 1496 @return EFI_SUCCESS supports this device.\r
1497 @return EFI_UNSUPPORTED do not support this device.\r
1498 @return EFI_DEVICE_ERROR cannot be started due to device Error.\r
1499 @return EFI_OUT_OF_RESOURCES cannot allocate resources.\r
913cb9dc 1500\r
1501**/\r
1502EFI_STATUS\r
1503EFIAPI\r
1504EhcDriverBindingStart (\r
1505 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1506 IN EFI_HANDLE Controller,\r
1507 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1508 )\r
1509{\r
1510 EFI_STATUS Status;\r
1511 USB2_HC_DEV *Ehc;\r
1512 EFI_PCI_IO_PROTOCOL *PciIo;\r
cd92e3fb 1513 EFI_PCI_IO_PROTOCOL *Instance;\r
96f6af14 1514 UINT64 Supports;\r
68246fa8 1515 UINT64 OriginalPciAttributes;\r
6a6d955c 1516 BOOLEAN PciAttributesSaved;\r
cd92e3fb 1517 USB_CLASSC UsbClassCReg;\r
1518 EFI_HANDLE *HandleBuffer;\r
1519 UINTN NumberOfHandles;\r
1520 UINTN Index;\r
1521 UINTN UhciSegmentNumber;\r
1522 UINTN UhciBusNumber;\r
1523 UINTN UhciDeviceNumber;\r
1524 UINTN UhciFunctionNumber;\r
1525 UINTN EhciSegmentNumber;\r
1526 UINTN EhciBusNumber;\r
1527 UINTN EhciDeviceNumber;\r
1528 UINTN EhciFunctionNumber;\r
913cb9dc 1529\r
1530 //\r
1531 // Open the PciIo Protocol, then enable the USB host controller\r
1532 //\r
1533 Status = gBS->OpenProtocol (\r
1534 Controller,\r
1535 &gEfiPciIoProtocolGuid,\r
c52fa98c 1536 (VOID **) &PciIo,\r
913cb9dc 1537 This->DriverBindingHandle,\r
1538 Controller,\r
1539 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1540 );\r
1541\r
1542 if (EFI_ERROR (Status)) {\r
cd92e3fb 1543 return Status;\r
913cb9dc 1544 }\r
1545\r
6a6d955c 1546 PciAttributesSaved = FALSE;\r
68246fa8 1547 //\r
1548 // Save original PCI attributes\r
1549 //\r
1550 Status = PciIo->Attributes (\r
1551 PciIo,\r
1552 EfiPciIoAttributeOperationGet,\r
1553 0,\r
1554 &OriginalPciAttributes\r
1555 );\r
1556\r
1557 if (EFI_ERROR (Status)) {\r
6a6d955c 1558 goto CLOSE_PCIIO;\r
68246fa8 1559 }\r
6a6d955c 1560 PciAttributesSaved = TRUE;\r
68246fa8 1561\r
913cb9dc 1562 Status = PciIo->Attributes (\r
1563 PciIo,\r
96f6af14
LG
1564 EfiPciIoAttributeOperationSupported,\r
1565 0,\r
1566 &Supports\r
913cb9dc 1567 );\r
96f6af14
LG
1568 if (!EFI_ERROR (Status)) {\r
1569 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1570 Status = PciIo->Attributes (\r
1571 PciIo,\r
1572 EfiPciIoAttributeOperationEnable,\r
1573 Supports,\r
1574 NULL\r
1575 );\r
1576 }\r
913cb9dc 1577\r
1578 if (EFI_ERROR (Status)) {\r
1c619535 1579 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));\r
913cb9dc 1580 goto CLOSE_PCIIO;\r
1581 }\r
1582\r
ba19956a 1583 //\r
1584 // Get the Pci device class code.\r
1585 //\r
cd92e3fb 1586 Status = PciIo->Pci.Read (\r
1587 PciIo,\r
1588 EfiPciIoWidthUint8,\r
a261044c 1589 PCI_CLASSCODE_OFFSET,\r
cd92e3fb 1590 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1591 &UsbClassCReg\r
1592 );\r
1593\r
1594 if (EFI_ERROR (Status)) {\r
1595 Status = EFI_UNSUPPORTED;\r
1596 goto CLOSE_PCIIO;\r
1597 }\r
ba19956a 1598 //\r
1599 // determine if the device is UHCI host controller or not. If yes, then find out the \r
1600 // companion usb ehci host controller and force EHCI driver get attached to it before\r
1601 // UHCI driver attaches to UHCI host controller.\r
1602 //\r
1ccdbf2a 1603 if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI) &&\r
cd92e3fb 1604 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && \r
1605 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {\r
1606 Status = PciIo->GetLocation (\r
1607 PciIo,\r
1608 &UhciSegmentNumber,\r
1609 &UhciBusNumber,\r
1610 &UhciDeviceNumber,\r
1611 &UhciFunctionNumber\r
1612 );\r
1613 if (EFI_ERROR (Status)) {\r
1614 goto CLOSE_PCIIO;\r
1615 }\r
1616\r
1617 Status = gBS->LocateHandleBuffer (\r
1618 ByProtocol,\r
1619 &gEfiPciIoProtocolGuid,\r
1620 NULL,\r
1621 &NumberOfHandles,\r
1622 &HandleBuffer\r
1623 );\r
1624 if (EFI_ERROR (Status)) {\r
1625 goto CLOSE_PCIIO;\r
1626 }\r
1627\r
1628 for (Index = 0; Index < NumberOfHandles; Index++) {\r
1629 //\r
1630 // Get the device path on this handle\r
1631 //\r
1632 Status = gBS->HandleProtocol (\r
1633 HandleBuffer[Index],\r
1634 &gEfiPciIoProtocolGuid,\r
1635 (VOID **)&Instance\r
1636 );\r
1637 ASSERT_EFI_ERROR (Status);\r
1638\r
1639 Status = Instance->Pci.Read (\r
1640 Instance,\r
1641 EfiPciIoWidthUint8,\r
a261044c 1642 PCI_CLASSCODE_OFFSET,\r
cd92e3fb 1643 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1644 &UsbClassCReg\r
1645 );\r
1646\r
1647 if (EFI_ERROR (Status)) {\r
1648 Status = EFI_UNSUPPORTED;\r
1649 goto CLOSE_PCIIO;\r
1650 }\r
1651\r
1ccdbf2a 1652 if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) &&\r
cd92e3fb 1653 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && \r
1654 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {\r
1655 Status = Instance->GetLocation (\r
1656 Instance,\r
1657 &EhciSegmentNumber,\r
1658 &EhciBusNumber,\r
1659 &EhciDeviceNumber,\r
1660 &EhciFunctionNumber\r
1661 );\r
1662 if (EFI_ERROR (Status)) {\r
1663 goto CLOSE_PCIIO;\r
1664 }\r
ba19956a 1665 //\r
1666 // Currently, the judgment on the companion usb host controller is through the\r
1667 // same bus number, which may vary on different platform.\r
1668 //\r
cd92e3fb 1669 if (EhciBusNumber == UhciBusNumber) {\r
1670 gBS->CloseProtocol (\r
1671 Controller,\r
1672 &gEfiPciIoProtocolGuid,\r
1673 This->DriverBindingHandle,\r
1674 Controller\r
1675 );\r
1676 EhcDriverBindingStart(This, HandleBuffer[Index], NULL);\r
1677 }\r
1678 }\r
1679 }\r
1680 Status = EFI_NOT_FOUND;\r
1681 goto CLOSE_PCIIO;\r
1682 }\r
1683\r
913cb9dc 1684 //\r
1685 // Create then install USB2_HC_PROTOCOL\r
1686 //\r
68246fa8 1687 Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);\r
913cb9dc 1688\r
1689 if (Ehc == NULL) {\r
1c619535 1690 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));\r
913cb9dc 1691\r
1692 Status = EFI_OUT_OF_RESOURCES;\r
1693 goto CLOSE_PCIIO;\r
1694 }\r
1695\r
1696 Status = gBS->InstallProtocolInterface (\r
1697 &Controller,\r
1698 &gEfiUsb2HcProtocolGuid,\r
1699 EFI_NATIVE_INTERFACE,\r
1700 &Ehc->Usb2Hc\r
1701 );\r
1702\r
1703 if (EFI_ERROR (Status)) {\r
1c619535 1704 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
913cb9dc 1705 goto FREE_POOL;\r
1706 }\r
1707\r
1708 //\r
c39c3e21 1709 // Robustnesss improvement such as for Duet platform\r
f0a83bb3 1710 // Default is not required.\r
913cb9dc 1711 //\r
cc582cff 1712 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
dd4047a5 1713 EhcClearLegacySupport (Ehc);\r
1714 }\r
41e8ff27 1715 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
913cb9dc 1716\r
1717 Status = EhcInitHC (Ehc);\r
1718\r
1719 if (EFI_ERROR (Status)) {\r
1c619535 1720 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));\r
913cb9dc 1721 goto UNINSTALL_USBHC;\r
1722 }\r
1723\r
1724 //\r
1725 // Start the asynchronous interrupt monitor\r
1726 //\r
41e8ff27 1727 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);\r
913cb9dc 1728\r
1729 if (EFI_ERROR (Status)) {\r
1c619535 1730 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
913cb9dc 1731\r
41e8ff27 1732 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
913cb9dc 1733 goto UNINSTALL_USBHC;\r
1734 }\r
1735\r
0428a6cb 1736 //\r
1737 // Create event to stop the HC when exit boot service.\r
1738 //\r
1739 Status = gBS->CreateEventEx (\r
1740 EVT_NOTIFY_SIGNAL,\r
1741 TPL_NOTIFY,\r
1742 EhcExitBootService,\r
1743 Ehc,\r
1744 &gEfiEventExitBootServicesGuid,\r
1745 &Ehc->ExitBootServiceEvent\r
1746 );\r
1747 if (EFI_ERROR (Status)) {\r
1748 goto UNINSTALL_USBHC;\r
1749 }\r
1750\r
913cb9dc 1751 //\r
1752 // Install the component name protocol, don't fail the start\r
1753 // because of something for display.\r
1754 //\r
f527bce3 1755 AddUnicodeString2 (\r
913cb9dc 1756 "eng",\r
1757 gEhciComponentName.SupportedLanguages,\r
1758 &Ehc->ControllerNameTable,\r
f527bce3 1759 L"Enhanced Host Controller (USB 2.0)",\r
1760 TRUE\r
913cb9dc 1761 );\r
f527bce3 1762 AddUnicodeString2 (\r
1763 "en",\r
1764 gEhciComponentName2.SupportedLanguages,\r
1765 &Ehc->ControllerNameTable,\r
1766 L"Enhanced Host Controller (USB 2.0)",\r
1767 FALSE\r
1768 );\r
1769\r
913cb9dc 1770\r
0e549d5b 1771 DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));\r
913cb9dc 1772 return EFI_SUCCESS;\r
1773\r
1774UNINSTALL_USBHC:\r
1775 gBS->UninstallProtocolInterface (\r
1776 Controller,\r
1777 &gEfiUsb2HcProtocolGuid,\r
1778 &Ehc->Usb2Hc\r
1779 );\r
1780\r
1781FREE_POOL:\r
1782 EhcFreeSched (Ehc);\r
1783 gBS->CloseEvent (Ehc->PollTimer);\r
1784 gBS->FreePool (Ehc);\r
1785\r
1786CLOSE_PCIIO:\r
a92d4e8a 1787 if (PciAttributesSaved) {\r
6a6d955c 1788 //\r
1789 // Restore original PCI attributes\r
1790 //\r
1791 PciIo->Attributes (\r
1792 PciIo,\r
1793 EfiPciIoAttributeOperationSet,\r
1794 OriginalPciAttributes,\r
1795 NULL\r
1796 );\r
1797 }\r
68246fa8 1798\r
913cb9dc 1799 gBS->CloseProtocol (\r
1800 Controller,\r
1801 &gEfiPciIoProtocolGuid,\r
1802 This->DriverBindingHandle,\r
1803 Controller\r
1804 );\r
1805\r
1806 return Status;\r
1807}\r
1808\r
1809\r
1810/**\r
1811 Stop this driver on ControllerHandle. Support stoping any child handles\r
1812 created by this driver.\r
1813\r
1814 @param This Protocol instance pointer.\r
78c2ffb5 1815 @param Controller Handle of device to stop driver on.\r
1816 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
913cb9dc 1817 @param ChildHandleBuffer List of handles for the children we need to stop.\r
1818\r
78c2ffb5 1819 @return EFI_SUCCESS Success.\r
1820 @return EFI_DEVICE_ERROR Fail.\r
913cb9dc 1821\r
1822**/\r
1823EFI_STATUS\r
1824EFIAPI\r
1825EhcDriverBindingStop (\r
1826 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1827 IN EFI_HANDLE Controller,\r
1828 IN UINTN NumberOfChildren,\r
1829 IN EFI_HANDLE *ChildHandleBuffer\r
1830 )\r
1831{\r
1832 EFI_STATUS Status;\r
1833 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1834 EFI_PCI_IO_PROTOCOL *PciIo;\r
1835 USB2_HC_DEV *Ehc;\r
1836\r
1837 //\r
1838 // Test whether the Controller handler passed in is a valid\r
1839 // Usb controller handle that should be supported, if not,\r
1840 // return the error status directly\r
1841 //\r
1842 Status = gBS->OpenProtocol (\r
1843 Controller,\r
1844 &gEfiUsb2HcProtocolGuid,\r
c52fa98c 1845 (VOID **) &Usb2Hc,\r
913cb9dc 1846 This->DriverBindingHandle,\r
1847 Controller,\r
1848 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1849 );\r
1850\r
1851 if (EFI_ERROR (Status)) {\r
1852 return Status;\r
1853 }\r
1854\r
1855 Ehc = EHC_FROM_THIS (Usb2Hc);\r
1856 PciIo = Ehc->PciIo;\r
1857\r
1858 //\r
1859 // Stop AsyncRequest Polling timer then stop the EHCI driver\r
1860 // and uninstall the EHCI protocl.\r
1861 //\r
41e8ff27 1862 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
1863 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
913cb9dc 1864\r
1865 Status = gBS->UninstallProtocolInterface (\r
1866 Controller,\r
1867 &gEfiUsb2HcProtocolGuid,\r
1868 Usb2Hc\r
1869 );\r
1870\r
1871 if (EFI_ERROR (Status)) {\r
1872 return Status;\r
1873 }\r
1874\r
1875 if (Ehc->PollTimer != NULL) {\r
1876 gBS->CloseEvent (Ehc->PollTimer);\r
1877 }\r
1878\r
0428a6cb 1879 if (Ehc->ExitBootServiceEvent != NULL) {\r
1880 gBS->CloseEvent (Ehc->ExitBootServiceEvent);\r
1881 }\r
1882\r
913cb9dc 1883 EhcFreeSched (Ehc);\r
1884\r
78c2ffb5 1885 if (Ehc->ControllerNameTable != NULL) {\r
913cb9dc 1886 FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
1887 }\r
1888\r
efe9186f 1889 //\r
1890 // Disable routing of all ports to EHCI controller, so all ports are \r
1891 // routed back to the UHCI controller.\r
1892 //\r
1893 EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
1894\r
913cb9dc 1895 //\r
68246fa8 1896 // Restore original PCI attributes\r
913cb9dc 1897 //\r
68246fa8 1898 PciIo->Attributes (\r
1899 PciIo,\r
1900 EfiPciIoAttributeOperationSet,\r
1901 Ehc->OriginalPciAttributes,\r
1902 NULL\r
1903 );\r
913cb9dc 1904\r
1905 gBS->CloseProtocol (\r
1906 Controller,\r
1907 &gEfiPciIoProtocolGuid,\r
1908 This->DriverBindingHandle,\r
1909 Controller\r
1910 );\r
1911\r
68246fa8 1912 FreePool (Ehc);\r
1913\r
96f6af14 1914 return EFI_SUCCESS;\r
913cb9dc 1915}\r
1916\r