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