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