]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
Fixed one bug: gSmmCorePrivate->InSmm is not set to FALSE correctly before exiting
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / Uhci.c
CommitLineData
913cb9dc 1/** @file\r
2\r
ab6495ea 3 The UHCI driver model and HC protocol routines.\r
4\r
37623a5c 5Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 6This program and the accompanying materials\r
913cb9dc 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#include "Uhci.h"\r
17\r
aa79b0b3 18\r
19EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {\r
20 UhciDriverBindingSupported,\r
21 UhciDriverBindingStart,\r
22 UhciDriverBindingStop,\r
23 0x20,\r
24 NULL,\r
25 NULL\r
26};\r
27\r
913cb9dc 28/**\r
ea5632e5 29 Provides software reset for the USB host controller according to UEFI 2.0 spec.\r
913cb9dc 30\r
ab6495ea 31 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
32 @param Attributes A bit mask of the reset operation to perform. See\r
33 below for a list of the supported bit mask values.\r
913cb9dc 34\r
ab6495ea 35 @return EFI_SUCCESS The reset operation succeeded.\r
36 @return EFI_INVALID_PARAMETER Attributes is not valid.\r
37 @return EFI_UNSUPPORTED This type of reset is not currently supported.\r
38 @return EFI_DEVICE_ERROR Other errors.\r
913cb9dc 39\r
40**/\r
913cb9dc 41EFI_STATUS\r
42EFIAPI\r
ea5632e5 43Uhci2Reset (\r
44 IN EFI_USB2_HC_PROTOCOL *This,\r
45 IN UINT16 Attributes\r
913cb9dc 46 )\r
47{\r
48 USB_HC_DEV *Uhc;\r
49 EFI_TPL OldTpl;\r
50\r
ea5632e5 51 if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||\r
52 (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {\r
53 return EFI_UNSUPPORTED;\r
54 }\r
55\r
37623a5c 56 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
57\r
58 if (Uhc->DevicePath != NULL) {\r
59 //\r
60 // Report Status Code to indicate reset happens\r
61 //\r
62 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
63 EFI_PROGRESS_CODE,\r
64 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
65 Uhc->DevicePath\r
66 );\r
67 }\r
ea5632e5 68\r
913cb9dc 69 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
913cb9dc 70\r
71 switch (Attributes) {\r
72 case EFI_USB_HC_RESET_GLOBAL:\r
73 //\r
74 // Stop schedule and set the Global Reset bit in the command register\r
75 //\r
41e8ff27 76 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);\r
913cb9dc 77 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
78\r
41e8ff27 79 gBS->Stall (UHC_ROOT_PORT_RESET_STALL);\r
913cb9dc 80\r
81 //\r
82 // Clear the Global Reset bit to zero.\r
83 //\r
84 UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
85\r
41e8ff27 86 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);\r
913cb9dc 87 break;\r
88\r
89 case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
90 //\r
91 // Stop schedule and set Host Controller Reset bit to 1\r
92 //\r
41e8ff27 93 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);\r
913cb9dc 94 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);\r
95\r
41e8ff27 96 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);\r
913cb9dc 97 break;\r
98\r
99 default:\r
100 goto ON_INVAILD_PARAMETER;\r
101 }\r
68246fa8 102\r
913cb9dc 103 //\r
104 // Delete all old transactions on the USB bus, then\r
105 // reinitialize the frame list\r
106 //\r
107 UhciFreeAllAsyncReq (Uhc);\r
108 UhciDestoryFrameList (Uhc);\r
109 UhciInitFrameList (Uhc);\r
110\r
111 gBS->RestoreTPL (OldTpl);\r
68246fa8 112\r
913cb9dc 113 return EFI_SUCCESS;\r
114\r
115ON_INVAILD_PARAMETER:\r
68246fa8 116\r
913cb9dc 117 gBS->RestoreTPL (OldTpl);\r
68246fa8 118\r
913cb9dc 119 return EFI_INVALID_PARAMETER;\r
120}\r
121\r
122\r
123/**\r
ea5632e5 124 Retrieves current state of the USB host controller according to UEFI 2.0 spec.\r
913cb9dc 125\r
ab6495ea 126 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
127 @param State Variable to receive current device state.\r
913cb9dc 128\r
ab6495ea 129 @return EFI_SUCCESS The state is returned.\r
130 @return EFI_INVALID_PARAMETER State is not valid.\r
131 @return EFI_DEVICE_ERROR Other errors.\r
913cb9dc 132\r
133**/\r
913cb9dc 134EFI_STATUS\r
135EFIAPI\r
ea5632e5 136Uhci2GetState (\r
db0f0d3c 137 IN EFI_USB2_HC_PROTOCOL *This,\r
138 OUT EFI_USB_HC_STATE *State\r
913cb9dc 139 )\r
140{\r
141 USB_HC_DEV *Uhc;\r
142 UINT16 UsbSts;\r
143 UINT16 UsbCmd;\r
144\r
145 if (State == NULL) {\r
146 return EFI_INVALID_PARAMETER;\r
147 }\r
148\r
ea5632e5 149 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 150\r
151 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
152 UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);\r
153\r
ab6495ea 154 if ((UsbCmd & USBCMD_EGSM) !=0 ) {\r
913cb9dc 155 *State = EfiUsbHcStateSuspend;\r
156\r
157 } else if ((UsbSts & USBSTS_HCH) != 0) {\r
158 *State = EfiUsbHcStateHalt;\r
159\r
160 } else {\r
161 *State = EfiUsbHcStateOperational;\r
162 }\r
163\r
164 return EFI_SUCCESS;\r
165}\r
166\r
167\r
168/**\r
ea5632e5 169 Sets the USB host controller to a specific state according to UEFI 2.0 spec.\r
913cb9dc 170\r
ab6495ea 171 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
172 @param State Indicates the state of the host controller that will\r
173 be set.\r
913cb9dc 174\r
ab6495ea 175 @return EFI_SUCCESS Host controller was successfully placed in the state.\r
176 @return EFI_INVALID_PARAMETER State is invalid.\r
177 @return EFI_DEVICE_ERROR Failed to set the state.\r
913cb9dc 178\r
179**/\r
913cb9dc 180EFI_STATUS\r
181EFIAPI\r
ea5632e5 182Uhci2SetState (\r
183 IN EFI_USB2_HC_PROTOCOL *This,\r
913cb9dc 184 IN EFI_USB_HC_STATE State\r
185 )\r
186{\r
187 EFI_USB_HC_STATE CurState;\r
188 USB_HC_DEV *Uhc;\r
189 EFI_TPL OldTpl;\r
190 EFI_STATUS Status;\r
191 UINT16 UsbCmd;\r
192\r
ea5632e5 193 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
194 Status = Uhci2GetState (This, &CurState);\r
913cb9dc 195\r
196 if (EFI_ERROR (Status)) {\r
197 return EFI_DEVICE_ERROR;\r
198 }\r
199\r
200 if (CurState == State) {\r
201 return EFI_SUCCESS;\r
202 }\r
203\r
204 Status = EFI_SUCCESS;\r
205 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
206\r
207 switch (State) {\r
208 case EfiUsbHcStateHalt:\r
41e8ff27 209 Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);\r
913cb9dc 210 break;\r
211\r
212 case EfiUsbHcStateOperational:\r
213 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
214\r
215 if (CurState == EfiUsbHcStateHalt) {\r
216 //\r
217 // Set Run/Stop bit to 1, also set the bandwidht reclamation\r
218 // point to 64 bytes\r
219 //\r
220 UsbCmd |= USBCMD_RS | USBCMD_MAXP;\r
221 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
222\r
223 } else if (CurState == EfiUsbHcStateSuspend) {\r
224 //\r
225 // If FGR(Force Global Resume) bit is 0, set it\r
226 //\r
227 if ((UsbCmd & USBCMD_FGR) == 0) {\r
228 UsbCmd |= USBCMD_FGR;\r
229 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
230 }\r
68246fa8 231\r
913cb9dc 232 //\r
233 // wait 20ms to let resume complete (20ms is specified by UHCI spec)\r
234 //\r
41e8ff27 235 gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);\r
913cb9dc 236\r
237 //\r
238 // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0\r
239 //\r
240 UsbCmd &= ~USBCMD_FGR;\r
241 UsbCmd &= ~USBCMD_EGSM;\r
242 UsbCmd |= USBCMD_RS;\r
243 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
244 }\r
245\r
246 break;\r
247\r
248 case EfiUsbHcStateSuspend:\r
ea5632e5 249 Status = Uhci2SetState (This, EfiUsbHcStateHalt);\r
913cb9dc 250\r
251 if (EFI_ERROR (Status)) {\r
252 Status = EFI_DEVICE_ERROR;\r
253 goto ON_EXIT;\r
254 }\r
68246fa8 255\r
913cb9dc 256 //\r
257 // Set Enter Global Suspend Mode bit to 1.\r
258 //\r
259 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
260 UsbCmd |= USBCMD_EGSM;\r
261 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
262 break;\r
263\r
264 default:\r
265 Status = EFI_INVALID_PARAMETER;\r
266 break;\r
267 }\r
268\r
269ON_EXIT:\r
270 gBS->RestoreTPL (OldTpl);\r
271 return Status;\r
272}\r
273\r
913cb9dc 274/**\r
ea5632e5 275 Retrieves capabilities of USB host controller according to UEFI 2.0 spec.\r
913cb9dc 276\r
ab6495ea 277 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
278 @param MaxSpeed A pointer to the max speed USB host controller\r
279 supports.\r
280 @param PortNumber A pointer to the number of root hub ports.\r
281 @param Is64BitCapable A pointer to an integer to show whether USB host\r
282 controller supports 64-bit memory addressing.\r
913cb9dc 283\r
ab6495ea 284 @return EFI_SUCCESS capabilities were retrieved successfully.\r
285 @return EFI_INVALID_PARAMETER MaxSpeed or PortNumber or Is64BitCapable is NULL.\r
286 @return EFI_DEVICE_ERROR An error was encountered.\r
913cb9dc 287\r
288**/\r
913cb9dc 289EFI_STATUS\r
290EFIAPI\r
ea5632e5 291Uhci2GetCapability (\r
292 IN EFI_USB2_HC_PROTOCOL *This,\r
293 OUT UINT8 *MaxSpeed,\r
294 OUT UINT8 *PortNumber,\r
295 OUT UINT8 *Is64BitCapable\r
913cb9dc 296 )\r
297{\r
298 USB_HC_DEV *Uhc;\r
299 UINT32 Offset;\r
300 UINT16 PortSC;\r
301 UINT32 Index;\r
302\r
ea5632e5 303 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 304\r
ea5632e5 305 if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {\r
913cb9dc 306 return EFI_INVALID_PARAMETER;\r
307 }\r
308\r
ea5632e5 309 *MaxSpeed = EFI_USB_SPEED_FULL;\r
310 *Is64BitCapable = (UINT8) FALSE;\r
311\r
913cb9dc 312 *PortNumber = 0;\r
313\r
314 for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {\r
315 Offset = USBPORTSC_OFFSET + Index * 2;\r
316 PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
317\r
318 //\r
319 // Port status's bit 7 is reserved and always returns 1 if\r
320 // the port number is valid. Intel's UHCI (in EHCI controller)\r
321 // returns 0 in this bit if port number is invalid. Also, if\r
322 // PciIo IoRead returns error, 0xFFFF is returned to caller.\r
323 //\r
b4c24e2d 324 if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {\r
325 break;\r
913cb9dc 326 }\r
b4c24e2d 327 (*PortNumber)++;\r
913cb9dc 328 }\r
329\r
330 Uhc->RootPorts = *PortNumber;\r
331\r
7df7393f 332 DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));\r
913cb9dc 333 return EFI_SUCCESS;\r
334}\r
335\r
336\r
337/**\r
ea5632e5 338 Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.\r
913cb9dc 339\r
ab6495ea 340 @param This A pointer to the EFI_USB2_HC_PROTOCOL.\r
341 @param PortNumber The port to get status.\r
342 @param PortStatus A pointer to the current port status bits and port\r
343 status change bits.\r
913cb9dc 344\r
ab6495ea 345 @return EFI_SUCCESS status of the USB root hub port was returned in PortStatus.\r
346 @return EFI_INVALID_PARAMETER PortNumber is invalid.\r
347 @return EFI_DEVICE_ERROR Can't read register.\r
913cb9dc 348\r
349**/\r
350EFI_STATUS\r
351EFIAPI\r
ea5632e5 352Uhci2GetRootHubPortStatus (\r
db0f0d3c 353 IN EFI_USB2_HC_PROTOCOL *This,\r
354 IN UINT8 PortNumber,\r
355 OUT EFI_USB_PORT_STATUS *PortStatus\r
913cb9dc 356 )\r
357{\r
358 USB_HC_DEV *Uhc;\r
359 UINT32 Offset;\r
360 UINT16 PortSC;\r
361\r
ea5632e5 362 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 363\r
364 if (PortStatus == NULL) {\r
365 return EFI_INVALID_PARAMETER;\r
366 }\r
367\r
368 if (PortNumber >= Uhc->RootPorts) {\r
369 return EFI_INVALID_PARAMETER;\r
370 }\r
371\r
372 Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
373 PortStatus->PortStatus = 0;\r
374 PortStatus->PortChangeStatus = 0;\r
375\r
376 PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
377\r
ab6495ea 378 if ((PortSC & USBPORTSC_CCS) != 0) {\r
913cb9dc 379 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
380 }\r
381\r
ab6495ea 382 if ((PortSC & USBPORTSC_PED) != 0) {\r
913cb9dc 383 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
384 }\r
385\r
ab6495ea 386 if ((PortSC & USBPORTSC_SUSP) != 0) {\r
1c619535 387 DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));\r
913cb9dc 388 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
389 }\r
390\r
ab6495ea 391 if ((PortSC & USBPORTSC_PR) != 0) {\r
913cb9dc 392 PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
393 }\r
394\r
ab6495ea 395 if ((PortSC & USBPORTSC_LSDA) != 0) {\r
913cb9dc 396 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
397 }\r
398\r
399 //\r
400 // CHC will always return one in port owner bit\r
401 //\r
402 PortStatus->PortStatus |= USB_PORT_STAT_OWNER;\r
403\r
ab6495ea 404 if ((PortSC & USBPORTSC_CSC) != 0) {\r
913cb9dc 405 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
406 }\r
407\r
ab6495ea 408 if ((PortSC & USBPORTSC_PEDC) != 0) {\r
913cb9dc 409 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
410 }\r
411\r
412 return EFI_SUCCESS;\r
413}\r
414\r
415\r
416/**\r
ea5632e5 417 Sets a feature for the specified root hub port according to UEFI 2.0 spec.\r
913cb9dc 418\r
ab6495ea 419 @param This A pointer to the EFI_USB2_HC_PROTOCOL.\r
420 @param PortNumber Specifies the root hub port whose feature is\r
421 requested to be set.\r
422 @param PortFeature Indicates the feature selector associated with the\r
423 feature set request.\r
913cb9dc 424\r
ab6495ea 425 @return EFI_SUCCESS PortFeature was set for the root port.\r
426 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
427 @return EFI_DEVICE_ERROR Can't read register.\r
913cb9dc 428\r
429**/\r
913cb9dc 430EFI_STATUS\r
431EFIAPI\r
ea5632e5 432Uhci2SetRootHubPortFeature (\r
433 IN EFI_USB2_HC_PROTOCOL *This,\r
434 IN UINT8 PortNumber,\r
435 IN EFI_USB_PORT_FEATURE PortFeature\r
913cb9dc 436 )\r
437{\r
438 USB_HC_DEV *Uhc;\r
439 EFI_TPL OldTpl;\r
440 UINT32 Offset;\r
441 UINT16 PortSC;\r
442 UINT16 Command;\r
443\r
ea5632e5 444 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 445\r
446 if (PortNumber >= Uhc->RootPorts) {\r
447 return EFI_INVALID_PARAMETER;\r
448 }\r
449\r
450 Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
451\r
452 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
453 PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
454\r
455 switch (PortFeature) {\r
456 case EfiUsbPortSuspend:\r
457 Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
ab6495ea 458 if ((Command & USBCMD_EGSM) == 0) {\r
913cb9dc 459 //\r
460 // if global suspend is not active, can set port suspend\r
461 //\r
462 PortSC &= 0xfff5;\r
463 PortSC |= USBPORTSC_SUSP;\r
464 }\r
465 break;\r
466\r
467 case EfiUsbPortReset:\r
468 PortSC &= 0xfff5;\r
469 PortSC |= USBPORTSC_PR;\r
470 break;\r
471\r
472 case EfiUsbPortPower:\r
473 //\r
474 // No action\r
475 //\r
476 break;\r
477\r
478 case EfiUsbPortEnable:\r
479 PortSC &= 0xfff5;\r
480 PortSC |= USBPORTSC_PED;\r
481 break;\r
482\r
483 default:\r
484 gBS->RestoreTPL (OldTpl);\r
485 return EFI_INVALID_PARAMETER;\r
486 }\r
487\r
488 UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
489 gBS->RestoreTPL (OldTpl);\r
490\r
491 return EFI_SUCCESS;\r
492}\r
493\r
494\r
495/**\r
ea5632e5 496 Clears a feature for the specified root hub port according to Uefi 2.0 spec.\r
913cb9dc 497\r
ab6495ea 498 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
499 @param PortNumber Specifies the root hub port whose feature is\r
500 requested to be cleared.\r
501 @param PortFeature Indicates the feature selector associated with the\r
502 feature clear request.\r
913cb9dc 503\r
ab6495ea 504 @return EFI_SUCCESS PortFeature was cleared for the USB root hub port.\r
505 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
506 @return EFI_DEVICE_ERROR Can't read register.\r
913cb9dc 507\r
508**/\r
913cb9dc 509EFI_STATUS\r
510EFIAPI\r
ea5632e5 511Uhci2ClearRootHubPortFeature (\r
512 IN EFI_USB2_HC_PROTOCOL *This,\r
513 IN UINT8 PortNumber,\r
514 IN EFI_USB_PORT_FEATURE PortFeature\r
913cb9dc 515 )\r
516{\r
517 USB_HC_DEV *Uhc;\r
518 EFI_TPL OldTpl;\r
519 UINT32 Offset;\r
520 UINT16 PortSC;\r
521\r
ea5632e5 522 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 523\r
524 if (PortNumber >= Uhc->RootPorts) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527\r
528 Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
529\r
530 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
531 PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
532\r
533 switch (PortFeature) {\r
534 case EfiUsbPortEnable:\r
535 PortSC &= 0xfff5;\r
536 PortSC &= ~USBPORTSC_PED;\r
537 break;\r
538\r
539 case EfiUsbPortSuspend:\r
540 //\r
541 // Cause a resume on the specified port if in suspend mode.\r
542 //\r
543 PortSC &= 0xfff5;\r
544 PortSC &= ~USBPORTSC_SUSP;\r
545 break;\r
546\r
547 case EfiUsbPortPower:\r
548 //\r
549 // No action\r
550 //\r
551 break;\r
552\r
553 case EfiUsbPortReset:\r
554 PortSC &= 0xfff5;\r
555 PortSC &= ~USBPORTSC_PR;\r
556 break;\r
557\r
558 case EfiUsbPortConnectChange:\r
559 PortSC &= 0xfff5;\r
560 PortSC |= USBPORTSC_CSC;\r
561 break;\r
562\r
563 case EfiUsbPortEnableChange:\r
564 PortSC &= 0xfff5;\r
565 PortSC |= USBPORTSC_PEDC;\r
566 break;\r
567\r
568 case EfiUsbPortSuspendChange:\r
569 //\r
570 // Root hub does not support this\r
571 //\r
572 break;\r
573\r
574 case EfiUsbPortOverCurrentChange:\r
575 //\r
576 // Root hub does not support this\r
577 //\r
578 break;\r
579\r
580 case EfiUsbPortResetChange:\r
581 //\r
582 // Root hub does not support this\r
583 //\r
584 break;\r
585\r
586 default:\r
587 gBS->RestoreTPL (OldTpl);\r
588 return EFI_INVALID_PARAMETER;\r
589 }\r
590\r
591 UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
592 gBS->RestoreTPL (OldTpl);\r
593\r
594 return EFI_SUCCESS;\r
595}\r
596\r
597\r
598/**\r
ab6495ea 599 Submits control transfer to a target USB device accroding to UEFI 2.0 spec.\r
600\r
601 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
602 @param DeviceAddress Target device address.\r
603 @param DeviceSpeed Device speed.\r
604 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
605 @param Request USB device request to send.\r
606 @param TransferDirection Data direction of the Data stage in control transfer.\r
607 @param Data Data to transmit/receive in data stage.\r
608 @param DataLength Length of the data.\r
609 @param TimeOut Maximum time, in microseconds, for transfer to complete.\r
610 @param Translator Transaction translator to be used by this device.\r
611 @param TransferResult Variable to receive the transfer result.\r
612\r
613 @return EFI_SUCCESS The control transfer was completed successfully.\r
614 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.\r
615 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
616 @return EFI_TIMEOUT Failed due to timeout.\r
617 @return EFI_DEVICE_ERROR Failed due to host controller or device error.\r
913cb9dc 618\r
619**/\r
913cb9dc 620EFI_STATUS\r
621EFIAPI\r
ea5632e5 622Uhci2ControlTransfer (\r
623 IN EFI_USB2_HC_PROTOCOL *This,\r
624 IN UINT8 DeviceAddress,\r
625 IN UINT8 DeviceSpeed,\r
626 IN UINTN MaximumPacketLength,\r
627 IN EFI_USB_DEVICE_REQUEST *Request,\r
628 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
629 IN OUT VOID *Data,\r
630 IN OUT UINTN *DataLength,\r
631 IN UINTN TimeOut,\r
632 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
633 OUT UINT32 *TransferResult\r
913cb9dc 634 )\r
635{\r
636 USB_HC_DEV *Uhc;\r
637 UHCI_TD_SW *TDs;\r
638 EFI_TPL OldTpl;\r
639 EFI_STATUS Status;\r
640 UHCI_QH_RESULT QhResult;\r
641 UINT8 PktId;\r
642 UINT8 *RequestPhy;\r
643 VOID *RequestMap;\r
644 UINT8 *DataPhy;\r
645 VOID *DataMap;\r
ea5632e5 646 BOOLEAN IsSlowDevice;\r
af58e377 647 UINTN TransferDataLength;\r
913cb9dc 648\r
ea5632e5 649 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 650 TDs = NULL;\r
651 DataPhy = NULL;\r
652 DataMap = NULL;\r
653 RequestPhy = NULL;\r
654 RequestMap = NULL;\r
655\r
ea5632e5 656 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);\r
657\r
913cb9dc 658 //\r
659 // Parameters Checking\r
660 //\r
661 if (Request == NULL || TransferResult == NULL) {\r
662 return EFI_INVALID_PARAMETER;\r
663 }\r
664\r
665 if (IsSlowDevice && (MaximumPacketLength != 8)) {\r
666 return EFI_INVALID_PARAMETER;\r
667 }\r
668\r
669 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
670 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
671\r
672 return EFI_INVALID_PARAMETER;\r
673 }\r
674\r
af58e377 675 if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {\r
913cb9dc 676 return EFI_INVALID_PARAMETER;\r
677 }\r
678\r
af58e377 679 if (TransferDirection == EfiUsbNoData) {\r
680 TransferDataLength = 0;\r
681 } else {\r
682 TransferDataLength = *DataLength;\r
683 }\r
684\r
913cb9dc 685 *TransferResult = EFI_USB_ERR_SYSTEM;\r
686 Status = EFI_DEVICE_ERROR;\r
687\r
688 //\r
689 // If errors exist that cause host controller halt,\r
690 // clear status then return EFI_DEVICE_ERROR.\r
691 //\r
692 UhciAckAllInterrupt (Uhc);\r
693\r
694 if (!UhciIsHcWorking (Uhc->PciIo)) {\r
695 return EFI_DEVICE_ERROR;\r
696 }\r
697\r
698 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
699\r
700 //\r
701 // Map the Request and data for bus master access,\r
702 // then create a list of TD for this transfer\r
703 //\r
704 Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);\r
705\r
706 if (EFI_ERROR (Status)) {\r
707 goto ON_EXIT;\r
708 }\r
709\r
710 Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);\r
711\r
712 if (EFI_ERROR (Status)) {\r
713 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
714 goto ON_EXIT;\r
715 }\r
716\r
717 TDs = UhciCreateCtrlTds (\r
718 Uhc,\r
719 DeviceAddress,\r
720 PktId,\r
3af875e2 721 (UINT8*)Request,\r
913cb9dc 722 RequestPhy,\r
3af875e2 723 (UINT8*)Data,\r
913cb9dc 724 DataPhy,\r
af58e377 725 TransferDataLength,\r
ea5632e5 726 (UINT8) MaximumPacketLength,\r
913cb9dc 727 IsSlowDevice\r
728 );\r
729\r
730 if (TDs == NULL) {\r
731 Status = EFI_OUT_OF_RESOURCES;\r
732 goto UNMAP_DATA;\r
733 }\r
734\r
735 //\r
736 // According to the speed of the end point, link\r
737 // the TD to corrosponding queue head, then check\r
738 // the execution result\r
739 //\r
3af875e2 740 UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);\r
913cb9dc 741 Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
742 UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);\r
743\r
744 Uhc->PciIo->Flush (Uhc->PciIo);\r
745\r
746 *TransferResult = QhResult.Result;\r
747\r
748 if (DataLength != NULL) {\r
749 *DataLength = QhResult.Complete;\r
750 }\r
751\r
752 UhciDestoryTds (Uhc, TDs);\r
753\r
754UNMAP_DATA:\r
755 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
756 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
757\r
758ON_EXIT:\r
759 gBS->RestoreTPL (OldTpl);\r
760 return Status;\r
761}\r
762\r
763\r
764/**\r
ab6495ea 765 Submits bulk transfer to a bulk endpoint of a USB device.\r
766\r
767 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
768 @param DeviceAddress Target device address.\r
769 @param EndPointAddress Endpoint number and direction.\r
770 @param DeviceSpeed Device speed.\r
771 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
772 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
773 @param Data Array of pointers to the buffers of data.\r
774 @param DataLength On input, size of the data buffer, On output,\r
775 actually transferred data size.\r
776 @param DataToggle On input, data toggle to use; On output, next data toggle.\r
777 @param TimeOut Maximum time out, in microseconds.\r
778 @param Translator A pointr to the transaction translator data.\r
779 @param TransferResult Variable to receive transfer result.\r
780\r
781 @return EFI_SUCCESS The bulk transfer was completed successfully.\r
782 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.\r
783 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
784 @return EFI_TIMEOUT Failed due to timeout.\r
785 @return EFI_DEVICE_ERROR Failed due to host controller or device error.\r
913cb9dc 786\r
787**/\r
913cb9dc 788EFI_STATUS\r
789EFIAPI\r
ea5632e5 790Uhci2BulkTransfer (\r
791 IN EFI_USB2_HC_PROTOCOL *This,\r
792 IN UINT8 DeviceAddress,\r
793 IN UINT8 EndPointAddress,\r
794 IN UINT8 DeviceSpeed,\r
795 IN UINTN MaximumPacketLength,\r
796 IN UINT8 DataBuffersNumber,\r
797 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
798 IN OUT UINTN *DataLength,\r
799 IN OUT UINT8 *DataToggle,\r
800 IN UINTN TimeOut,\r
801 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
802 OUT UINT32 *TransferResult\r
913cb9dc 803 )\r
804{\r
805 EFI_USB_DATA_DIRECTION Direction;\r
806 EFI_TPL OldTpl;\r
807 USB_HC_DEV *Uhc;\r
808 UHCI_TD_SW *TDs;\r
809 UHCI_QH_SW *BulkQh;\r
810 UHCI_QH_RESULT QhResult;\r
811 EFI_STATUS Status;\r
812 UINT8 PktId;\r
813 UINT8 *DataPhy;\r
814 VOID *DataMap;\r
815\r
ea5632e5 816 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 817 DataPhy = NULL;\r
818 DataMap = NULL;\r
819\r
ea5632e5 820 if (DeviceSpeed == EFI_USB_SPEED_LOW) {\r
821 return EFI_INVALID_PARAMETER;\r
822 }\r
823\r
ab6495ea 824 if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {\r
913cb9dc 825 return EFI_INVALID_PARAMETER;\r
826 }\r
827\r
828 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
829 return EFI_INVALID_PARAMETER;\r
830 }\r
831\r
832 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
833 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
834 return EFI_INVALID_PARAMETER;\r
835 }\r
836\r
837 *TransferResult = EFI_USB_ERR_SYSTEM;\r
838 Status = EFI_OUT_OF_RESOURCES;\r
839\r
840 //\r
841 // If has errors that cause host controller halt,\r
842 // then return EFI_DEVICE_ERROR directly.\r
843 //\r
844 UhciAckAllInterrupt (Uhc);\r
845\r
846 if (!UhciIsHcWorking (Uhc->PciIo)) {\r
847 return EFI_DEVICE_ERROR;\r
848 }\r
849\r
850 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
851\r
852 //\r
853 // Map the source data buffer for bus master access,\r
854 // then create a list of TDs\r
855 //\r
ab6495ea 856 if ((EndPointAddress & 0x80) != 0) {\r
913cb9dc 857 Direction = EfiUsbDataIn;\r
858 } else {\r
859 Direction = EfiUsbDataOut;\r
860 }\r
861\r
ea5632e5 862 Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);\r
913cb9dc 863\r
864 if (EFI_ERROR (Status)) {\r
865 goto ON_EXIT;\r
866 }\r
867\r
868 Status = EFI_OUT_OF_RESOURCES;\r
869 TDs = UhciCreateBulkOrIntTds (\r
870 Uhc,\r
871 DeviceAddress,\r
872 EndPointAddress,\r
873 PktId,\r
3af875e2 874 (UINT8 *)*Data,\r
913cb9dc 875 DataPhy,\r
876 *DataLength,\r
877 DataToggle,\r
ea5632e5 878 (UINT8) MaximumPacketLength,\r
913cb9dc 879 FALSE\r
880 );\r
881\r
882 if (TDs == NULL) {\r
883 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
884 goto ON_EXIT;\r
885 }\r
886\r
887\r
888 //\r
889 // Link the TDs to bulk queue head. According to the platfore\r
890 // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured\r
891 // to do full speed bandwidth reclamation or not.\r
892 //\r
893 BulkQh = Uhc->BulkQh;\r
894\r
3af875e2 895 UhciLinkTdToQh (Uhc, BulkQh, TDs);\r
913cb9dc 896 Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);\r
897 UhciUnlinkTdFromQh (BulkQh, TDs);\r
898\r
899 Uhc->PciIo->Flush (Uhc->PciIo);\r
900\r
901 *TransferResult = QhResult.Result;\r
902 *DataToggle = QhResult.NextToggle;\r
903 *DataLength = QhResult.Complete;\r
904\r
905 UhciDestoryTds (Uhc, TDs);\r
906 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
907\r
908ON_EXIT:\r
909 gBS->RestoreTPL (OldTpl);\r
910 return Status;\r
911}\r
912\r
913\r
914/**\r
ea5632e5 915 Submits an asynchronous interrupt transfer to an\r
916 interrupt endpoint of a USB device according to UEFI 2.0 spec.\r
913cb9dc 917\r
ab6495ea 918 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
919 @param DeviceAddress Target device address.\r
920 @param EndPointAddress Endpoint number and direction.\r
921 @param DeviceSpeed Device speed.\r
922 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
923 @param IsNewTransfer If TRUE, submit a new transfer, if FALSE cancel old transfer.\r
924 @param DataToggle On input, data toggle to use; On output, next data toggle.\r
925 @param PollingInterval Interrupt poll rate in milliseconds.\r
926 @param DataLength On input, size of the data buffer, On output,\r
927 actually transferred data size.\r
928 @param Translator A pointr to the transaction translator data.\r
929 @param CallBackFunction Function to call periodically.\r
930 @param Context User context.\r
931\r
932 @return EFI_SUCCESS Transfer was submitted.\r
933 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
934 @return EFI_OUT_OF_RESOURCES Failed due to a lack of resources.\r
935 @return EFI_DEVICE_ERROR Can't read register.\r
913cb9dc 936\r
937**/\r
913cb9dc 938EFI_STATUS\r
939EFIAPI\r
ea5632e5 940Uhci2AsyncInterruptTransfer (\r
941 IN EFI_USB2_HC_PROTOCOL *This,\r
913cb9dc 942 IN UINT8 DeviceAddress,\r
943 IN UINT8 EndPointAddress,\r
ea5632e5 944 IN UINT8 DeviceSpeed,\r
945 IN UINTN MaximumPacketLength,\r
913cb9dc 946 IN BOOLEAN IsNewTransfer,\r
947 IN OUT UINT8 *DataToggle,\r
ea5632e5 948 IN UINTN PollingInterval,\r
949 IN UINTN DataLength,\r
950 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
951 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
952 IN VOID *Context\r
913cb9dc 953 )\r
954{\r
955 USB_HC_DEV *Uhc;\r
ea5632e5 956 BOOLEAN IsSlowDevice;\r
913cb9dc 957 UHCI_QH_SW *Qh;\r
958 UHCI_TD_SW *IntTds;\r
959 EFI_TPL OldTpl;\r
960 EFI_STATUS Status;\r
961 UINT8 *DataPtr;\r
962 UINT8 *DataPhy;\r
913cb9dc 963 UINT8 PktId;\r
964\r
ea5632e5 965 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 966 Qh = NULL;\r
967 IntTds = NULL;\r
968 DataPtr = NULL;\r
969 DataPhy = NULL;\r
913cb9dc 970\r
ea5632e5 971 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);\r
972\r
913cb9dc 973 if ((EndPointAddress & 0x80) == 0) {\r
974 return EFI_INVALID_PARAMETER;\r
975 }\r
976\r
977 //\r
978 // Delete Async interrupt transfer request\r
979 //\r
980 if (!IsNewTransfer) {\r
981 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
982 Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);\r
983\r
984 gBS->RestoreTPL (OldTpl);\r
985 return Status;\r
986 }\r
987\r
988 if (PollingInterval < 1 || PollingInterval > 255) {\r
989 return EFI_INVALID_PARAMETER;\r
990 }\r
991\r
992 if (DataLength == 0) {\r
993 return EFI_INVALID_PARAMETER;\r
994 }\r
995\r
996 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
997 return EFI_INVALID_PARAMETER;\r
998 }\r
999\r
1000 //\r
1001 // If has errors that cause host controller halt,\r
1002 // then return EFI_DEVICE_ERROR directly.\r
1003 //\r
1004 UhciAckAllInterrupt (Uhc);\r
1005\r
1006 if (!UhciIsHcWorking (Uhc->PciIo)) {\r
1007 return EFI_DEVICE_ERROR;\r
1008 }\r
1009\r
aa91de05 1010 if ((EndPointAddress & 0x80) == 0) {\r
1011 PktId = OUTPUT_PACKET_ID;\r
1012 } else {\r
1013 PktId = INPUT_PACKET_ID;\r
1014 }\r
1015\r
913cb9dc 1016 //\r
1017 // Allocate and map source data buffer for bus master access.\r
1018 //\r
aa91de05 1019 DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);\r
913cb9dc 1020\r
1021 if (DataPtr == NULL) {\r
1022 return EFI_OUT_OF_RESOURCES;\r
1023 }\r
1024\r
6691cae9 1025 DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Uhc->MemPool, DataPtr, DataLength);\r
913cb9dc 1026\r
aa91de05 1027 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
913cb9dc 1028\r
1029 Qh = UhciCreateQh (Uhc, PollingInterval);\r
1030\r
1031 if (Qh == NULL) {\r
1032 Status = EFI_OUT_OF_RESOURCES;\r
aa91de05 1033 goto FREE_DATA;\r
913cb9dc 1034 }\r
1035\r
1036 IntTds = UhciCreateBulkOrIntTds (\r
1037 Uhc,\r
1038 DeviceAddress,\r
1039 EndPointAddress,\r
1040 PktId,\r
3af875e2 1041 DataPtr,\r
913cb9dc 1042 DataPhy,\r
1043 DataLength,\r
1044 DataToggle,\r
ea5632e5 1045 (UINT8) MaximumPacketLength,\r
913cb9dc 1046 IsSlowDevice\r
1047 );\r
1048\r
1049 if (IntTds == NULL) {\r
1050 Status = EFI_OUT_OF_RESOURCES;\r
1051 goto DESTORY_QH;\r
1052 }\r
1053\r
3af875e2 1054 UhciLinkTdToQh (Uhc, Qh, IntTds);\r
913cb9dc 1055\r
1056 //\r
1057 // Save QH-TD structures to async Interrupt transfer list,\r
1058 // for monitor interrupt transfer execution routine use.\r
1059 //\r
1060 Status = UhciCreateAsyncReq (\r
1061 Uhc,\r
1062 Qh,\r
1063 IntTds,\r
1064 DeviceAddress,\r
1065 EndPointAddress,\r
1066 DataLength,\r
1067 PollingInterval,\r
913cb9dc 1068 DataPtr,\r
1069 CallBackFunction,\r
1070 Context,\r
1071 IsSlowDevice\r
1072 );\r
1073\r
1074 if (EFI_ERROR (Status)) {\r
1075 goto DESTORY_QH;\r
1076 }\r
1077\r
3af875e2 1078 UhciLinkQhToFrameList (Uhc, Qh);\r
913cb9dc 1079\r
1080 gBS->RestoreTPL (OldTpl);\r
1081 return EFI_SUCCESS;\r
1082\r
1083DESTORY_QH:\r
1084 UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));\r
1085\r
913cb9dc 1086FREE_DATA:\r
aa91de05 1087 UsbHcFreeMem (Uhc->MemPool, DataPtr, DataLength);\r
913cb9dc 1088 Uhc->PciIo->Flush (Uhc->PciIo);\r
1089\r
1090 gBS->RestoreTPL (OldTpl);\r
1091 return Status;\r
1092}\r
1093\r
913cb9dc 1094/**\r
ea5632e5 1095 Submits synchronous interrupt transfer to an interrupt endpoint\r
1096 of a USB device according to UEFI 2.0 spec.\r
913cb9dc 1097\r
ab6495ea 1098\r
1099 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1100 @param DeviceAddress Target device address.\r
1101 @param EndPointAddress Endpoint number and direction.\r
1102 @param DeviceSpeed Device speed.\r
1103 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
1104 @param Data Array of pointers to the buffers of data.\r
1105 @param DataLength On input, size of the data buffer, On output,\r
1106 actually transferred data size.\r
1107 @param DataToggle On input, data toggle to use; On output, next data toggle.\r
1108 @param TimeOut Maximum time out, in microseconds.\r
1109 @param Translator A pointr to the transaction translator data.\r
1110 @param TransferResult Variable to receive transfer result.\r
1111\r
1112 @return EFI_SUCCESS The transfer was completed successfully.\r
1113 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.\r
1114 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
1115 @return EFI_TIMEOUT Failed due to timeout.\r
1116 @return EFI_DEVICE_ERROR Failed due to host controller or device error.\r
913cb9dc 1117\r
1118**/\r
913cb9dc 1119EFI_STATUS\r
1120EFIAPI\r
ea5632e5 1121Uhci2SyncInterruptTransfer (\r
1122 IN EFI_USB2_HC_PROTOCOL *This,\r
1123 IN UINT8 DeviceAddress,\r
1124 IN UINT8 EndPointAddress,\r
1125 IN UINT8 DeviceSpeed,\r
1126 IN UINTN MaximumPacketLength,\r
1127 IN OUT VOID *Data,\r
1128 IN OUT UINTN *DataLength,\r
1129 IN OUT UINT8 *DataToggle,\r
1130 IN UINTN TimeOut,\r
1131 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1132 OUT UINT32 *TransferResult\r
913cb9dc 1133 )\r
1134{\r
1135 EFI_STATUS Status;\r
1136 USB_HC_DEV *Uhc;\r
1137 UHCI_TD_SW *TDs;\r
1138 UHCI_QH_RESULT QhResult;\r
1139 EFI_TPL OldTpl;\r
1140 UINT8 *DataPhy;\r
1141 VOID *DataMap;\r
1142 UINT8 PktId;\r
ea5632e5 1143 BOOLEAN IsSlowDevice;\r
913cb9dc 1144\r
ea5632e5 1145 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
913cb9dc 1146 DataPhy = NULL;\r
1147 DataMap = NULL;\r
1148 TDs = NULL;\r
1149\r
ea5632e5 1150 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1151 return EFI_INVALID_PARAMETER;\r
1152 }\r
1153\r
1154 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);\r
1155\r
913cb9dc 1156 if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {\r
1157 return EFI_INVALID_PARAMETER;\r
1158 }\r
1159\r
1160 if ((EndPointAddress & 0x80) == 0) {\r
1161 return EFI_INVALID_PARAMETER;\r
1162 }\r
1163\r
1164 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1165 return EFI_INVALID_PARAMETER;\r
1166 }\r
1167\r
1168 if ((*DataLength == 0) || (MaximumPacketLength > 64)) {\r
1169 return EFI_INVALID_PARAMETER;\r
1170 }\r
1171\r
1172 if (IsSlowDevice && (MaximumPacketLength > 8)) {\r
1173 return EFI_INVALID_PARAMETER;\r
1174 }\r
1175\r
1176 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1177 Status = EFI_DEVICE_ERROR;\r
1178\r
1179\r
1180 UhciAckAllInterrupt (Uhc);\r
1181\r
1182 if (!UhciIsHcWorking (Uhc->PciIo)) {\r
1183 return Status;\r
1184 }\r
1185\r
1186 OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
1187\r
1188 //\r
1189 // Map the source data buffer for bus master access.\r
1190 // Create Tds list, then link it to the UHC's interrupt list\r
1191 //\r
1192 Status = UhciMapUserData (\r
1193 Uhc,\r
1194 EfiUsbDataIn,\r
1195 Data,\r
1196 DataLength,\r
1197 &PktId,\r
1198 &DataPhy,\r
1199 &DataMap\r
1200 );\r
1201\r
1202 if (EFI_ERROR (Status)) {\r
1203 goto ON_EXIT;\r
1204 }\r
1205\r
1206 TDs = UhciCreateBulkOrIntTds (\r
1207 Uhc,\r
1208 DeviceAddress,\r
1209 EndPointAddress,\r
1210 PktId,\r
3af875e2 1211 (UINT8 *)Data,\r
913cb9dc 1212 DataPhy,\r
1213 *DataLength,\r
1214 DataToggle,\r
ea5632e5 1215 (UINT8) MaximumPacketLength,\r
913cb9dc 1216 IsSlowDevice\r
1217 );\r
1218\r
1219 if (TDs == NULL) {\r
1220 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
1221\r
1222 Status = EFI_OUT_OF_RESOURCES;\r
1223 goto ON_EXIT;\r
1224 }\r
1225\r
1226\r
3af875e2 1227 UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);\r
913cb9dc 1228\r
1229 Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
1230\r
1231 UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);\r
1232 Uhc->PciIo->Flush (Uhc->PciIo);\r
1233\r
1234 *TransferResult = QhResult.Result;\r
1235 *DataToggle = QhResult.NextToggle;\r
1236 *DataLength = QhResult.Complete;\r
1237\r
1238 UhciDestoryTds (Uhc, TDs);\r
1239 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
1240\r
1241ON_EXIT:\r
1242 gBS->RestoreTPL (OldTpl);\r
1243 return Status;\r
1244}\r
1245\r
1246\r
1247/**\r
ea5632e5 1248 Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
913cb9dc 1249\r
ab6495ea 1250 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1251 @param DeviceAddress Target device address.\r
1252 @param EndPointAddress Endpoint number and direction.\r
1253 @param DeviceSpeed Device speed.\r
1254 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
1255 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1256 @param Data Array of pointers to the buffers of data.\r
1257 @param DataLength On input, size of the data buffer, On output,\r
1258 actually transferred data size.\r
1259 @param Translator A pointr to the transaction translator data.\r
1260 @param TransferResult Variable to receive transfer result.\r
913cb9dc 1261\r
1262 @return EFI_UNSUPPORTED\r
1263\r
1264**/\r
913cb9dc 1265EFI_STATUS\r
1266EFIAPI\r
ea5632e5 1267Uhci2IsochronousTransfer (\r
1268 IN EFI_USB2_HC_PROTOCOL *This,\r
1269 IN UINT8 DeviceAddress,\r
1270 IN UINT8 EndPointAddress,\r
1271 IN UINT8 DeviceSpeed,\r
1272 IN UINTN MaximumPacketLength,\r
1273 IN UINT8 DataBuffersNumber,\r
1274 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1275 IN UINTN DataLength,\r
1276 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1277 OUT UINT32 *TransferResult\r
913cb9dc 1278 )\r
1279{\r
1280 return EFI_UNSUPPORTED;\r
1281}\r
1282\r
1283\r
1284/**\r
ea5632e5 1285 Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
913cb9dc 1286\r
ab6495ea 1287 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1288 @param DeviceAddress Target device address.\r
1289 @param EndPointAddress Endpoint number and direction.\r
1290 @param DeviceSpeed Device speed.\r
1291 @param MaximumPacketLength Maximum packet size of the target endpoint.\r
1292 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1293 @param Data Array of pointers to the buffers of data.\r
1294 @param DataLength On input, size of the data buffer, On output,\r
1295 actually transferred data size.\r
1296 @param Translator A pointr to the transaction translator data.\r
1297 @param IsochronousCallBack Function to call when the transfer complete.\r
1298 @param Context Pass to the call back function as parameter.\r
913cb9dc 1299\r
1300 @return EFI_UNSUPPORTED\r
1301\r
1302**/\r
913cb9dc 1303EFI_STATUS\r
1304EFIAPI\r
ea5632e5 1305Uhci2AsyncIsochronousTransfer (\r
1306 IN EFI_USB2_HC_PROTOCOL *This,\r
1307 IN UINT8 DeviceAddress,\r
1308 IN UINT8 EndPointAddress,\r
1309 IN UINT8 DeviceSpeed,\r
1310 IN UINTN MaximumPacketLength,\r
1311 IN UINT8 DataBuffersNumber,\r
1312 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1313 IN UINTN DataLength,\r
1314 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1315 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1316 IN VOID *Context\r
913cb9dc 1317 )\r
1318{\r
1319 return EFI_UNSUPPORTED;\r
1320}\r
1321\r
ab6495ea 1322/**\r
1323 Entry point for EFI drivers.\r
1324\r
1325 @param ImageHandle EFI_HANDLE.\r
1326 @param SystemTable EFI_SYSTEM_TABLE.\r
1327\r
1328 @retval EFI_SUCCESS Driver is successfully loaded.\r
1329 @return Others Failed.\r
1330\r
1331**/\r
913cb9dc 1332EFI_STATUS\r
1333EFIAPI\r
1334UhciDriverEntryPoint (\r
1335 IN EFI_HANDLE ImageHandle,\r
1336 IN EFI_SYSTEM_TABLE *SystemTable\r
1337 )\r
913cb9dc 1338{\r
f527bce3 1339 return EfiLibInstallDriverBindingComponentName2 (\r
913cb9dc 1340 ImageHandle,\r
1341 SystemTable,\r
1342 &gUhciDriverBinding,\r
1343 ImageHandle,\r
1344 &gUhciComponentName,\r
f527bce3 1345 &gUhciComponentName2\r
913cb9dc 1346 );\r
1347}\r
1348\r
1349\r
1350/**\r
1351 Test to see if this driver supports ControllerHandle. Any\r
1352 ControllerHandle that has UsbHcProtocol installed will be supported.\r
1353\r
1354 @param This Protocol instance pointer.\r
ab6495ea 1355 @param Controller Handle of device to test.\r
1356 @param RemainingDevicePath Not used.\r
913cb9dc 1357\r
ab6495ea 1358 @return EFI_SUCCESS This driver supports this device.\r
1359 @return EFI_UNSUPPORTED This driver does not support this device.\r
913cb9dc 1360\r
1361**/\r
1362EFI_STATUS\r
1363EFIAPI\r
1364UhciDriverBindingSupported (\r
1365 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1366 IN EFI_HANDLE Controller,\r
1367 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1368 )\r
1369{\r
1370 EFI_STATUS OpenStatus;\r
1371 EFI_STATUS Status;\r
1372 EFI_PCI_IO_PROTOCOL *PciIo;\r
1373 USB_CLASSC UsbClassCReg;\r
1374\r
1375 //\r
1376 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1377 //\r
1378 OpenStatus = gBS->OpenProtocol (\r
1379 Controller,\r
1380 &gEfiPciIoProtocolGuid,\r
c52fa98c 1381 (VOID **) &PciIo,\r
913cb9dc 1382 This->DriverBindingHandle,\r
1383 Controller,\r
1384 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1385 );\r
1386\r
1387 if (EFI_ERROR (OpenStatus)) {\r
1388 return OpenStatus;\r
1389 }\r
1390\r
1391 Status = PciIo->Pci.Read (\r
1392 PciIo,\r
1393 EfiPciIoWidthUint8,\r
a261044c 1394 PCI_CLASSCODE_OFFSET,\r
913cb9dc 1395 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1396 &UsbClassCReg\r
1397 );\r
1398\r
1399 if (EFI_ERROR (Status)) {\r
1400 Status = EFI_UNSUPPORTED;\r
1401 goto ON_EXIT;\r
1402 }\r
1403\r
1404 //\r
1405 // Test whether the controller belongs to UHCI type\r
1406 //\r
1407 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1408 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1ccdbf2a 1409 (UsbClassCReg.ProgInterface != PCI_IF_UHCI)\r
913cb9dc 1410 ) {\r
1411\r
1412 Status = EFI_UNSUPPORTED;\r
1413 }\r
1414\r
1415ON_EXIT:\r
1416 gBS->CloseProtocol (\r
1417 Controller,\r
1418 &gEfiPciIoProtocolGuid,\r
1419 This->DriverBindingHandle,\r
1420 Controller\r
1421 );\r
1422\r
1423 return Status;\r
1424\r
1425}\r
1426\r
1427\r
1428/**\r
ab6495ea 1429 Allocate and initialize the empty UHCI device.\r
913cb9dc 1430\r
ab6495ea 1431 @param PciIo The PCIIO to use.\r
1432 @param OriginalPciAttributes The original PCI attributes.\r
913cb9dc 1433\r
ab6495ea 1434 @return Allocated UHCI device. If err, return NULL.\r
913cb9dc 1435\r
1436**/\r
913cb9dc 1437USB_HC_DEV *\r
1438UhciAllocateDev (\r
37623a5c 1439 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1440 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1441 IN UINT64 OriginalPciAttributes\r
913cb9dc 1442 )\r
1443{\r
1444 USB_HC_DEV *Uhc;\r
1445 EFI_STATUS Status;\r
1446\r
1447 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));\r
1448\r
1449 if (Uhc == NULL) {\r
1450 return NULL;\r
1451 }\r
1452\r
1453 //\r
1454 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.\r
1455 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.\r
1456 //\r
1457 Uhc->Signature = USB_HC_DEV_SIGNATURE;\r
913cb9dc 1458 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;\r
1459 Uhc->Usb2Hc.Reset = Uhci2Reset;\r
1460 Uhc->Usb2Hc.GetState = Uhci2GetState;\r
1461 Uhc->Usb2Hc.SetState = Uhci2SetState;\r
1462 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;\r
1463 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;\r
1464 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;\r
1465 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;\r
1466 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;\r
1467 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;\r
1468 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;\r
1469 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;\r
1470 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;\r
1471 Uhc->Usb2Hc.MajorRevision = 0x1;\r
1472 Uhc->Usb2Hc.MinorRevision = 0x1;\r
1473\r
68246fa8 1474 Uhc->PciIo = PciIo;\r
37623a5c 1475 Uhc->DevicePath = DevicePath;\r
68246fa8 1476 Uhc->OriginalPciAttributes = OriginalPciAttributes;\r
1477 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);\r
913cb9dc 1478\r
1479 if (Uhc->MemPool == NULL) {\r
1480 Status = EFI_OUT_OF_RESOURCES;\r
1481 goto ON_ERROR;\r
1482 }\r
1483\r
1484 InitializeListHead (&Uhc->AsyncIntList);\r
1485\r
1486 Status = gBS->CreateEvent (\r
1487 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1488 TPL_CALLBACK,\r
1489 UhciMonitorAsyncReqList,\r
1490 Uhc,\r
1491 &Uhc->AsyncIntMonitor\r
1492 );\r
1493\r
1494 if (EFI_ERROR (Status)) {\r
1495 UsbHcFreeMemPool (Uhc->MemPool);\r
1496 goto ON_ERROR;\r
1497 }\r
1498\r
1499 return Uhc;\r
1500\r
1501ON_ERROR:\r
7351070b 1502 FreePool (Uhc);\r
913cb9dc 1503 return NULL;\r
1504}\r
1505\r
1506\r
1507/**\r
ab6495ea 1508 Free the UHCI device and release its associated resources.\r
913cb9dc 1509\r
ab6495ea 1510 @param Uhc The UHCI device to release.\r
913cb9dc 1511\r
913cb9dc 1512**/\r
913cb9dc 1513VOID\r
1514UhciFreeDev (\r
1515 IN USB_HC_DEV *Uhc\r
1516 )\r
1517{\r
1518 if (Uhc->AsyncIntMonitor != NULL) {\r
1519 gBS->CloseEvent (Uhc->AsyncIntMonitor);\r
1520 }\r
1521\r
0428a6cb 1522 if (Uhc->ExitBootServiceEvent != NULL) {\r
1523 gBS->CloseEvent (Uhc->ExitBootServiceEvent);\r
1524 }\r
1525 \r
913cb9dc 1526 if (Uhc->MemPool != NULL) {\r
1527 UsbHcFreeMemPool (Uhc->MemPool);\r
1528 }\r
1529\r
ab6495ea 1530 if (Uhc->CtrlNameTable != NULL) {\r
913cb9dc 1531 FreeUnicodeStringTable (Uhc->CtrlNameTable);\r
1532 }\r
1533\r
7351070b 1534 FreePool (Uhc);\r
913cb9dc 1535}\r
1536\r
1537\r
1538/**\r
ab6495ea 1539 Uninstall all Uhci Interface.\r
913cb9dc 1540\r
ab6495ea 1541 @param Controller Controller handle.\r
913cb9dc 1542 @param This Protocol instance pointer.\r
1543\r
913cb9dc 1544**/\r
913cb9dc 1545VOID\r
1546UhciCleanDevUp (\r
ea5632e5 1547 IN EFI_HANDLE Controller,\r
1548 IN EFI_USB2_HC_PROTOCOL *This\r
913cb9dc 1549 )\r
1550{\r
1551 USB_HC_DEV *Uhc;\r
1552\r
1553 //\r
1554 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller\r
1555 //\r
ea5632e5 1556 Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
41e8ff27 1557 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);\r
913cb9dc 1558\r
913cb9dc 1559 gBS->UninstallProtocolInterface (\r
1560 Controller,\r
1561 &gEfiUsb2HcProtocolGuid,\r
1562 &Uhc->Usb2Hc\r
1563 );\r
1564\r
1565 UhciFreeAllAsyncReq (Uhc);\r
1566 UhciDestoryFrameList (Uhc);\r
68246fa8 1567\r
1568 //\r
1569 // Restore original PCI attributes\r
1570 //\r
913cb9dc 1571 Uhc->PciIo->Attributes (\r
68246fa8 1572 Uhc->PciIo,\r
1573 EfiPciIoAttributeOperationSet,\r
1574 Uhc->OriginalPciAttributes,\r
1575 NULL\r
1576 );\r
913cb9dc 1577\r
1578 UhciFreeDev (Uhc);\r
1579}\r
1580\r
0428a6cb 1581/**\r
1582 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1583\r
1584 @param Event Pointer to this event\r
1585 @param Context Event hanlder private data\r
1586\r
1587**/\r
1588VOID\r
1589EFIAPI\r
1590UhcExitBootService (\r
1591 EFI_EVENT Event,\r
1592 VOID *Context\r
1593 )\r
1594{\r
1595 USB_HC_DEV *Uhc;\r
1596\r
1597 Uhc = (USB_HC_DEV *) Context;\r
1598\r
1599 //\r
1600 // Stop the Host Controller\r
1601 //\r
1602 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);\r
1603\r
2dda77a6 1604 //\r
1605 // Reset the Host Controller\r
1606 //\r
1607 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);\r
1608 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);\r
0428a6cb 1609}\r
913cb9dc 1610\r
1611/**\r
ab6495ea 1612 Starting the Usb UHCI Driver.\r
913cb9dc 1613\r
1614 @param This Protocol instance pointer.\r
ab6495ea 1615 @param Controller Handle of device to test.\r
1616 @param RemainingDevicePath Not used.\r
913cb9dc 1617\r
1618 @retval EFI_SUCCESS This driver supports this device.\r
1619 @retval EFI_UNSUPPORTED This driver does not support this device.\r
ab6495ea 1620 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
1621 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
913cb9dc 1622\r
1623**/\r
1624EFI_STATUS\r
1625EFIAPI\r
1626UhciDriverBindingStart (\r
1627 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1628 IN EFI_HANDLE Controller,\r
1629 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1630 )\r
1631{\r
1632 EFI_STATUS Status;\r
1633 EFI_PCI_IO_PROTOCOL *PciIo;\r
1634 USB_HC_DEV *Uhc;\r
96f6af14 1635 UINT64 Supports;\r
68246fa8 1636 UINT64 OriginalPciAttributes;\r
6a6d955c 1637 BOOLEAN PciAttributesSaved;\r
37623a5c 1638 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;\r
913cb9dc 1639\r
1640 //\r
1641 // Open PCIIO, then enable the EHC device and turn off emulation\r
1642 //\r
1643 Uhc = NULL;\r
1644 Status = gBS->OpenProtocol (\r
1645 Controller,\r
1646 &gEfiPciIoProtocolGuid,\r
c52fa98c 1647 (VOID **) &PciIo,\r
913cb9dc 1648 This->DriverBindingHandle,\r
1649 Controller,\r
1650 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1651 );\r
1652\r
1653 if (EFI_ERROR (Status)) {\r
1654 return Status;\r
1655 }\r
1656\r
37623a5c 1657 //\r
1658 // Open Device Path Protocol for on USB host controller\r
1659 //\r
1660 HcDevicePath = NULL;\r
1661 Status = gBS->OpenProtocol (\r
1662 Controller,\r
1663 &gEfiDevicePathProtocolGuid,\r
1664 (VOID **) &HcDevicePath,\r
1665 This->DriverBindingHandle,\r
1666 Controller,\r
1667 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1668 );\r
1669\r
6a6d955c 1670 PciAttributesSaved = FALSE;\r
68246fa8 1671 //\r
1672 // Save original PCI attributes\r
1673 //\r
1674 Status = PciIo->Attributes (\r
1675 PciIo,\r
1676 EfiPciIoAttributeOperationGet,\r
1677 0,\r
1678 &OriginalPciAttributes\r
1679 );\r
1680\r
1681 if (EFI_ERROR (Status)) {\r
6a6d955c 1682 goto CLOSE_PCIIO;\r
68246fa8 1683 }\r
6a6d955c 1684 PciAttributesSaved = TRUE;\r
68246fa8 1685\r
f0a83bb3
LG
1686 //\r
1687 // Robustnesss improvement such as for UoL\r
1688 // Default is not required.\r
1689 //\r
cc582cff 1690 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
dd4047a5 1691 UhciTurnOffUsbEmulation (PciIo);\r
1692 }\r
913cb9dc 1693\r
1694 Status = PciIo->Attributes (\r
1695 PciIo,\r
96f6af14
LG
1696 EfiPciIoAttributeOperationSupported,\r
1697 0,\r
1698 &Supports\r
913cb9dc 1699 );\r
96f6af14
LG
1700 if (!EFI_ERROR (Status)) {\r
1701 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1702 Status = PciIo->Attributes (\r
1703 PciIo,\r
1704 EfiPciIoAttributeOperationEnable,\r
1705 Supports,\r
1706 NULL\r
1707 );\r
1708 }\r
913cb9dc 1709\r
1710 if (EFI_ERROR (Status)) {\r
1711 goto CLOSE_PCIIO;\r
1712 }\r
1713\r
37623a5c 1714 Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);\r
913cb9dc 1715\r
1716 if (Uhc == NULL) {\r
1717 Status = EFI_OUT_OF_RESOURCES;\r
1718 goto CLOSE_PCIIO;\r
1719 }\r
1720\r
1721 //\r
1722 // Allocate and Init Host Controller's Frame List Entry\r
1723 //\r
1724 Status = UhciInitFrameList (Uhc);\r
1725\r
1726 if (EFI_ERROR (Status)) {\r
1727 Status = EFI_OUT_OF_RESOURCES;\r
1728 goto FREE_UHC;\r
1729 }\r
1730\r
1731 Status = gBS->SetTimer (\r
1732 Uhc->AsyncIntMonitor,\r
1733 TimerPeriodic,\r
41e8ff27 1734 UHC_ASYNC_POLL_INTERVAL\r
913cb9dc 1735 );\r
1736\r
1737 if (EFI_ERROR (Status)) {\r
1738 goto FREE_UHC;\r
1739 }\r
1740\r
1741 //\r
ea5632e5 1742 // Install USB2_HC_PROTOCOL\r
913cb9dc 1743 //\r
1744 Status = gBS->InstallMultipleProtocolInterfaces (\r
1745 &Controller,\r
913cb9dc 1746 &gEfiUsb2HcProtocolGuid,\r
1747 &Uhc->Usb2Hc,\r
1748 NULL\r
1749 );\r
1750\r
1751 if (EFI_ERROR (Status)) {\r
1752 goto FREE_UHC;\r
1753 }\r
1754\r
0428a6cb 1755 //\r
1756 // Create event to stop the HC when exit boot service.\r
1757 //\r
1758 Status = gBS->CreateEventEx (\r
1759 EVT_NOTIFY_SIGNAL,\r
1760 TPL_NOTIFY,\r
1761 UhcExitBootService,\r
1762 Uhc,\r
1763 &gEfiEventExitBootServicesGuid,\r
1764 &Uhc->ExitBootServiceEvent\r
1765 );\r
1766 if (EFI_ERROR (Status)) {\r
1767 goto UNINSTALL_USBHC;\r
1768 }\r
1769\r
913cb9dc 1770 //\r
1771 // Install the component name protocol\r
1772 //\r
1773 Uhc->CtrlNameTable = NULL;\r
1774\r
f527bce3 1775 AddUnicodeString2 (\r
913cb9dc 1776 "eng",\r
1777 gUhciComponentName.SupportedLanguages,\r
1778 &Uhc->CtrlNameTable,\r
f527bce3 1779 L"Usb Universal Host Controller",\r
1780 TRUE\r
913cb9dc 1781 );\r
f527bce3 1782 AddUnicodeString2 (\r
1783 "en",\r
1784 gUhciComponentName2.SupportedLanguages,\r
1785 &Uhc->CtrlNameTable,\r
1786 L"Usb Universal Host Controller",\r
1787 FALSE\r
1788 );\r
1789\r
913cb9dc 1790\r
1791 //\r
1792 // Start the UHCI hardware, also set its reclamation point to 64 bytes\r
1793 //\r
1794 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);\r
1795\r
1796 return EFI_SUCCESS;\r
0428a6cb 1797 \r
1798UNINSTALL_USBHC:\r
1799 gBS->UninstallMultipleProtocolInterfaces (\r
1800 Controller,\r
1801 &gEfiUsb2HcProtocolGuid,\r
1802 &Uhc->Usb2Hc,\r
1803 NULL\r
1804 );\r
913cb9dc 1805\r
1806FREE_UHC:\r
1807 UhciFreeDev (Uhc);\r
1808\r
1809CLOSE_PCIIO:\r
a92d4e8a 1810 if (PciAttributesSaved) {\r
6a6d955c 1811 //\r
1812 // Restore original PCI attributes\r
1813 //\r
1814 PciIo->Attributes (\r
1815 PciIo,\r
1816 EfiPciIoAttributeOperationSet,\r
1817 OriginalPciAttributes,\r
1818 NULL\r
1819 );\r
1820 }\r
68246fa8 1821\r
913cb9dc 1822 gBS->CloseProtocol (\r
1823 Controller,\r
1824 &gEfiPciIoProtocolGuid,\r
1825 This->DriverBindingHandle,\r
1826 Controller\r
1827 );\r
1828\r
1829 return Status;\r
1830}\r
1831\r
1832\r
1833/**\r
1834 Stop this driver on ControllerHandle. Support stoping any child handles\r
1835 created by this driver.\r
1836\r
1837 @param This Protocol instance pointer.\r
ab6495ea 1838 @param Controller Handle of device to stop driver on.\r
1839 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
913cb9dc 1840 @param ChildHandleBuffer List of handles for the children we need to stop.\r
1841\r
1842 @return EFI_SUCCESS\r
1843 @return others\r
1844\r
1845**/\r
1846EFI_STATUS\r
1847EFIAPI\r
1848UhciDriverBindingStop (\r
1849 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1850 IN EFI_HANDLE Controller,\r
1851 IN UINTN NumberOfChildren,\r
1852 IN EFI_HANDLE *ChildHandleBuffer\r
1853 )\r
1854{\r
913cb9dc 1855 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1856 EFI_STATUS Status;\r
1857\r
ea5632e5 1858 Status = gBS->OpenProtocol (\r
913cb9dc 1859 Controller,\r
1860 &gEfiUsb2HcProtocolGuid,\r
c52fa98c 1861 (VOID **) &Usb2Hc,\r
913cb9dc 1862 This->DriverBindingHandle,\r
1863 Controller,\r
1864 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1865 );\r
1866\r
1867 //\r
1868 // Test whether the Controller handler passed in is a valid\r
1869 // Usb controller handle that should be supported, if not,\r
1870 // return the error status directly\r
1871 //\r
1872 if (EFI_ERROR (Status)) {\r
1873 return Status;\r
1874 }\r
1875\r
ea5632e5 1876 UhciCleanDevUp (Controller, Usb2Hc);\r
913cb9dc 1877\r
1878 gBS->CloseProtocol (\r
1879 Controller,\r
1880 &gEfiPciIoProtocolGuid,\r
1881 This->DriverBindingHandle,\r
1882 Controller\r
1883 );\r
1884\r
1885 return EFI_SUCCESS;\r
1886}\r
1887\r