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