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