1 /** @file 2 The XHCI controller driver. 3 4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Xhci.h" 16 17 // 18 // Two arrays used to translate the XHCI port state (change) 19 // to the UEFI protocol's port state (change). 20 // 21 USB_PORT_STATE_MAP mUsbPortStateMap[] = { 22 {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION}, 23 {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE}, 24 {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT}, 25 {XHC_PORTSC_RESET, USB_PORT_STAT_RESET} 26 }; 27 28 USB_PORT_STATE_MAP mUsbPortChangeMap[] = { 29 {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION}, 30 {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE}, 31 {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT}, 32 {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET} 33 }; 34 35 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = { 36 {XHC_PORTSC_CSC, EfiUsbPortConnectChange}, 37 {XHC_PORTSC_PEC, EfiUsbPortEnableChange}, 38 {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange}, 39 {XHC_PORTSC_PRC, EfiUsbPortResetChange} 40 }; 41 42 USB_PORT_STATE_MAP mUsbHubPortStateMap[] = { 43 {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION}, 44 {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE}, 45 {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT}, 46 {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET} 47 }; 48 49 USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = { 50 {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION}, 51 {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE}, 52 {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT}, 53 {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET} 54 }; 55 56 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = { 57 {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange}, 58 {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange}, 59 {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange}, 60 {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange}, 61 {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange} 62 }; 63 64 EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = { 65 XhcDriverBindingSupported, 66 XhcDriverBindingStart, 67 XhcDriverBindingStop, 68 0x30, 69 NULL, 70 NULL 71 }; 72 73 // 74 // Template for Xhci's Usb2 Host Controller Protocol Instance. 75 // 76 EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = { 77 XhcGetCapability, 78 XhcReset, 79 XhcGetState, 80 XhcSetState, 81 XhcControlTransfer, 82 XhcBulkTransfer, 83 XhcAsyncInterruptTransfer, 84 XhcSyncInterruptTransfer, 85 XhcIsochronousTransfer, 86 XhcAsyncIsochronousTransfer, 87 XhcGetRootHubPortStatus, 88 XhcSetRootHubPortFeature, 89 XhcClearRootHubPortFeature, 90 0x3, 91 0x0 92 }; 93 94 /** 95 Retrieves the capability of root hub ports. 96 97 @param This The EFI_USB2_HC_PROTOCOL instance. 98 @param MaxSpeed Max speed supported by the controller. 99 @param PortNumber Number of the root hub ports. 100 @param Is64BitCapable Whether the controller supports 64-bit memory 101 addressing. 102 103 @retval EFI_SUCCESS Host controller capability were retrieved successfully. 104 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL. 105 106 **/ 107 EFI_STATUS 108 EFIAPI 109 XhcGetCapability ( 110 IN EFI_USB2_HC_PROTOCOL *This, 111 OUT UINT8 *MaxSpeed, 112 OUT UINT8 *PortNumber, 113 OUT UINT8 *Is64BitCapable 114 ) 115 { 116 USB_XHCI_INSTANCE *Xhc; 117 EFI_TPL OldTpl; 118 119 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) { 120 return EFI_INVALID_PARAMETER; 121 } 122 123 OldTpl = gBS->RaiseTPL (XHC_TPL); 124 125 Xhc = XHC_FROM_THIS (This); 126 *MaxSpeed = EFI_USB_SPEED_SUPER; 127 *PortNumber = (UINT8) (Xhc->HcSParams1.Data.MaxPorts); 128 *Is64BitCapable = (UINT8) (Xhc->HcCParams.Data.Ac64); 129 DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable)); 130 131 gBS->RestoreTPL (OldTpl); 132 133 return EFI_SUCCESS; 134 } 135 136 137 /** 138 Provides software reset for the USB host controller. 139 140 @param This This EFI_USB2_HC_PROTOCOL instance. 141 @param Attributes A bit mask of the reset operation to perform. 142 143 @retval EFI_SUCCESS The reset operation succeeded. 144 @retval EFI_INVALID_PARAMETER Attributes is not valid. 145 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is 146 not currently supported by the host controller. 147 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. 148 149 **/ 150 EFI_STATUS 151 EFIAPI 152 XhcReset ( 153 IN EFI_USB2_HC_PROTOCOL *This, 154 IN UINT16 Attributes 155 ) 156 { 157 USB_XHCI_INSTANCE *Xhc; 158 EFI_STATUS Status; 159 EFI_TPL OldTpl; 160 161 Xhc = XHC_FROM_THIS (This); 162 163 if (Xhc->DevicePath != NULL) { 164 // 165 // Report Status Code to indicate reset happens 166 // 167 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 168 EFI_PROGRESS_CODE, 169 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET), 170 Xhc->DevicePath 171 ); 172 } 173 174 OldTpl = gBS->RaiseTPL (XHC_TPL); 175 176 switch (Attributes) { 177 case EFI_USB_HC_RESET_GLOBAL: 178 // 179 // Flow through, same behavior as Host Controller Reset 180 // 181 case EFI_USB_HC_RESET_HOST_CONTROLLER: 182 if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) && 183 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0)) { 184 Status = EFI_SUCCESS; 185 goto ON_EXIT; 186 } 187 // 188 // Host Controller must be Halt when Reset it 189 // 190 if (!XhcIsHalt (Xhc)) { 191 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); 192 193 if (EFI_ERROR (Status)) { 194 Status = EFI_DEVICE_ERROR; 195 goto ON_EXIT; 196 } 197 } 198 199 Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT); 200 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR))); 201 202 if (EFI_ERROR (Status)) { 203 goto ON_EXIT; 204 } 205 // 206 // Clean up the asynchronous transfers, currently only 207 // interrupt supports asynchronous operation. 208 // 209 XhciDelAllAsyncIntTransfers (Xhc); 210 XhcFreeSched (Xhc); 211 212 XhcInitSched (Xhc); 213 break; 214 215 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG: 216 case EFI_USB_HC_RESET_HOST_WITH_DEBUG: 217 Status = EFI_UNSUPPORTED; 218 break; 219 220 default: 221 Status = EFI_INVALID_PARAMETER; 222 } 223 224 ON_EXIT: 225 DEBUG ((EFI_D_INFO, "XhcReset: status %r\n", Status)); 226 gBS->RestoreTPL (OldTpl); 227 228 return Status; 229 } 230 231 232 /** 233 Retrieve the current state of the USB host controller. 234 235 @param This This EFI_USB2_HC_PROTOCOL instance. 236 @param State Variable to return the current host controller 237 state. 238 239 @retval EFI_SUCCESS Host controller state was returned in State. 240 @retval EFI_INVALID_PARAMETER State is NULL. 241 @retval EFI_DEVICE_ERROR An error was encountered while attempting to 242 retrieve the host controller's current state. 243 244 **/ 245 EFI_STATUS 246 EFIAPI 247 XhcGetState ( 248 IN EFI_USB2_HC_PROTOCOL *This, 249 OUT EFI_USB_HC_STATE *State 250 ) 251 { 252 USB_XHCI_INSTANCE *Xhc; 253 EFI_TPL OldTpl; 254 255 if (State == NULL) { 256 return EFI_INVALID_PARAMETER; 257 } 258 259 OldTpl = gBS->RaiseTPL (XHC_TPL); 260 261 Xhc = XHC_FROM_THIS (This); 262 263 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) { 264 *State = EfiUsbHcStateHalt; 265 } else { 266 *State = EfiUsbHcStateOperational; 267 } 268 269 DEBUG ((EFI_D_INFO, "XhcGetState: current state %d\n", *State)); 270 gBS->RestoreTPL (OldTpl); 271 272 return EFI_SUCCESS; 273 } 274 275 /** 276 Sets the USB host controller to a specific state. 277 278 @param This This EFI_USB2_HC_PROTOCOL instance. 279 @param State The state of the host controller that will be set. 280 281 @retval EFI_SUCCESS The USB host controller was successfully placed 282 in the state specified by State. 283 @retval EFI_INVALID_PARAMETER State is invalid. 284 @retval EFI_DEVICE_ERROR Failed to set the state due to device error. 285 286 **/ 287 EFI_STATUS 288 EFIAPI 289 XhcSetState ( 290 IN EFI_USB2_HC_PROTOCOL *This, 291 IN EFI_USB_HC_STATE State 292 ) 293 { 294 USB_XHCI_INSTANCE *Xhc; 295 EFI_STATUS Status; 296 EFI_USB_HC_STATE CurState; 297 EFI_TPL OldTpl; 298 299 Status = XhcGetState (This, &CurState); 300 301 if (EFI_ERROR (Status)) { 302 return EFI_DEVICE_ERROR; 303 } 304 305 if (CurState == State) { 306 return EFI_SUCCESS; 307 } 308 309 OldTpl = gBS->RaiseTPL (XHC_TPL); 310 311 Xhc = XHC_FROM_THIS (This); 312 313 switch (State) { 314 case EfiUsbHcStateHalt: 315 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); 316 break; 317 318 case EfiUsbHcStateOperational: 319 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) { 320 Status = EFI_DEVICE_ERROR; 321 break; 322 } 323 324 // 325 // Software must not write a one to this field unless the host controller 326 // is in the Halted state. Doing so will yield undefined results. 327 // refers to Spec[XHCI1.0-2.3.1] 328 // 329 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) { 330 Status = EFI_DEVICE_ERROR; 331 break; 332 } 333 334 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT); 335 break; 336 337 case EfiUsbHcStateSuspend: 338 Status = EFI_UNSUPPORTED; 339 break; 340 341 default: 342 Status = EFI_INVALID_PARAMETER; 343 } 344 345 DEBUG ((EFI_D_INFO, "XhcSetState: status %r\n", Status)); 346 gBS->RestoreTPL (OldTpl); 347 348 return Status; 349 } 350 351 /** 352 Retrieves the current status of a USB root hub port. 353 354 @param This This EFI_USB2_HC_PROTOCOL instance. 355 @param PortNumber The root hub port to retrieve the state from. 356 This value is zero-based. 357 @param PortStatus Variable to receive the port state. 358 359 @retval EFI_SUCCESS The status of the USB root hub port specified. 360 by PortNumber was returned in PortStatus. 361 @retval EFI_INVALID_PARAMETER PortNumber is invalid. 362 @retval EFI_DEVICE_ERROR Can't read register. 363 364 **/ 365 EFI_STATUS 366 EFIAPI 367 XhcGetRootHubPortStatus ( 368 IN EFI_USB2_HC_PROTOCOL *This, 369 IN UINT8 PortNumber, 370 OUT EFI_USB_PORT_STATUS *PortStatus 371 ) 372 { 373 USB_XHCI_INSTANCE *Xhc; 374 UINT32 Offset; 375 UINT32 State; 376 UINT32 TotalPort; 377 UINTN Index; 378 UINTN MapSize; 379 EFI_STATUS Status; 380 USB_DEV_ROUTE ParentRouteChart; 381 EFI_TPL OldTpl; 382 383 if (PortStatus == NULL) { 384 return EFI_INVALID_PARAMETER; 385 } 386 387 OldTpl = gBS->RaiseTPL (XHC_TPL); 388 389 Xhc = XHC_FROM_THIS (This); 390 Status = EFI_SUCCESS; 391 392 TotalPort = Xhc->HcSParams1.Data.MaxPorts; 393 394 if (PortNumber >= TotalPort) { 395 Status = EFI_INVALID_PARAMETER; 396 goto ON_EXIT; 397 } 398 399 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber)); 400 PortStatus->PortStatus = 0; 401 PortStatus->PortChangeStatus = 0; 402 403 State = XhcReadOpReg (Xhc, Offset); 404 405 // 406 // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device. 407 // 408 switch ((State & XHC_PORTSC_PS) >> 10) { 409 case 2: 410 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; 411 break; 412 413 case 3: 414 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; 415 break; 416 417 case 4: 418 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED; 419 break; 420 421 default: 422 break; 423 } 424 425 // 426 // Convert the XHCI port/port change state to UEFI status 427 // 428 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP); 429 430 for (Index = 0; Index < MapSize; Index++) { 431 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) { 432 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState); 433 } 434 } 435 // 436 // Bit5~8 reflects its current link state. 437 // 438 if ((State & XHC_PORTSC_PLS) >> 5 == 3) { 439 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; 440 } 441 442 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP); 443 444 for (Index = 0; Index < MapSize; Index++) { 445 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) { 446 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState); 447 } 448 } 449 450 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP); 451 452 for (Index = 0; Index < MapSize; Index++) { 453 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) { 454 XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector); 455 } 456 } 457 458 // 459 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached. 460 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub. 461 // 462 ParentRouteChart.Dword = 0; 463 XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus); 464 465 ON_EXIT: 466 gBS->RestoreTPL (OldTpl); 467 return Status; 468 } 469 470 471 /** 472 Sets a feature for the specified root hub port. 473 474 @param This This EFI_USB2_HC_PROTOCOL instance. 475 @param PortNumber Root hub port to set. 476 @param PortFeature Feature to set. 477 478 @retval EFI_SUCCESS The feature specified by PortFeature was set. 479 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 480 @retval EFI_DEVICE_ERROR Can't read register. 481 482 **/ 483 EFI_STATUS 484 EFIAPI 485 XhcSetRootHubPortFeature ( 486 IN EFI_USB2_HC_PROTOCOL *This, 487 IN UINT8 PortNumber, 488 IN EFI_USB_PORT_FEATURE PortFeature 489 ) 490 { 491 USB_XHCI_INSTANCE *Xhc; 492 UINT32 Offset; 493 UINT32 State; 494 UINT32 TotalPort; 495 EFI_STATUS Status; 496 EFI_TPL OldTpl; 497 498 OldTpl = gBS->RaiseTPL (XHC_TPL); 499 500 Xhc = XHC_FROM_THIS (This); 501 Status = EFI_SUCCESS; 502 503 TotalPort = (Xhc->HcSParams1.Data.MaxPorts); 504 505 if (PortNumber >= TotalPort) { 506 Status = EFI_INVALID_PARAMETER; 507 goto ON_EXIT; 508 } 509 510 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber)); 511 State = XhcReadOpReg (Xhc, Offset); 512 513 // 514 // Mask off the port status change bits, these bits are 515 // write clean bit 516 // 517 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23); 518 519 switch (PortFeature) { 520 case EfiUsbPortEnable: 521 // 522 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag. 523 // A port may be disabled by software writing a '1' to this flag. 524 // 525 Status = EFI_SUCCESS; 526 break; 527 528 case EfiUsbPortSuspend: 529 State |= XHC_PORTSC_LWS; 530 XhcWriteOpReg (Xhc, Offset, State); 531 State &= ~XHC_PORTSC_PLS; 532 State |= (3 << 5) ; 533 XhcWriteOpReg (Xhc, Offset, State); 534 break; 535 536 case EfiUsbPortReset: 537 DEBUG ((EFI_D_INFO, "XhcUsbPortReset!\n")); 538 // 539 // Make sure Host Controller not halt before reset it 540 // 541 if (XhcIsHalt (Xhc)) { 542 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT); 543 544 if (EFI_ERROR (Status)) { 545 DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status)); 546 break; 547 } 548 } 549 550 // 551 // 4.3.1 Resetting a Root Hub Port 552 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'. 553 // 554 State |= XHC_PORTSC_RESET; 555 XhcWriteOpReg (Xhc, Offset, State); 556 XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT); 557 break; 558 559 case EfiUsbPortPower: 560 // 561 // Not supported, ignore the operation 562 // 563 Status = EFI_SUCCESS; 564 break; 565 566 case EfiUsbPortOwner: 567 // 568 // XHCI root hub port don't has the owner bit, ignore the operation 569 // 570 Status = EFI_SUCCESS; 571 break; 572 573 default: 574 Status = EFI_INVALID_PARAMETER; 575 } 576 577 ON_EXIT: 578 DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature: status %r\n", Status)); 579 gBS->RestoreTPL (OldTpl); 580 581 return Status; 582 } 583 584 585 /** 586 Clears a feature for the specified root hub port. 587 588 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance. 589 @param PortNumber Specifies the root hub port whose feature is 590 requested to be cleared. 591 @param PortFeature Indicates the feature selector associated with the 592 feature clear request. 593 594 @retval EFI_SUCCESS The feature specified by PortFeature was cleared 595 for the USB root hub port specified by PortNumber. 596 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 597 @retval EFI_DEVICE_ERROR Can't read register. 598 599 **/ 600 EFI_STATUS 601 EFIAPI 602 XhcClearRootHubPortFeature ( 603 IN EFI_USB2_HC_PROTOCOL *This, 604 IN UINT8 PortNumber, 605 IN EFI_USB_PORT_FEATURE PortFeature 606 ) 607 { 608 USB_XHCI_INSTANCE *Xhc; 609 UINT32 Offset; 610 UINT32 State; 611 UINT32 TotalPort; 612 EFI_STATUS Status; 613 EFI_TPL OldTpl; 614 615 OldTpl = gBS->RaiseTPL (XHC_TPL); 616 617 Xhc = XHC_FROM_THIS (This); 618 Status = EFI_SUCCESS; 619 620 TotalPort = (Xhc->HcSParams1.Data.MaxPorts); 621 622 if (PortNumber >= TotalPort) { 623 Status = EFI_INVALID_PARAMETER; 624 goto ON_EXIT; 625 } 626 627 Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber); 628 629 // 630 // Mask off the port status change bits, these bits are 631 // write clean bit 632 // 633 State = XhcReadOpReg (Xhc, Offset); 634 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23); 635 636 switch (PortFeature) { 637 case EfiUsbPortEnable: 638 // 639 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag. 640 // A port may be disabled by software writing a '1' to this flag. 641 // 642 State |= XHC_PORTSC_PED; 643 State &= ~XHC_PORTSC_RESET; 644 XhcWriteOpReg (Xhc, Offset, State); 645 break; 646 647 case EfiUsbPortSuspend: 648 State |= XHC_PORTSC_LWS; 649 XhcWriteOpReg (Xhc, Offset, State); 650 State &= ~XHC_PORTSC_PLS; 651 XhcWriteOpReg (Xhc, Offset, State); 652 break; 653 654 case EfiUsbPortReset: 655 // 656 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status: 657 // Register bits indicate status when read, a clear bit may be set by 658 // writing a '1'. Writing a '0' to RW1S bits has no effect. 659 // 660 break; 661 662 case EfiUsbPortOwner: 663 // 664 // XHCI root hub port don't has the owner bit, ignore the operation 665 // 666 break; 667 668 case EfiUsbPortConnectChange: 669 // 670 // Clear connect status change 671 // 672 State |= XHC_PORTSC_CSC; 673 XhcWriteOpReg (Xhc, Offset, State); 674 break; 675 676 case EfiUsbPortEnableChange: 677 // 678 // Clear enable status change 679 // 680 State |= XHC_PORTSC_PEC; 681 XhcWriteOpReg (Xhc, Offset, State); 682 break; 683 684 case EfiUsbPortOverCurrentChange: 685 // 686 // Clear PortOverCurrent change 687 // 688 State |= XHC_PORTSC_OCC; 689 XhcWriteOpReg (Xhc, Offset, State); 690 break; 691 692 case EfiUsbPortResetChange: 693 // 694 // Clear Port Reset change 695 // 696 State |= XHC_PORTSC_PRC; 697 XhcWriteOpReg (Xhc, Offset, State); 698 break; 699 700 case EfiUsbPortPower: 701 case EfiUsbPortSuspendChange: 702 // 703 // Not supported or not related operation 704 // 705 break; 706 707 default: 708 Status = EFI_INVALID_PARAMETER; 709 break; 710 } 711 712 ON_EXIT: 713 DEBUG ((EFI_D_INFO, "XhcClearRootHubPortFeature: status %r\n", Status)); 714 gBS->RestoreTPL (OldTpl); 715 716 return Status; 717 } 718 719 720 /** 721 Submits control transfer to a target USB device. 722 723 @param This This EFI_USB2_HC_PROTOCOL instance. 724 @param DeviceAddress The target device address. 725 @param DeviceSpeed Target device speed. 726 @param MaximumPacketLength Maximum packet size the default control transfer 727 endpoint is capable of sending or receiving. 728 @param Request USB device request to send. 729 @param TransferDirection Specifies the data direction for the data stage 730 @param Data Data buffer to be transmitted or received from USB 731 device. 732 @param DataLength The size (in bytes) of the data buffer. 733 @param Timeout Indicates the maximum timeout, in millisecond. 734 @param Translator Transaction translator to be used by this device. 735 @param TransferResult Return the result of this control transfer. 736 737 @retval EFI_SUCCESS Transfer was completed successfully. 738 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. 739 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 740 @retval EFI_TIMEOUT Transfer failed due to timeout. 741 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. 742 743 **/ 744 EFI_STATUS 745 EFIAPI 746 XhcControlTransfer ( 747 IN EFI_USB2_HC_PROTOCOL *This, 748 IN UINT8 DeviceAddress, 749 IN UINT8 DeviceSpeed, 750 IN UINTN MaximumPacketLength, 751 IN EFI_USB_DEVICE_REQUEST *Request, 752 IN EFI_USB_DATA_DIRECTION TransferDirection, 753 IN OUT VOID *Data, 754 IN OUT UINTN *DataLength, 755 IN UINTN Timeout, 756 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 757 OUT UINT32 *TransferResult 758 ) 759 { 760 USB_XHCI_INSTANCE *Xhc; 761 URB *Urb; 762 UINT8 Endpoint; 763 UINT8 Index; 764 UINT8 DescriptorType; 765 UINT8 SlotId; 766 UINT8 TTT; 767 UINT8 MTT; 768 UINT32 MaxPacket0; 769 EFI_USB_HUB_DESCRIPTOR *HubDesc; 770 EFI_TPL OldTpl; 771 EFI_STATUS Status; 772 EFI_STATUS RecoveryStatus; 773 UINTN MapSize; 774 EFI_USB_PORT_STATUS PortStatus; 775 UINT32 State; 776 EFI_USB_DEVICE_REQUEST ClearPortRequest; 777 UINTN Len; 778 779 // 780 // Validate parameters 781 // 782 if ((Request == NULL) || (TransferResult == NULL)) { 783 return EFI_INVALID_PARAMETER; 784 } 785 786 if ((TransferDirection != EfiUsbDataIn) && 787 (TransferDirection != EfiUsbDataOut) && 788 (TransferDirection != EfiUsbNoData)) { 789 return EFI_INVALID_PARAMETER; 790 } 791 792 if ((TransferDirection == EfiUsbNoData) && 793 ((Data != NULL) || (*DataLength != 0))) { 794 return EFI_INVALID_PARAMETER; 795 } 796 797 if ((TransferDirection != EfiUsbNoData) && 798 ((Data == NULL) || (*DataLength == 0))) { 799 return EFI_INVALID_PARAMETER; 800 } 801 802 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && 803 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) && 804 (MaximumPacketLength != 512) 805 ) { 806 return EFI_INVALID_PARAMETER; 807 } 808 809 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) { 810 return EFI_INVALID_PARAMETER; 811 } 812 813 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) { 814 return EFI_INVALID_PARAMETER; 815 } 816 817 OldTpl = gBS->RaiseTPL (XHC_TPL); 818 819 Xhc = XHC_FROM_THIS (This); 820 821 Status = EFI_DEVICE_ERROR; 822 *TransferResult = EFI_USB_ERR_SYSTEM; 823 Len = 0; 824 825 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) { 826 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n")); 827 goto ON_EXIT; 828 } 829 830 // 831 // Check if the device is still enabled before every transaction. 832 // 833 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress); 834 if (SlotId == 0) { 835 goto ON_EXIT; 836 } 837 838 // 839 // Hook the Set_Address request from UsbBus. 840 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd. 841 // 842 if ((Request->Request == USB_REQ_SET_ADDRESS) && 843 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) { 844 // 845 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly. 846 // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer(). 847 // 848 for (Index = 0; Index < 255; Index++) { 849 if (!Xhc->UsbDevContext[Index + 1].Enabled && 850 (Xhc->UsbDevContext[Index + 1].SlotId == 0) && 851 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) { 852 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0; 853 } 854 } 855 856 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) { 857 Status = EFI_DEVICE_ERROR; 858 goto ON_EXIT; 859 } 860 // 861 // The actual device address has been assigned by XHCI during initializing the device slot. 862 // So we just need establish the mapping relationship between the device address requested from UsbBus 863 // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface 864 // can find out the actual device address by it. 865 // 866 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value; 867 Status = EFI_SUCCESS; 868 goto ON_EXIT; 869 } 870 871 // 872 // Create a new URB, insert it into the asynchronous 873 // schedule list, then poll the execution status. 874 // Note that we encode the direction in address although default control 875 // endpoint is bidirectional. XhcCreateUrb expects this 876 // combination of Ep addr and its direction. 877 // 878 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0)); 879 Urb = XhcCreateUrb ( 880 Xhc, 881 DeviceAddress, 882 Endpoint, 883 DeviceSpeed, 884 MaximumPacketLength, 885 XHC_CTRL_TRANSFER, 886 Request, 887 Data, 888 *DataLength, 889 NULL, 890 NULL 891 ); 892 893 if (Urb == NULL) { 894 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: failed to create URB")); 895 Status = EFI_OUT_OF_RESOURCES; 896 goto ON_EXIT; 897 } 898 899 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); 900 901 // 902 // Get the status from URB. The result is updated in XhcCheckUrbResult 903 // which is called by XhcExecTransfer 904 // 905 *TransferResult = Urb->Result; 906 *DataLength = Urb->Completed; 907 908 if (Status == EFI_TIMEOUT) { 909 // 910 // The transfer timed out. Abort the transfer by dequeueing of the TD. 911 // 912 RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb); 913 if (EFI_ERROR(RecoveryStatus)) { 914 DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n")); 915 } 916 goto FREE_URB; 917 } else { 918 if (*TransferResult == EFI_USB_NOERROR) { 919 Status = EFI_SUCCESS; 920 } else if (*TransferResult == EFI_USB_ERR_STALL) { 921 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb); 922 if (EFI_ERROR (RecoveryStatus)) { 923 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n")); 924 } 925 Status = EFI_DEVICE_ERROR; 926 goto FREE_URB; 927 } else { 928 goto FREE_URB; 929 } 930 } 931 932 Xhc->PciIo->Flush (Xhc->PciIo); 933 934 if (Urb->DataMap != NULL) { 935 Status = Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap); 936 ASSERT_EFI_ERROR (Status); 937 if (EFI_ERROR (Status)) { 938 Status = EFI_DEVICE_ERROR; 939 goto FREE_URB; 940 } 941 } 942 943 // 944 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint. 945 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub. 946 // Hook Set_Config request from UsbBus as we need configure device endpoint. 947 // 948 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) && 949 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) || 950 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) { 951 DescriptorType = (UINT8)(Request->Value >> 8); 952 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) { 953 ASSERT (Data != NULL); 954 // 955 // Store a copy of device scriptor as hub device need this info to configure endpoint. 956 // 957 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength); 958 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) { 959 // 960 // If it's a usb3.0 device, then its max packet size is a 2^n. 961 // 962 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0; 963 } else { 964 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0; 965 } 966 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *)); 967 if (Xhc->HcCParams.Data.Csz == 0) { 968 Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0); 969 } else { 970 Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0); 971 } 972 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) { 973 ASSERT (Data != NULL); 974 if (*DataLength == ((UINT16 *)Data)[1]) { 975 // 976 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd. 977 // 978 Index = (UINT8)Request->Value; 979 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations); 980 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength); 981 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength); 982 // 983 // Default to use AlternateSetting 0 for all interfaces. 984 // 985 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8)); 986 } 987 } else if (((DescriptorType == USB_DESC_TYPE_HUB) || 988 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) { 989 ASSERT (Data != NULL); 990 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data; 991 ASSERT (HubDesc->NumPorts <= 15); 992 // 993 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT. 994 // 995 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5); 996 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) { 997 // 998 // Don't support multi-TT feature for super speed hub now. 999 // 1000 MTT = 0; 1001 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n")); 1002 } else { 1003 MTT = 0; 1004 } 1005 1006 if (Xhc->HcCParams.Data.Csz == 0) { 1007 Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT); 1008 } else { 1009 Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT); 1010 } 1011 } 1012 } else if ((Request->Request == USB_REQ_SET_CONFIG) && 1013 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) { 1014 // 1015 // Hook Set_Config request from UsbBus as we need configure device endpoint. 1016 // 1017 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { 1018 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) { 1019 if (Xhc->HcCParams.Data.Csz == 0) { 1020 Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]); 1021 } else { 1022 Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]); 1023 } 1024 break; 1025 } 1026 } 1027 } else if ((Request->Request == USB_REQ_SET_INTERFACE) && 1028 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE))) { 1029 // 1030 // Hook Set_Interface request from UsbBus as we need configure interface setting. 1031 // Request->Value indicates AlterlateSetting to set 1032 // Request->Index indicates Interface to set 1033 // 1034 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] != (UINT8) Request->Value) { 1035 if (Xhc->HcCParams.Data.Csz == 0) { 1036 Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request); 1037 } else { 1038 Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request); 1039 } 1040 } 1041 } else if ((Request->Request == USB_REQ_GET_STATUS) && 1042 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) { 1043 ASSERT (Data != NULL); 1044 // 1045 // Hook Get_Status request from UsbBus to keep track of the port status change. 1046 // 1047 State = *(UINT32 *)Data; 1048 PortStatus.PortStatus = 0; 1049 PortStatus.PortChangeStatus = 0; 1050 1051 if (DeviceSpeed == EFI_USB_SPEED_SUPER) { 1052 // 1053 // For super speed hub, its bit10~12 presents the attached device speed. 1054 // 1055 if ((State & XHC_PORTSC_PS) >> 10 == 0) { 1056 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED; 1057 } 1058 } else { 1059 // 1060 // For high or full/low speed hub, its bit9~10 presents the attached device speed. 1061 // 1062 if (XHC_BIT_IS_SET (State, BIT9)) { 1063 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED; 1064 } else if (XHC_BIT_IS_SET (State, BIT10)) { 1065 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED; 1066 } 1067 } 1068 1069 // 1070 // Convert the XHCI port/port change state to UEFI status 1071 // 1072 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP); 1073 for (Index = 0; Index < MapSize; Index++) { 1074 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) { 1075 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState); 1076 } 1077 } 1078 1079 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP); 1080 for (Index = 0; Index < MapSize; Index++) { 1081 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) { 1082 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState); 1083 } 1084 } 1085 1086 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP); 1087 1088 for (Index = 0; Index < MapSize; Index++) { 1089 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) { 1090 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST)); 1091 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER); 1092 ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE; 1093 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector; 1094 ClearPortRequest.Index = Request->Index; 1095 ClearPortRequest.Length = 0; 1096 1097 XhcControlTransfer ( 1098 This, 1099 DeviceAddress, 1100 DeviceSpeed, 1101 MaximumPacketLength, 1102 &ClearPortRequest, 1103 EfiUsbNoData, 1104 NULL, 1105 &Len, 1106 Timeout, 1107 Translator, 1108 TransferResult 1109 ); 1110 } 1111 } 1112 1113 XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus); 1114 1115 *(UINT32 *)Data = *(UINT32*)&PortStatus; 1116 } 1117 1118 FREE_URB: 1119 FreePool (Urb); 1120 1121 ON_EXIT: 1122 1123 if (EFI_ERROR (Status)) { 1124 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); 1125 } 1126 1127 gBS->RestoreTPL (OldTpl); 1128 1129 return Status; 1130 } 1131 1132 1133 /** 1134 Submits bulk transfer to a bulk endpoint of a USB device. 1135 1136 @param This This EFI_USB2_HC_PROTOCOL instance. 1137 @param DeviceAddress Target device address. 1138 @param EndPointAddress Endpoint number and its direction in bit 7. 1139 @param DeviceSpeed Device speed, Low speed device doesn't support bulk 1140 transfer. 1141 @param MaximumPacketLength Maximum packet size the endpoint is capable of 1142 sending or receiving. 1143 @param DataBuffersNumber Number of data buffers prepared for the transfer. 1144 @param Data Array of pointers to the buffers of data to transmit 1145 from or receive into. 1146 @param DataLength The lenght of the data buffer. 1147 @param DataToggle On input, the initial data toggle for the transfer; 1148 On output, it is updated to to next data toggle to 1149 use of the subsequent bulk transfer. 1150 @param Timeout Indicates the maximum time, in millisecond, which 1151 the transfer is allowed to complete. 1152 @param Translator A pointr to the transaction translator data. 1153 @param TransferResult A pointer to the detailed result information of the 1154 bulk transfer. 1155 1156 @retval EFI_SUCCESS The transfer was completed successfully. 1157 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. 1158 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 1159 @retval EFI_TIMEOUT The transfer failed due to timeout. 1160 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. 1161 1162 **/ 1163 EFI_STATUS 1164 EFIAPI 1165 XhcBulkTransfer ( 1166 IN EFI_USB2_HC_PROTOCOL *This, 1167 IN UINT8 DeviceAddress, 1168 IN UINT8 EndPointAddress, 1169 IN UINT8 DeviceSpeed, 1170 IN UINTN MaximumPacketLength, 1171 IN UINT8 DataBuffersNumber, 1172 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], 1173 IN OUT UINTN *DataLength, 1174 IN OUT UINT8 *DataToggle, 1175 IN UINTN Timeout, 1176 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1177 OUT UINT32 *TransferResult 1178 ) 1179 { 1180 USB_XHCI_INSTANCE *Xhc; 1181 URB *Urb; 1182 UINT8 SlotId; 1183 EFI_STATUS Status; 1184 EFI_STATUS RecoveryStatus; 1185 EFI_TPL OldTpl; 1186 1187 // 1188 // Validate the parameters 1189 // 1190 if ((DataLength == NULL) || (*DataLength == 0) || 1191 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) { 1192 return EFI_INVALID_PARAMETER; 1193 } 1194 1195 if ((*DataToggle != 0) && (*DataToggle != 1)) { 1196 return EFI_INVALID_PARAMETER; 1197 } 1198 1199 if ((DeviceSpeed == EFI_USB_SPEED_LOW) || 1200 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || 1201 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) || 1202 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024))) { 1203 return EFI_INVALID_PARAMETER; 1204 } 1205 1206 OldTpl = gBS->RaiseTPL (XHC_TPL); 1207 1208 Xhc = XHC_FROM_THIS (This); 1209 1210 *TransferResult = EFI_USB_ERR_SYSTEM; 1211 Status = EFI_DEVICE_ERROR; 1212 1213 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) { 1214 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: HC is halted\n")); 1215 goto ON_EXIT; 1216 } 1217 1218 // 1219 // Check if the device is still enabled before every transaction. 1220 // 1221 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress); 1222 if (SlotId == 0) { 1223 goto ON_EXIT; 1224 } 1225 1226 // 1227 // Create a new URB, insert it into the asynchronous 1228 // schedule list, then poll the execution status. 1229 // 1230 Urb = XhcCreateUrb ( 1231 Xhc, 1232 DeviceAddress, 1233 EndPointAddress, 1234 DeviceSpeed, 1235 MaximumPacketLength, 1236 XHC_BULK_TRANSFER, 1237 NULL, 1238 Data[0], 1239 *DataLength, 1240 NULL, 1241 NULL 1242 ); 1243 1244 if (Urb == NULL) { 1245 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n")); 1246 Status = EFI_OUT_OF_RESOURCES; 1247 goto ON_EXIT; 1248 } 1249 1250 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); 1251 1252 *TransferResult = Urb->Result; 1253 *DataLength = Urb->Completed; 1254 1255 if (Status == EFI_TIMEOUT) { 1256 // 1257 // The transfer timed out. Abort the transfer by dequeueing of the TD. 1258 // 1259 RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb); 1260 if (EFI_ERROR(RecoveryStatus)) { 1261 DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n")); 1262 } 1263 } else { 1264 if (*TransferResult == EFI_USB_NOERROR) { 1265 Status = EFI_SUCCESS; 1266 } else if (*TransferResult == EFI_USB_ERR_STALL) { 1267 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb); 1268 if (EFI_ERROR (RecoveryStatus)) { 1269 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n")); 1270 } 1271 Status = EFI_DEVICE_ERROR; 1272 } 1273 } 1274 1275 Xhc->PciIo->Flush (Xhc->PciIo); 1276 XhcFreeUrb (Xhc, Urb); 1277 1278 ON_EXIT: 1279 1280 if (EFI_ERROR (Status)) { 1281 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); 1282 } 1283 gBS->RestoreTPL (OldTpl); 1284 1285 return Status; 1286 } 1287 1288 /** 1289 Submits an asynchronous interrupt transfer to an 1290 interrupt endpoint of a USB device. 1291 1292 @param This This EFI_USB2_HC_PROTOCOL instance. 1293 @param DeviceAddress Target device address. 1294 @param EndPointAddress Endpoint number and its direction encoded in bit 7 1295 @param DeviceSpeed Indicates device speed. 1296 @param MaximumPacketLength Maximum packet size the target endpoint is capable 1297 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt 1298 transfer If FALSE, to remove the specified 1299 asynchronous interrupt. 1300 @param DataToggle On input, the initial data toggle to use; on output, 1301 it is updated to indicate the next data toggle. 1302 @param PollingInterval The he interval, in milliseconds, that the transfer 1303 is polled. 1304 @param DataLength The length of data to receive at the rate specified 1305 by PollingInterval. 1306 @param Translator Transaction translator to use. 1307 @param CallBackFunction Function to call at the rate specified by 1308 PollingInterval. 1309 @param Context Context to CallBackFunction. 1310 1311 @retval EFI_SUCCESS The request has been successfully submitted or canceled. 1312 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 1313 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources. 1314 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. 1315 1316 **/ 1317 EFI_STATUS 1318 EFIAPI 1319 XhcAsyncInterruptTransfer ( 1320 IN EFI_USB2_HC_PROTOCOL *This, 1321 IN UINT8 DeviceAddress, 1322 IN UINT8 EndPointAddress, 1323 IN UINT8 DeviceSpeed, 1324 IN UINTN MaximumPacketLength, 1325 IN BOOLEAN IsNewTransfer, 1326 IN OUT UINT8 *DataToggle, 1327 IN UINTN PollingInterval, 1328 IN UINTN DataLength, 1329 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1330 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, 1331 IN VOID *Context OPTIONAL 1332 ) 1333 { 1334 USB_XHCI_INSTANCE *Xhc; 1335 URB *Urb; 1336 EFI_STATUS Status; 1337 UINT8 SlotId; 1338 UINT8 Index; 1339 UINT8 *Data; 1340 EFI_TPL OldTpl; 1341 1342 // 1343 // Validate parameters 1344 // 1345 if (!XHCI_IS_DATAIN (EndPointAddress)) { 1346 return EFI_INVALID_PARAMETER; 1347 } 1348 1349 if (IsNewTransfer) { 1350 if (DataLength == 0) { 1351 return EFI_INVALID_PARAMETER; 1352 } 1353 1354 if ((*DataToggle != 1) && (*DataToggle != 0)) { 1355 return EFI_INVALID_PARAMETER; 1356 } 1357 1358 if ((PollingInterval > 255) || (PollingInterval < 1)) { 1359 return EFI_INVALID_PARAMETER; 1360 } 1361 } 1362 1363 OldTpl = gBS->RaiseTPL (XHC_TPL); 1364 1365 Xhc = XHC_FROM_THIS (This); 1366 1367 // 1368 // Delete Async interrupt transfer request. 1369 // 1370 if (!IsNewTransfer) { 1371 // 1372 // The delete request may happen after device is detached. 1373 // 1374 for (Index = 0; Index < 255; Index++) { 1375 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) { 1376 break; 1377 } 1378 } 1379 1380 if (Index == 255) { 1381 Status = EFI_INVALID_PARAMETER; 1382 goto ON_EXIT; 1383 } 1384 1385 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress); 1386 DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status)); 1387 goto ON_EXIT; 1388 } 1389 1390 Status = EFI_SUCCESS; 1391 1392 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) { 1393 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n")); 1394 Status = EFI_DEVICE_ERROR; 1395 goto ON_EXIT; 1396 } 1397 1398 // 1399 // Check if the device is still enabled before every transaction. 1400 // 1401 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress); 1402 if (SlotId == 0) { 1403 goto ON_EXIT; 1404 } 1405 1406 Data = AllocateZeroPool (DataLength); 1407 1408 if (Data == NULL) { 1409 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n")); 1410 Status = EFI_OUT_OF_RESOURCES; 1411 goto ON_EXIT; 1412 } 1413 1414 Urb = XhcCreateUrb ( 1415 Xhc, 1416 DeviceAddress, 1417 EndPointAddress, 1418 DeviceSpeed, 1419 MaximumPacketLength, 1420 XHC_INT_TRANSFER_ASYNC, 1421 NULL, 1422 Data, 1423 DataLength, 1424 CallBackFunction, 1425 Context 1426 ); 1427 1428 if (Urb == NULL) { 1429 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n")); 1430 FreePool (Data); 1431 Status = EFI_OUT_OF_RESOURCES; 1432 goto ON_EXIT; 1433 } 1434 1435 InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList); 1436 // 1437 // Ring the doorbell 1438 // 1439 Status = RingIntTransferDoorBell (Xhc, Urb); 1440 1441 ON_EXIT: 1442 Xhc->PciIo->Flush (Xhc->PciIo); 1443 gBS->RestoreTPL (OldTpl); 1444 1445 return Status; 1446 } 1447 1448 1449 /** 1450 Submits synchronous interrupt transfer to an interrupt endpoint 1451 of a USB device. 1452 1453 @param This This EFI_USB2_HC_PROTOCOL instance. 1454 @param DeviceAddress Target device address. 1455 @param EndPointAddress Endpoint number and its direction encoded in bit 7 1456 @param DeviceSpeed Indicates device speed. 1457 @param MaximumPacketLength Maximum packet size the target endpoint is capable 1458 of sending or receiving. 1459 @param Data Buffer of data that will be transmitted to USB 1460 device or received from USB device. 1461 @param DataLength On input, the size, in bytes, of the data buffer; On 1462 output, the number of bytes transferred. 1463 @param DataToggle On input, the initial data toggle to use; on output, 1464 it is updated to indicate the next data toggle. 1465 @param Timeout Maximum time, in second, to complete. 1466 @param Translator Transaction translator to use. 1467 @param TransferResult Variable to receive the transfer result. 1468 1469 @return EFI_SUCCESS The transfer was completed successfully. 1470 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. 1471 @return EFI_INVALID_PARAMETER Some parameters are invalid. 1472 @return EFI_TIMEOUT The transfer failed due to timeout. 1473 @return EFI_DEVICE_ERROR The failed due to host controller or device error 1474 1475 **/ 1476 EFI_STATUS 1477 EFIAPI 1478 XhcSyncInterruptTransfer ( 1479 IN EFI_USB2_HC_PROTOCOL *This, 1480 IN UINT8 DeviceAddress, 1481 IN UINT8 EndPointAddress, 1482 IN UINT8 DeviceSpeed, 1483 IN UINTN MaximumPacketLength, 1484 IN OUT VOID *Data, 1485 IN OUT UINTN *DataLength, 1486 IN OUT UINT8 *DataToggle, 1487 IN UINTN Timeout, 1488 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1489 OUT UINT32 *TransferResult 1490 ) 1491 { 1492 USB_XHCI_INSTANCE *Xhc; 1493 URB *Urb; 1494 UINT8 SlotId; 1495 EFI_STATUS Status; 1496 EFI_STATUS RecoveryStatus; 1497 EFI_TPL OldTpl; 1498 1499 // 1500 // Validates parameters 1501 // 1502 if ((DataLength == NULL) || (*DataLength == 0) || 1503 (Data == NULL) || (TransferResult == NULL)) { 1504 return EFI_INVALID_PARAMETER; 1505 } 1506 1507 if ((*DataToggle != 1) && (*DataToggle != 0)) { 1508 return EFI_INVALID_PARAMETER; 1509 } 1510 1511 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) || 1512 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || 1513 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) { 1514 return EFI_INVALID_PARAMETER; 1515 } 1516 1517 OldTpl = gBS->RaiseTPL (XHC_TPL); 1518 1519 Xhc = XHC_FROM_THIS (This); 1520 1521 *TransferResult = EFI_USB_ERR_SYSTEM; 1522 Status = EFI_DEVICE_ERROR; 1523 1524 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) { 1525 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n")); 1526 goto ON_EXIT; 1527 } 1528 1529 // 1530 // Check if the device is still enabled before every transaction. 1531 // 1532 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress); 1533 if (SlotId == 0) { 1534 goto ON_EXIT; 1535 } 1536 1537 Urb = XhcCreateUrb ( 1538 Xhc, 1539 DeviceAddress, 1540 EndPointAddress, 1541 DeviceSpeed, 1542 MaximumPacketLength, 1543 XHC_INT_TRANSFER_SYNC, 1544 NULL, 1545 Data, 1546 *DataLength, 1547 NULL, 1548 NULL 1549 ); 1550 1551 if (Urb == NULL) { 1552 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n")); 1553 Status = EFI_OUT_OF_RESOURCES; 1554 goto ON_EXIT; 1555 } 1556 1557 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); 1558 1559 *TransferResult = Urb->Result; 1560 *DataLength = Urb->Completed; 1561 1562 if (Status == EFI_TIMEOUT) { 1563 // 1564 // The transfer timed out. Abort the transfer by dequeueing of the TD. 1565 // 1566 RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb); 1567 if (EFI_ERROR(RecoveryStatus)) { 1568 DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n")); 1569 } 1570 } else { 1571 if (*TransferResult == EFI_USB_NOERROR) { 1572 Status = EFI_SUCCESS; 1573 } else if (*TransferResult == EFI_USB_ERR_STALL) { 1574 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb); 1575 if (EFI_ERROR (RecoveryStatus)) { 1576 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n")); 1577 } 1578 Status = EFI_DEVICE_ERROR; 1579 } 1580 } 1581 1582 Xhc->PciIo->Flush (Xhc->PciIo); 1583 XhcFreeUrb (Xhc, Urb); 1584 1585 ON_EXIT: 1586 if (EFI_ERROR (Status)) { 1587 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); 1588 } 1589 gBS->RestoreTPL (OldTpl); 1590 1591 return Status; 1592 } 1593 1594 1595 /** 1596 Submits isochronous transfer to a target USB device. 1597 1598 @param This This EFI_USB2_HC_PROTOCOL instance. 1599 @param DeviceAddress Target device address. 1600 @param EndPointAddress End point address with its direction. 1601 @param DeviceSpeed Device speed, Low speed device doesn't support this 1602 type. 1603 @param MaximumPacketLength Maximum packet size that the endpoint is capable of 1604 sending or receiving. 1605 @param DataBuffersNumber Number of data buffers prepared for the transfer. 1606 @param Data Array of pointers to the buffers of data that will 1607 be transmitted to USB device or received from USB 1608 device. 1609 @param DataLength The size, in bytes, of the data buffer. 1610 @param Translator Transaction translator to use. 1611 @param TransferResult Variable to receive the transfer result. 1612 1613 @return EFI_UNSUPPORTED Isochronous transfer is unsupported. 1614 1615 **/ 1616 EFI_STATUS 1617 EFIAPI 1618 XhcIsochronousTransfer ( 1619 IN EFI_USB2_HC_PROTOCOL *This, 1620 IN UINT8 DeviceAddress, 1621 IN UINT8 EndPointAddress, 1622 IN UINT8 DeviceSpeed, 1623 IN UINTN MaximumPacketLength, 1624 IN UINT8 DataBuffersNumber, 1625 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], 1626 IN UINTN DataLength, 1627 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1628 OUT UINT32 *TransferResult 1629 ) 1630 { 1631 return EFI_UNSUPPORTED; 1632 } 1633 1634 1635 /** 1636 Submits Async isochronous transfer to a target USB device. 1637 1638 @param This This EFI_USB2_HC_PROTOCOL instance. 1639 @param DeviceAddress Target device address. 1640 @param EndPointAddress End point address with its direction. 1641 @param DeviceSpeed Device speed, Low speed device doesn't support this 1642 type. 1643 @param MaximumPacketLength Maximum packet size that the endpoint is capable of 1644 sending or receiving. 1645 @param DataBuffersNumber Number of data buffers prepared for the transfer. 1646 @param Data Array of pointers to the buffers of data that will 1647 be transmitted to USB device or received from USB 1648 device. 1649 @param DataLength The size, in bytes, of the data buffer. 1650 @param Translator Transaction translator to use. 1651 @param IsochronousCallBack Function to be called when the transfer complete. 1652 @param Context Context passed to the call back function as 1653 parameter. 1654 1655 @return EFI_UNSUPPORTED Isochronous transfer isn't supported. 1656 1657 **/ 1658 EFI_STATUS 1659 EFIAPI 1660 XhcAsyncIsochronousTransfer ( 1661 IN EFI_USB2_HC_PROTOCOL *This, 1662 IN UINT8 DeviceAddress, 1663 IN UINT8 EndPointAddress, 1664 IN UINT8 DeviceSpeed, 1665 IN UINTN MaximumPacketLength, 1666 IN UINT8 DataBuffersNumber, 1667 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], 1668 IN UINTN DataLength, 1669 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1670 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, 1671 IN VOID *Context 1672 ) 1673 { 1674 return EFI_UNSUPPORTED; 1675 } 1676 1677 /** 1678 Entry point for EFI drivers. 1679 1680 @param ImageHandle EFI_HANDLE. 1681 @param SystemTable EFI_SYSTEM_TABLE. 1682 1683 @retval EFI_SUCCESS Success. 1684 @retval Others Fail. 1685 1686 **/ 1687 EFI_STATUS 1688 EFIAPI 1689 XhcDriverEntryPoint ( 1690 IN EFI_HANDLE ImageHandle, 1691 IN EFI_SYSTEM_TABLE *SystemTable 1692 ) 1693 { 1694 return EfiLibInstallDriverBindingComponentName2 ( 1695 ImageHandle, 1696 SystemTable, 1697 &gXhciDriverBinding, 1698 ImageHandle, 1699 &gXhciComponentName, 1700 &gXhciComponentName2 1701 ); 1702 } 1703 1704 1705 /** 1706 Test to see if this driver supports ControllerHandle. Any 1707 ControllerHandle that has Usb2HcProtocol installed will 1708 be supported. 1709 1710 @param This Protocol instance pointer. 1711 @param Controller Handle of device to test. 1712 @param RemainingDevicePath Not used. 1713 1714 @return EFI_SUCCESS This driver supports this device. 1715 @return EFI_UNSUPPORTED This driver does not support this device. 1716 1717 **/ 1718 EFI_STATUS 1719 EFIAPI 1720 XhcDriverBindingSupported ( 1721 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1722 IN EFI_HANDLE Controller, 1723 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1724 ) 1725 { 1726 EFI_STATUS Status; 1727 EFI_PCI_IO_PROTOCOL *PciIo; 1728 USB_CLASSC UsbClassCReg; 1729 1730 // 1731 // Test whether there is PCI IO Protocol attached on the controller handle. 1732 // 1733 Status = gBS->OpenProtocol ( 1734 Controller, 1735 &gEfiPciIoProtocolGuid, 1736 (VOID **) &PciIo, 1737 This->DriverBindingHandle, 1738 Controller, 1739 EFI_OPEN_PROTOCOL_BY_DRIVER 1740 ); 1741 1742 if (EFI_ERROR (Status)) { 1743 return EFI_UNSUPPORTED; 1744 } 1745 1746 Status = PciIo->Pci.Read ( 1747 PciIo, 1748 EfiPciIoWidthUint8, 1749 PCI_CLASSCODE_OFFSET, 1750 sizeof (USB_CLASSC) / sizeof (UINT8), 1751 &UsbClassCReg 1752 ); 1753 1754 if (EFI_ERROR (Status)) { 1755 Status = EFI_UNSUPPORTED; 1756 goto ON_EXIT; 1757 } 1758 1759 // 1760 // Test whether the controller belongs to Xhci type 1761 // 1762 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || 1763 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || 1764 (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) { 1765 Status = EFI_UNSUPPORTED; 1766 } 1767 1768 ON_EXIT: 1769 gBS->CloseProtocol ( 1770 Controller, 1771 &gEfiPciIoProtocolGuid, 1772 This->DriverBindingHandle, 1773 Controller 1774 ); 1775 1776 return Status; 1777 } 1778 1779 /** 1780 Create and initialize a USB_XHCI_INSTANCE structure. 1781 1782 @param PciIo The PciIo on this device. 1783 @param DevicePath The device path of host controller. 1784 @param OriginalPciAttributes Original PCI attributes. 1785 1786 @return The allocated and initialized USB_XHCI_INSTANCE structure if created, 1787 otherwise NULL. 1788 1789 **/ 1790 USB_XHCI_INSTANCE* 1791 XhcCreateUsbHc ( 1792 IN EFI_PCI_IO_PROTOCOL *PciIo, 1793 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 1794 IN UINT64 OriginalPciAttributes 1795 ) 1796 { 1797 USB_XHCI_INSTANCE *Xhc; 1798 EFI_STATUS Status; 1799 UINT32 PageSize; 1800 UINT16 ExtCapReg; 1801 1802 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE)); 1803 1804 if (Xhc == NULL) { 1805 return NULL; 1806 } 1807 1808 // 1809 // Initialize private data structure 1810 // 1811 Xhc->Signature = XHCI_INSTANCE_SIG; 1812 Xhc->PciIo = PciIo; 1813 Xhc->DevicePath = DevicePath; 1814 Xhc->OriginalPciAttributes = OriginalPciAttributes; 1815 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL)); 1816 1817 InitializeListHead (&Xhc->AsyncIntTransfers); 1818 1819 // 1820 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align 1821 // 1822 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET); 1823 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET); 1824 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET); 1825 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET); 1826 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET); 1827 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET); 1828 1829 // 1830 // This PageSize field defines the page size supported by the xHC implementation. 1831 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example, 1832 // if bit 0 is Set, the xHC supports 4k byte page sizes. 1833 // 1834 PageSize = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK; 1835 Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12); 1836 1837 ExtCapReg = (UINT16) (Xhc->HcCParams.Data.ExtCapReg); 1838 Xhc->ExtCapRegBase = ExtCapReg << 2; 1839 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY); 1840 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG); 1841 1842 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength)); 1843 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1)); 1844 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2)); 1845 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams)); 1846 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff)); 1847 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff)); 1848 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset)); 1849 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset)); 1850 1851 // 1852 // Create AsyncRequest Polling Timer 1853 // 1854 Status = gBS->CreateEvent ( 1855 EVT_TIMER | EVT_NOTIFY_SIGNAL, 1856 TPL_NOTIFY, 1857 XhcMonitorAsyncRequests, 1858 Xhc, 1859 &Xhc->PollTimer 1860 ); 1861 1862 if (EFI_ERROR (Status)) { 1863 goto ON_ERROR; 1864 } 1865 1866 return Xhc; 1867 1868 ON_ERROR: 1869 FreePool (Xhc); 1870 return NULL; 1871 } 1872 1873 /** 1874 One notified function to stop the Host Controller when gBS->ExitBootServices() called. 1875 1876 @param Event Pointer to this event 1877 @param Context Event handler private data 1878 1879 **/ 1880 VOID 1881 EFIAPI 1882 XhcExitBootService ( 1883 EFI_EVENT Event, 1884 VOID *Context 1885 ) 1886 1887 { 1888 USB_XHCI_INSTANCE *Xhc; 1889 EFI_PCI_IO_PROTOCOL *PciIo; 1890 1891 Xhc = (USB_XHCI_INSTANCE*) Context; 1892 PciIo = Xhc->PciIo; 1893 1894 // 1895 // Stop AsyncRequest Polling timer then stop the XHCI driver 1896 // and uninstall the XHCI protocl. 1897 // 1898 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0); 1899 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); 1900 1901 if (Xhc->PollTimer != NULL) { 1902 gBS->CloseEvent (Xhc->PollTimer); 1903 } 1904 1905 XhcClearBiosOwnership (Xhc); 1906 1907 // 1908 // Restore original PCI attributes 1909 // 1910 PciIo->Attributes ( 1911 PciIo, 1912 EfiPciIoAttributeOperationSet, 1913 Xhc->OriginalPciAttributes, 1914 NULL 1915 ); 1916 } 1917 1918 /** 1919 Starting the Usb XHCI Driver. 1920 1921 @param This Protocol instance pointer. 1922 @param Controller Handle of device to test. 1923 @param RemainingDevicePath Not used. 1924 1925 @return EFI_SUCCESS supports this device. 1926 @return EFI_UNSUPPORTED do not support this device. 1927 @return EFI_DEVICE_ERROR cannot be started due to device Error. 1928 @return EFI_OUT_OF_RESOURCES cannot allocate resources. 1929 1930 **/ 1931 EFI_STATUS 1932 EFIAPI 1933 XhcDriverBindingStart ( 1934 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1935 IN EFI_HANDLE Controller, 1936 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1937 ) 1938 { 1939 EFI_STATUS Status; 1940 EFI_PCI_IO_PROTOCOL *PciIo; 1941 UINT64 Supports; 1942 UINT64 OriginalPciAttributes; 1943 BOOLEAN PciAttributesSaved; 1944 USB_XHCI_INSTANCE *Xhc; 1945 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath; 1946 1947 // 1948 // Open the PciIo Protocol, then enable the USB host controller 1949 // 1950 Status = gBS->OpenProtocol ( 1951 Controller, 1952 &gEfiPciIoProtocolGuid, 1953 (VOID **) &PciIo, 1954 This->DriverBindingHandle, 1955 Controller, 1956 EFI_OPEN_PROTOCOL_BY_DRIVER 1957 ); 1958 1959 if (EFI_ERROR (Status)) { 1960 return Status; 1961 } 1962 1963 // 1964 // Open Device Path Protocol for on USB host controller 1965 // 1966 HcDevicePath = NULL; 1967 Status = gBS->OpenProtocol ( 1968 Controller, 1969 &gEfiDevicePathProtocolGuid, 1970 (VOID **) &HcDevicePath, 1971 This->DriverBindingHandle, 1972 Controller, 1973 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1974 ); 1975 1976 PciAttributesSaved = FALSE; 1977 // 1978 // Save original PCI attributes 1979 // 1980 Status = PciIo->Attributes ( 1981 PciIo, 1982 EfiPciIoAttributeOperationGet, 1983 0, 1984 &OriginalPciAttributes 1985 ); 1986 1987 if (EFI_ERROR (Status)) { 1988 goto CLOSE_PCIIO; 1989 } 1990 PciAttributesSaved = TRUE; 1991 1992 Status = PciIo->Attributes ( 1993 PciIo, 1994 EfiPciIoAttributeOperationSupported, 1995 0, 1996 &Supports 1997 ); 1998 if (!EFI_ERROR (Status)) { 1999 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; 2000 Status = PciIo->Attributes ( 2001 PciIo, 2002 EfiPciIoAttributeOperationEnable, 2003 Supports, 2004 NULL 2005 ); 2006 } 2007 2008 if (EFI_ERROR (Status)) { 2009 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n")); 2010 goto CLOSE_PCIIO; 2011 } 2012 2013 // 2014 // Create then install USB2_HC_PROTOCOL 2015 // 2016 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes); 2017 2018 if (Xhc == NULL) { 2019 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n")); 2020 return EFI_OUT_OF_RESOURCES; 2021 } 2022 2023 XhcSetBiosOwnership (Xhc); 2024 2025 XhcResetHC (Xhc, XHC_RESET_TIMEOUT); 2026 ASSERT (XhcIsHalt (Xhc)); 2027 2028 // 2029 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag 2030 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers. 2031 // 2032 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR))); 2033 2034 // 2035 // Initialize the schedule 2036 // 2037 XhcInitSched (Xhc); 2038 2039 // 2040 // Start the Host Controller 2041 // 2042 XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT); 2043 2044 // 2045 // Start the asynchronous interrupt monitor 2046 // 2047 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL); 2048 if (EFI_ERROR (Status)) { 2049 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n")); 2050 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); 2051 goto FREE_POOL; 2052 } 2053 2054 // 2055 // Create event to stop the HC when exit boot service. 2056 // 2057 Status = gBS->CreateEventEx ( 2058 EVT_NOTIFY_SIGNAL, 2059 TPL_NOTIFY, 2060 XhcExitBootService, 2061 Xhc, 2062 &gEfiEventExitBootServicesGuid, 2063 &Xhc->ExitBootServiceEvent 2064 ); 2065 if (EFI_ERROR (Status)) { 2066 goto FREE_POOL; 2067 } 2068 2069 // 2070 // Install the component name protocol, don't fail the start 2071 // because of something for display. 2072 // 2073 AddUnicodeString2 ( 2074 "eng", 2075 gXhciComponentName.SupportedLanguages, 2076 &Xhc->ControllerNameTable, 2077 L"eXtensible Host Controller (USB 3.0)", 2078 TRUE 2079 ); 2080 AddUnicodeString2 ( 2081 "en", 2082 gXhciComponentName2.SupportedLanguages, 2083 &Xhc->ControllerNameTable, 2084 L"eXtensible Host Controller (USB 3.0)", 2085 FALSE 2086 ); 2087 2088 Status = gBS->InstallProtocolInterface ( 2089 &Controller, 2090 &gEfiUsb2HcProtocolGuid, 2091 EFI_NATIVE_INTERFACE, 2092 &Xhc->Usb2Hc 2093 ); 2094 if (EFI_ERROR (Status)) { 2095 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n")); 2096 goto FREE_POOL; 2097 } 2098 2099 DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller)); 2100 return EFI_SUCCESS; 2101 2102 FREE_POOL: 2103 gBS->CloseEvent (Xhc->PollTimer); 2104 XhcFreeSched (Xhc); 2105 FreePool (Xhc); 2106 2107 CLOSE_PCIIO: 2108 if (PciAttributesSaved) { 2109 // 2110 // Restore original PCI attributes 2111 // 2112 PciIo->Attributes ( 2113 PciIo, 2114 EfiPciIoAttributeOperationSet, 2115 OriginalPciAttributes, 2116 NULL 2117 ); 2118 } 2119 2120 gBS->CloseProtocol ( 2121 Controller, 2122 &gEfiPciIoProtocolGuid, 2123 This->DriverBindingHandle, 2124 Controller 2125 ); 2126 2127 return Status; 2128 } 2129 2130 2131 /** 2132 Stop this driver on ControllerHandle. Support stoping any child handles 2133 created by this driver. 2134 2135 @param This Protocol instance pointer. 2136 @param Controller Handle of device to stop driver on. 2137 @param NumberOfChildren Number of Children in the ChildHandleBuffer. 2138 @param ChildHandleBuffer List of handles for the children we need to stop. 2139 2140 @return EFI_SUCCESS Success. 2141 @return EFI_DEVICE_ERROR Fail. 2142 2143 **/ 2144 EFI_STATUS 2145 EFIAPI 2146 XhcDriverBindingStop ( 2147 IN EFI_DRIVER_BINDING_PROTOCOL *This, 2148 IN EFI_HANDLE Controller, 2149 IN UINTN NumberOfChildren, 2150 IN EFI_HANDLE *ChildHandleBuffer 2151 ) 2152 { 2153 EFI_STATUS Status; 2154 EFI_USB2_HC_PROTOCOL *Usb2Hc; 2155 EFI_PCI_IO_PROTOCOL *PciIo; 2156 USB_XHCI_INSTANCE *Xhc; 2157 UINT8 Index; 2158 2159 // 2160 // Test whether the Controller handler passed in is a valid 2161 // Usb controller handle that should be supported, if not, 2162 // return the error status directly 2163 // 2164 Status = gBS->OpenProtocol ( 2165 Controller, 2166 &gEfiUsb2HcProtocolGuid, 2167 (VOID **) &Usb2Hc, 2168 This->DriverBindingHandle, 2169 Controller, 2170 EFI_OPEN_PROTOCOL_GET_PROTOCOL 2171 ); 2172 2173 if (EFI_ERROR (Status)) { 2174 return Status; 2175 } 2176 2177 Status = gBS->UninstallProtocolInterface ( 2178 Controller, 2179 &gEfiUsb2HcProtocolGuid, 2180 Usb2Hc 2181 ); 2182 2183 if (EFI_ERROR (Status)) { 2184 return Status; 2185 } 2186 2187 Xhc = XHC_FROM_THIS (Usb2Hc); 2188 PciIo = Xhc->PciIo; 2189 2190 // 2191 // Stop AsyncRequest Polling timer then stop the XHCI driver 2192 // and uninstall the XHCI protocl. 2193 // 2194 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0); 2195 2196 // 2197 // Disable the device slots occupied by these devices on its downstream ports. 2198 // Entry 0 is reserved. 2199 // 2200 for (Index = 0; Index < 255; Index++) { 2201 if (!Xhc->UsbDevContext[Index + 1].Enabled || 2202 (Xhc->UsbDevContext[Index + 1].SlotId == 0)) { 2203 continue; 2204 } 2205 if (Xhc->HcCParams.Data.Csz == 0) { 2206 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); 2207 } else { 2208 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); 2209 } 2210 } 2211 2212 if (Xhc->PollTimer != NULL) { 2213 gBS->CloseEvent (Xhc->PollTimer); 2214 } 2215 2216 if (Xhc->ExitBootServiceEvent != NULL) { 2217 gBS->CloseEvent (Xhc->ExitBootServiceEvent); 2218 } 2219 2220 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); 2221 XhcClearBiosOwnership (Xhc); 2222 XhciDelAllAsyncIntTransfers (Xhc); 2223 XhcFreeSched (Xhc); 2224 2225 if (Xhc->ControllerNameTable) { 2226 FreeUnicodeStringTable (Xhc->ControllerNameTable); 2227 } 2228 2229 // 2230 // Restore original PCI attributes 2231 // 2232 PciIo->Attributes ( 2233 PciIo, 2234 EfiPciIoAttributeOperationSet, 2235 Xhc->OriginalPciAttributes, 2236 NULL 2237 ); 2238 2239 gBS->CloseProtocol ( 2240 Controller, 2241 &gEfiPciIoProtocolGuid, 2242 This->DriverBindingHandle, 2243 Controller 2244 ); 2245 2246 FreePool (Xhc); 2247 2248 return EFI_SUCCESS; 2249 } 2250 2251