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