1/** @file 2This file contains the implementation of Usb Hc Protocol. 3 4Copyright (c) 2013-2016 Intel Corporation. 5 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16 17#include "Ohci.h" 18 19/** 20 Provides software reset for the USB host controller. 21 22 @param This This EFI_USB_HC_PROTOCOL instance. 23 @param Attributes A bit mask of the reset operation to perform. 24 25 @retval EFI_SUCCESS The reset operation succeeded. 26 @retval EFI_INVALID_PARAMETER Attributes is not valid. 27 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is 28 not currently supported by the host controller. 29 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. 30 31**/ 32EFI_STATUS 33EFIAPI 34OhciReset ( 35 IN EFI_USB_HC_PROTOCOL *This, 36 IN UINT16 Attributes 37 ) 38{ 39 EFI_STATUS Status; 40 USB_OHCI_HC_DEV *Ohc; 41 UINT8 Index; 42 UINT8 NumOfPorts; 43 UINT32 PowerOnGoodTime; 44 UINT32 Data32; 45 BOOLEAN Flag = FALSE; 46 47 if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) { 48 return EFI_INVALID_PARAMETER; 49 } 50 51 Status = EFI_SUCCESS; 52 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 53 54 if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) { 55 gBS->Stall (50 * 1000); 56 Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET); 57 if (EFI_ERROR (Status)) { 58 return EFI_DEVICE_ERROR; 59 } 60 gBS->Stall (50 * 1000); 61 // 62 // Wait for host controller reset. 63 // 64 PowerOnGoodTime = 50; 65 do { 66 gBS->Stall (1 * 1000); 67 Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS ); 68 if (EFI_ERROR (Status)) { 69 return EFI_DEVICE_ERROR; 70 } 71 if ((Data32 & HC_RESET) == 0) { 72 Flag = TRUE; 73 break; 74 } 75 }while(PowerOnGoodTime--); 76 if (!Flag){ 77 return EFI_DEVICE_ERROR; 78 } 79 } 80 OhciFreeIntTransferMemory (Ohc); 81 Status = OhciInitializeInterruptList (Ohc); 82 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); 83 if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) { 84 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); 85 if (EFI_ERROR (Status)) { 86 return EFI_DEVICE_ERROR; 87 } 88 gBS->Stall (50 * 1000); 89 } 90 // 91 // Initialize host controller operational registers 92 // 93 OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778); 94 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); 95 OhciSetPeriodicStart (Ohc, 0x2a2f); 96 OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3); 97 OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0); 98 OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0); 99 OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1); 100 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0); 101 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1); 102 103 OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0); 104 OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff); 105 OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE); 106 OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER); 107 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 108 for (Index = 0; Index < NumOfPorts; Index++) { 109 if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) { 110 gBS->Stall (200 * 1000); 111 OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset); 112 gBS->Stall (1000); 113 OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable); 114 gBS->Stall (1000); 115 } 116 } 117 OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock); 118 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); 119 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); 120 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/ 121 OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); 122 gBS->Stall (50*1000); 123 // 124 // Wait till first SOF occurs, and then clear it 125 // 126 while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0); 127 OhciClearInterruptStatus (Ohc, START_OF_FRAME); 128 gBS->Stall (1000); 129 130 return Status; 131} 132 133/** 134 Retrieve the current state of the USB host controller. 135 136 @param This This EFI_USB_HC_PROTOCOL instance. 137 @param State Variable to return the current host controller 138 state. 139 140 @retval EFI_SUCCESS Host controller state was returned in State. 141 @retval EFI_INVALID_PARAMETER State is NULL. 142 @retval EFI_DEVICE_ERROR An error was encountered while attempting to 143 retrieve the host controller's current state. 144 145**/ 146 147EFI_STATUS 148EFIAPI 149OhciGetState ( 150 IN EFI_USB_HC_PROTOCOL *This, 151 OUT EFI_USB_HC_STATE *State 152 ) 153{ 154 USB_OHCI_HC_DEV *Ohc; 155 UINT32 FuncState; 156 157 if (State == NULL) { 158 return EFI_INVALID_PARAMETER; 159 } 160 161 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 162 163 FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE); 164 165 switch (FuncState) { 166 case HC_STATE_RESET: 167 case HC_STATE_RESUME: 168 *State = EfiUsbHcStateHalt; 169 break; 170 171 case HC_STATE_OPERATIONAL: 172 *State = EfiUsbHcStateOperational; 173 break; 174 175 case HC_STATE_SUSPEND: 176 *State = EfiUsbHcStateSuspend; 177 break; 178 179 default: 180 ASSERT (FALSE); 181 } 182 return EFI_SUCCESS; 183} 184 185/** 186 Sets the USB host controller to a specific state. 187 188 @param This This EFI_USB_HC_PROTOCOL instance. 189 @param State The state of the host controller that will be set. 190 191 @retval EFI_SUCCESS The USB host controller was successfully placed 192 in the state specified by State. 193 @retval EFI_INVALID_PARAMETER State is invalid. 194 @retval EFI_DEVICE_ERROR Failed to set the state due to device error. 195 196**/ 197 198EFI_STATUS 199EFIAPI 200OhciSetState( 201 IN EFI_USB_HC_PROTOCOL *This, 202 IN EFI_USB_HC_STATE State 203 ) 204{ 205 EFI_STATUS Status; 206 USB_OHCI_HC_DEV *Ohc; 207 208 Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); 209 210 switch (State) { 211 case EfiUsbHcStateHalt: 212 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); 213 break; 214 215 case EfiUsbHcStateOperational: 216 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); 217 break; 218 219 case EfiUsbHcStateSuspend: 220 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND); 221 break; 222 223 default: 224 Status = EFI_INVALID_PARAMETER; 225 } 226 227 gBS->Stall (1000); 228 229 return Status; 230} 231 232/** 233 234 Submits control transfer to a target USB device. 235 236 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 237 @param DeviceAddress Represents the address of the target device on the USB, 238 which is assigned during USB enumeration. 239 @param IsSlowDevice Indicates whether the target device is slow device 240 or full-speed device. 241 @param MaxPaketLength Indicates the maximum packet size that the 242 default control transfer endpoint is capable of 243 sending or receiving. 244 @param Request A pointer to the USB device request that will be sent 245 to the USB device. 246 @param TransferDirection Specifies the data direction for the transfer. 247 There are three values available, DataIn, DataOut 248 and NoData. 249 @param Data A pointer to the buffer of data that will be transmitted 250 to USB device or received from USB device. 251 @param DataLength Indicates the size, in bytes, of the data buffer 252 specified by Data. 253 @param TimeOut Indicates the maximum time, in microseconds, 254 which the transfer is allowed to complete. 255 @param TransferResult A pointer to the detailed result information generated 256 by this control transfer. 257 258 @retval EFI_SUCCESS The control transfer was completed successfully. 259 @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources. 260 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 261 @retval EFI_TIMEOUT The control transfer failed due to timeout. 262 @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error. 263 Caller should check TranferResult for detailed error information. 264 265--*/ 266 267 268EFI_STATUS 269EFIAPI 270OhciControlTransfer ( 271 IN EFI_USB_HC_PROTOCOL *This, 272 IN UINT8 DeviceAddress, 273 IN BOOLEAN IsSlowDevice, 274 IN UINT8 MaxPacketLength, 275 IN EFI_USB_DEVICE_REQUEST *Request, 276 IN EFI_USB_DATA_DIRECTION TransferDirection, 277 IN OUT VOID *Data OPTIONAL, 278 IN OUT UINTN *DataLength OPTIONAL, 279 IN UINTN TimeOut, 280 OUT UINT32 *TransferResult 281 ) 282{ 283 USB_OHCI_HC_DEV *Ohc; 284 ED_DESCRIPTOR *HeadEd; 285 ED_DESCRIPTOR *Ed; 286 TD_DESCRIPTOR *HeadTd; 287 TD_DESCRIPTOR *SetupTd; 288 TD_DESCRIPTOR *DataTd; 289 TD_DESCRIPTOR *StatusTd; 290 TD_DESCRIPTOR *EmptyTd; 291 EFI_STATUS Status; 292 UINT32 DataPidDir; 293 UINT32 StatusPidDir; 294 UINTN TimeCount; 295 OHCI_ED_RESULT EdResult; 296 297 EFI_PCI_IO_PROTOCOL_OPERATION MapOp; 298 299 UINTN ActualSendLength; 300 UINTN LeftLength; 301 UINT8 DataToggle; 302 303 VOID *ReqMapping = NULL; 304 UINTN ReqMapLength = 0; 305 EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0; 306 307 VOID *DataMapping = NULL; 308 UINTN DataMapLength = 0; 309 EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0; 310 311 HeadTd = NULL; 312 DataTd = NULL; 313 314 if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn && 315 TransferDirection != EfiUsbNoData) || 316 Request == NULL || DataLength == NULL || TransferResult == NULL || 317 (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) || 318 (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) || 319 (IsSlowDevice && MaxPacketLength != 8) || 320 (MaxPacketLength != 8 && MaxPacketLength != 16 && 321 MaxPacketLength != 32 && MaxPacketLength != 64)) { 322 return EFI_INVALID_PARAMETER; 323 } 324 325 if (*DataLength > MAX_BYTES_PER_TD) { 326 DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n")); 327 return EFI_INVALID_PARAMETER; 328 } 329 330 Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); 331 332 if (TransferDirection == EfiUsbDataIn) { 333 DataPidDir = TD_IN_PID; 334 StatusPidDir = TD_OUT_PID; 335 } else { 336 DataPidDir = TD_OUT_PID; 337 StatusPidDir = TD_IN_PID; 338 } 339 340 Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); 341 if (EFI_ERROR(Status)) { 342 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n")); 343 *TransferResult = EFI_USB_ERR_SYSTEM; 344 return EFI_DEVICE_ERROR; 345 } 346 Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0); 347 if (EFI_ERROR(Status)) { 348 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n")); 349 *TransferResult = EFI_USB_ERR_SYSTEM; 350 return EFI_DEVICE_ERROR; 351 } 352 gBS->Stall(20 * 1000); 353 354 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); 355 Ed = OhciCreateED (Ohc); 356 if (Ed == NULL) { 357 Status = EFI_OUT_OF_RESOURCES; 358 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n")); 359 goto CTRL_EXIT; 360 } 361 OhciSetEDField (Ed, ED_SKIP, 1); 362 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); 363 OhciSetEDField (Ed, ED_ENDPT_NUM, 0); 364 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); 365 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); 366 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); 367 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); 368 OhciSetEDField (Ed, ED_PDATA, 0); 369 OhciSetEDField (Ed, ED_ZERO, 0); 370 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); 371 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); 372 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); 373 HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL); 374 // 375 // Setup Stage 376 // 377 if(Request != NULL) { 378 ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST); 379 MapOp = EfiPciIoOperationBusMasterRead; 380 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping); 381 if (EFI_ERROR(Status)) { 382 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n")); 383 goto FREE_ED_BUFF; 384 } 385 } 386 SetupTd = OhciCreateTD (Ohc); 387 if (SetupTd == NULL) { 388 Status = EFI_OUT_OF_RESOURCES; 389 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n")); 390 goto UNMAP_SETUP_BUFF; 391 } 392 HeadTd = SetupTd; 393 OhciSetTDField (SetupTd, TD_PDATA, 0); 394 OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1); 395 OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID); 396 OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY); 397 OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2); 398 OhciSetTDField (SetupTd, TD_ERROR_CNT, 0); 399 OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED); 400 OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr); 401 OhciSetTDField (SetupTd, TD_NEXT_PTR, 0); 402 OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1)); 403 SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST); 404 SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr; 405 SetupTd->NextTDPointer = 0; 406 407 if (TransferDirection == EfiUsbDataIn) { 408 MapOp = EfiPciIoOperationBusMasterWrite; 409 } else { 410 MapOp = EfiPciIoOperationBusMasterRead; 411 } 412 DataMapLength = *DataLength; 413 if ((Data != NULL) && (DataMapLength != 0)) { 414 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping); 415 if (EFI_ERROR(Status)) { 416 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n")); 417 goto FREE_TD_BUFF; 418 } 419 } 420 // 421 //Data Stage 422 // 423 LeftLength = DataMapLength; 424 ActualSendLength = DataMapLength; 425 DataToggle = 1; 426 while (LeftLength > 0) { 427 ActualSendLength = LeftLength; 428 if (LeftLength > MaxPacketLength) { 429 ActualSendLength = MaxPacketLength; 430 } 431 DataTd = OhciCreateTD (Ohc); 432 if (DataTd == NULL) { 433 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n")); 434 Status = EFI_OUT_OF_RESOURCES; 435 goto UNMAP_DATA_BUFF; 436 } 437 OhciSetTDField (DataTd, TD_PDATA, 0); 438 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); 439 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); 440 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); 441 OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle); 442 OhciSetTDField (DataTd, TD_ERROR_CNT, 0); 443 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); 444 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr); 445 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1)); 446 OhciSetTDField (DataTd, TD_NEXT_PTR, 0); 447 DataTd->ActualSendLength = (UINT32)ActualSendLength; 448 DataTd->DataBuffer = (UINT32)DataMapPhyAddr; 449 DataTd->NextTDPointer = 0; 450 OhciLinkTD (HeadTd, DataTd); 451 DataToggle ^= 1; 452 DataMapPhyAddr += ActualSendLength; 453 LeftLength -= ActualSendLength; 454 } 455 // 456 // Status Stage 457 // 458 StatusTd = OhciCreateTD (Ohc); 459 if (StatusTd == NULL) { 460 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n")); 461 Status = EFI_OUT_OF_RESOURCES; 462 goto UNMAP_DATA_BUFF; 463 } 464 OhciSetTDField (StatusTd, TD_PDATA, 0); 465 OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1); 466 OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir); 467 OhciSetTDField (StatusTd, TD_DELAY_INT, 7); 468 OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3); 469 OhciSetTDField (StatusTd, TD_ERROR_CNT, 0); 470 OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED); 471 OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0); 472 OhciSetTDField (StatusTd, TD_NEXT_PTR, 0); 473 OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0); 474 StatusTd->ActualSendLength = 0; 475 StatusTd->DataBuffer = 0; 476 StatusTd->NextTDPointer = 0; 477 OhciLinkTD (HeadTd, StatusTd); 478 // 479 // Empty Stage 480 // 481 EmptyTd = OhciCreateTD (Ohc); 482 if (EmptyTd == NULL) { 483 Status = EFI_OUT_OF_RESOURCES; 484 goto UNMAP_DATA_BUFF; 485 } 486 OhciSetTDField (EmptyTd, TD_PDATA, 0); 487 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); 488 OhciSetTDField (EmptyTd, TD_DIR_PID, 0); 489 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); 490 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); 491 EmptyTd->Word0.DataToggle = 0; 492 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); 493 OhciSetTDField (EmptyTd, TD_COND_CODE, 0); 494 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); 495 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); 496 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); 497 EmptyTd->ActualSendLength = 0; 498 EmptyTd->DataBuffer = 0; 499 EmptyTd->NextTDPointer = 0; 500 OhciLinkTD (HeadTd, EmptyTd); 501 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; 502 OhciAttachTDListToED (Ed, HeadTd); 503 // 504 // For debugging, dump ED & TD buffer befor transferring 505 // 506 // 507 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE); 508 // 509 OhciSetEDField (Ed, ED_SKIP, 0); 510 Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1); 511 if (EFI_ERROR(Status)) { 512 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n")); 513 *TransferResult = EFI_USB_ERR_SYSTEM; 514 Status = EFI_DEVICE_ERROR; 515 goto UNMAP_DATA_BUFF; 516 } 517 Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1); 518 if (EFI_ERROR(Status)) { 519 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n")); 520 *TransferResult = EFI_USB_ERR_SYSTEM; 521 Status = EFI_DEVICE_ERROR; 522 goto UNMAP_DATA_BUFF; 523 } 524 gBS->Stall(20 * 1000); 525 526 527 TimeCount = 0; 528 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); 529 530 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { 531 gBS->Stall (1000); 532 TimeCount++; 533 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); 534 } 535 // 536 // For debugging, dump ED & TD buffer after transferring 537 // 538 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE); 539 // 540 *TransferResult = ConvertErrorCode (EdResult.ErrorCode); 541 542 if (EdResult.ErrorCode != TD_NO_ERROR) { 543 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { 544 DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut)); 545 } else { 546 DEBUG ((EFI_D_INFO, "Control pipe broken\r\n")); 547 } 548 *DataLength = 0; 549 } else { 550 DEBUG ((EFI_D_INFO, "Control transfer successed\r\n")); 551 } 552 553UNMAP_DATA_BUFF: 554 OhciSetEDField (Ed, ED_SKIP, 1); 555 if (HeadEd == Ed) { 556 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); 557 } else { 558 HeadEd->NextED = Ed->NextED; 559 } 560 if(DataMapping != NULL) { 561 Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping); 562 } 563 564FREE_TD_BUFF: 565 while (HeadTd) { 566 DataTd = HeadTd; 567 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); 568 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); 569 } 570 571UNMAP_SETUP_BUFF: 572 if(ReqMapping != NULL) { 573 Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping); 574 } 575 576FREE_ED_BUFF: 577 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); 578 579CTRL_EXIT: 580 return Status; 581} 582 583/** 584 585 Submits bulk transfer to a bulk endpoint of a USB device. 586 587 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 588 @param DeviceAddress Represents the address of the target device on the USB, 589 which is assigned during USB enumeration. 590 @param EndPointAddress The combination of an endpoint number and an 591 endpoint direction of the target USB device. 592 Each endpoint address supports data transfer in 593 one direction except the control endpoint 594 (whose default endpoint address is 0). 595 It is the caller's responsibility to make sure that 596 the EndPointAddress represents a bulk endpoint. 597 @param MaximumPacketLength Indicates the maximum packet size the target endpoint 598 is capable of sending or receiving. 599 @param Data A pointer to the buffer of data that will be transmitted 600 to USB device or received from USB device. 601 @param DataLength When input, indicates the size, in bytes, of the data buffer 602 specified by Data. When output, indicates the actually 603 transferred data size. 604 @param DataToggle A pointer to the data toggle value. On input, it indicates 605 the initial data toggle value the bulk transfer should adopt; 606 on output, it is updated to indicate the data toggle value 607 of the subsequent bulk transfer. 608 @param TimeOut Indicates the maximum time, in microseconds, which the 609 transfer is allowed to complete. 610 TransferResult A pointer to the detailed result information of the 611 bulk transfer. 612 613 @retval EFI_SUCCESS The bulk transfer was completed successfully. 614 @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource. 615 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 616 @retval EFI_TIMEOUT The bulk transfer failed due to timeout. 617 @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error. 618 Caller should check TranferResult for detailed error information. 619 620**/ 621 622 623EFI_STATUS 624EFIAPI 625OhciBulkTransfer( 626 IN EFI_USB_HC_PROTOCOL *This, 627 IN UINT8 DeviceAddress, 628 IN UINT8 EndPointAddress, 629 IN UINT8 MaxPacketLength, 630 IN OUT VOID *Data, 631 IN OUT UINTN *DataLength, 632 IN OUT UINT8 *DataToggle, 633 IN UINTN TimeOut, 634 OUT UINT32 *TransferResult 635 ) 636{ 637 USB_OHCI_HC_DEV *Ohc; 638 ED_DESCRIPTOR *HeadEd; 639 ED_DESCRIPTOR *Ed; 640 UINT32 DataPidDir; 641 TD_DESCRIPTOR *HeadTd; 642 TD_DESCRIPTOR *DataTd; 643 TD_DESCRIPTOR *EmptyTd; 644 EFI_STATUS Status; 645 UINT8 EndPointNum; 646 UINTN TimeCount; 647 OHCI_ED_RESULT EdResult; 648 649 EFI_PCI_IO_PROTOCOL_OPERATION MapOp; 650 VOID *Mapping; 651 UINTN MapLength; 652 EFI_PHYSICAL_ADDRESS MapPyhAddr; 653 UINTN LeftLength; 654 UINTN ActualSendLength; 655 BOOLEAN FirstTD; 656 657 Mapping = NULL; 658 MapLength = 0; 659 MapPyhAddr = 0; 660 LeftLength = 0; 661 Status = EFI_SUCCESS; 662 663 if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || 664 *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || 665 (MaxPacketLength != 8 && MaxPacketLength != 16 && 666 MaxPacketLength != 32 && MaxPacketLength != 64)) { 667 return EFI_INVALID_PARAMETER; 668 } 669 670 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 671 672 if ((EndPointAddress & 0x80) != 0) { 673 DataPidDir = TD_IN_PID; 674 MapOp = EfiPciIoOperationBusMasterWrite; 675 } else { 676 DataPidDir = TD_OUT_PID; 677 MapOp = EfiPciIoOperationBusMasterRead; 678 } 679 680 EndPointNum = (EndPointAddress & 0xF); 681 EdResult.NextToggle = *DataToggle; 682 683 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0); 684 if (EFI_ERROR(Status)) { 685 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n")); 686 *TransferResult = EFI_USB_ERR_SYSTEM; 687 return EFI_DEVICE_ERROR; 688 } 689 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0); 690 if (EFI_ERROR(Status)) { 691 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n")); 692 *TransferResult = EFI_USB_ERR_SYSTEM; 693 return EFI_DEVICE_ERROR; 694 } 695 gBS->Stall(20 * 1000); 696 697 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); 698 699 Ed = OhciCreateED (Ohc); 700 if (Ed == NULL) { 701 return EFI_OUT_OF_RESOURCES; 702 } 703 OhciSetEDField (Ed, ED_SKIP, 1); 704 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); 705 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); 706 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); 707 OhciSetEDField (Ed, ED_SPEED, HI_SPEED); 708 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); 709 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); 710 OhciSetEDField (Ed, ED_PDATA, 0); 711 OhciSetEDField (Ed, ED_ZERO, 0); 712 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); 713 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); 714 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); 715 HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); 716 717 if(Data != NULL) { 718 MapLength = *DataLength; 719 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping); 720 if (EFI_ERROR(Status)) { 721 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n")); 722 goto FREE_ED_BUFF; 723 } 724 } 725 // 726 //Data Stage 727 // 728 LeftLength = MapLength; 729 ActualSendLength = MapLength; 730 HeadTd = NULL; 731 FirstTD = TRUE; 732 while (LeftLength > 0) { 733 ActualSendLength = LeftLength; 734 if (LeftLength > MaxPacketLength) { 735 ActualSendLength = MaxPacketLength; 736 } 737 DataTd = OhciCreateTD (Ohc); 738 if (DataTd == NULL) { 739 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n")); 740 Status = EFI_OUT_OF_RESOURCES; 741 goto FREE_OHCI_TDBUFF; 742 } 743 OhciSetTDField (DataTd, TD_PDATA, 0); 744 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); 745 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); 746 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); 747 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); 748 OhciSetTDField (DataTd, TD_ERROR_CNT, 0); 749 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); 750 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); 751 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); 752 OhciSetTDField (DataTd, TD_NEXT_PTR, 0); 753 DataTd->ActualSendLength = (UINT32)ActualSendLength; 754 DataTd->DataBuffer = (UINT32)MapPyhAddr; 755 DataTd->NextTDPointer = 0; 756 if (FirstTD) { 757 HeadTd = DataTd; 758 FirstTD = FALSE; 759 } else { 760 OhciLinkTD (HeadTd, DataTd); 761 } 762 *DataToggle ^= 1; 763 MapPyhAddr += ActualSendLength; 764 LeftLength -= ActualSendLength; 765 } 766 // 767 // Empty Stage 768 // 769 EmptyTd = OhciCreateTD (Ohc); 770 if (EmptyTd == NULL) { 771 Status = EFI_OUT_OF_RESOURCES; 772 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n")); 773 goto FREE_OHCI_TDBUFF; 774 } 775 OhciSetTDField (EmptyTd, TD_PDATA, 0); 776 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); 777 OhciSetTDField (EmptyTd, TD_DIR_PID, 0); 778 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); 779 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); 780 EmptyTd->Word0.DataToggle = 0; 781 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); 782 OhciSetTDField (EmptyTd, TD_COND_CODE, 0); 783 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); 784 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); 785 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); 786 EmptyTd->ActualSendLength = 0; 787 EmptyTd->DataBuffer = 0; 788 EmptyTd->NextTDPointer = 0; 789 OhciLinkTD (HeadTd, EmptyTd); 790 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; 791 OhciAttachTDListToED (Ed, HeadTd); 792 793 OhciSetEDField (Ed, ED_SKIP, 0); 794 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); 795 if (EFI_ERROR(Status)) { 796 *TransferResult = EFI_USB_ERR_SYSTEM; 797 Status = EFI_DEVICE_ERROR; 798 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n")); 799 goto FREE_OHCI_TDBUFF; 800 } 801 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1); 802 if (EFI_ERROR(Status)) { 803 *TransferResult = EFI_USB_ERR_SYSTEM; 804 Status = EFI_DEVICE_ERROR; 805 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n")); 806 goto FREE_OHCI_TDBUFF; 807 } 808 gBS->Stall(20 * 1000); 809 810 TimeCount = 0; 811 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); 812 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { 813 gBS->Stall (1000); 814 TimeCount++; 815 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); 816 } 817 818 *TransferResult = ConvertErrorCode (EdResult.ErrorCode); 819 820 if (EdResult.ErrorCode != TD_NO_ERROR) { 821 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { 822 DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); 823 } else { 824 DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); 825 *DataToggle = EdResult.NextToggle; 826 } 827 *DataLength = 0; 828 } else { 829 DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n")); 830 } 831 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); 832 833FREE_OHCI_TDBUFF: 834 OhciSetEDField (Ed, ED_SKIP, 1); 835 if (HeadEd == Ed) { 836 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); 837 }else { 838 HeadEd->NextED = Ed->NextED; 839 } 840 while (HeadTd) { 841 DataTd = HeadTd; 842 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); 843 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); 844 } 845 846 if(Mapping != NULL) { 847 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); 848 } 849 850FREE_ED_BUFF: 851 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); 852 853 return Status; 854} 855/** 856 857 Submits an interrupt transfer to an interrupt endpoint of a USB device. 858 859 @param Ohc Device private data 860 @param DeviceAddress Represents the address of the target device on the USB, 861 which is assigned during USB enumeration. 862 @param EndPointAddress The combination of an endpoint number and an endpoint 863 direction of the target USB device. Each endpoint address 864 supports data transfer in one direction except the 865 control endpoint (whose default endpoint address is 0). 866 It is the caller's responsibility to make sure that 867 the EndPointAddress represents an interrupt endpoint. 868 @param IsSlowDevice Indicates whether the target device is slow device 869 or full-speed device. 870 @param MaxPacketLength Indicates the maximum packet size the target endpoint 871 is capable of sending or receiving. 872 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between 873 the host and the target interrupt endpoint. 874 If FALSE, the specified asynchronous interrupt pipe 875 is canceled. 876 @param DataToggle A pointer to the data toggle value. On input, it is valid 877 when IsNewTransfer is TRUE, and it indicates the initial 878 data toggle value the asynchronous interrupt transfer 879 should adopt. 880 On output, it is valid when IsNewTransfer is FALSE, 881 and it is updated to indicate the data toggle value of 882 the subsequent asynchronous interrupt transfer. 883 @param PollingInterval Indicates the interval, in milliseconds, that the 884 asynchronous interrupt transfer is polled. 885 This parameter is required when IsNewTransfer is TRUE. 886 @param UCBuffer Uncacheable buffer 887 @param DataLength Indicates the length of data to be received at the 888 rate specified by PollingInterval from the target 889 asynchronous interrupt endpoint. This parameter 890 is only required when IsNewTransfer is TRUE. 891 @param CallBackFunction The Callback function.This function is called at the 892 rate specified by PollingInterval.This parameter is 893 only required when IsNewTransfer is TRUE. 894 @param Context The context that is passed to the CallBackFunction. 895 This is an optional parameter and may be NULL. 896 @param IsPeriodic Periodic interrupt or not 897 @param OutputED The correspoding ED carried out 898 @param OutputTD The correspoding TD carried out 899 900 901 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully 902 submitted or canceled. 903 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 904 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 905 906**/ 907 908EFI_STATUS 909OhciInterruptTransfer ( 910 IN USB_OHCI_HC_DEV *Ohc, 911 IN UINT8 DeviceAddress, 912 IN UINT8 EndPointAddress, 913 IN BOOLEAN IsSlowDevice, 914 IN UINT8 MaxPacketLength, 915 IN BOOLEAN IsNewTransfer, 916 IN OUT UINT8 *DataToggle OPTIONAL, 917 IN UINTN PollingInterval OPTIONAL, 918 IN VOID *UCBuffer OPTIONAL, 919 IN UINTN DataLength OPTIONAL, 920 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, 921 IN VOID *Context OPTIONAL, 922 IN BOOLEAN IsPeriodic OPTIONAL, 923 OUT ED_DESCRIPTOR **OutputED OPTIONAL, 924 OUT TD_DESCRIPTOR **OutputTD OPTIONAL 925 ) 926{ 927 ED_DESCRIPTOR *Ed; 928 UINT8 EdDir; 929 ED_DESCRIPTOR *HeadEd; 930 TD_DESCRIPTOR *HeadTd; 931 TD_DESCRIPTOR *DataTd; 932 TD_DESCRIPTOR *EmptTd; 933 UINTN Depth; 934 UINTN Index; 935 EFI_STATUS Status; 936 UINT8 EndPointNum; 937 UINT32 DataPidDir; 938 INTERRUPT_CONTEXT_ENTRY *Entry; 939 EFI_TPL OldTpl; 940 BOOLEAN FirstTD; 941 942 VOID *Mapping; 943 UINTN MapLength; 944 EFI_PHYSICAL_ADDRESS MapPyhAddr; 945 UINTN LeftLength; 946 UINTN ActualSendLength; 947 948 949 if (DataLength > MAX_BYTES_PER_TD) { 950 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n")); 951 return EFI_INVALID_PARAMETER; 952 } 953 954 if ((EndPointAddress & 0x80) != 0) { 955 EdDir = ED_IN_DIR; 956 DataPidDir = TD_IN_PID; 957 } else { 958 EdDir = ED_OUT_DIR; 959 DataPidDir = TD_OUT_PID; 960 } 961 962 EndPointNum = (EndPointAddress & 0xF); 963 964 if (!IsNewTransfer) { 965 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 966 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0); 967 OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle); 968 Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum); 969 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); 970 gBS->RestoreTPL (OldTpl); 971 return Status; 972 } 973 MapLength = DataLength; 974 Status = Ohc->PciIo->Map( 975 Ohc->PciIo, 976 EfiPciIoOperationBusMasterWrite, 977 UCBuffer, 978 &MapLength, 979 &MapPyhAddr, 980 &Mapping 981 ); 982 if (EFI_ERROR (Status)) { 983 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n")); 984 goto EXIT; 985 } 986 Depth = 5; 987 Index = 1; 988 while (PollingInterval >= Index * 2 && Depth > 0) { 989 Index *= 2; 990 Depth--; 991 } 992 // 993 //ED Stage 994 // 995 HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth); 996 if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) { 997 OhciSetEDField (Ed, ED_SKIP, 1); 998 } else { 999 Ed = OhciCreateED (Ohc); 1000 if (Ed == NULL) { 1001 Status = EFI_OUT_OF_RESOURCES; 1002 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n")); 1003 goto UNMAP_OHCI_XBUFF; 1004 } 1005 OhciSetEDField (Ed, ED_SKIP, 1); 1006 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); 1007 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); 1008 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); 1009 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); 1010 OhciSetEDField (Ed, ED_FORMAT, 0); 1011 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); 1012 OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0); 1013 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); 1014 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); 1015 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); 1016 OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd); 1017 } 1018 // 1019 //Data Stage 1020 // 1021 LeftLength = MapLength; 1022 ActualSendLength = MapLength; 1023 HeadTd = NULL; 1024 FirstTD = TRUE; 1025 while (LeftLength > 0) { 1026 ActualSendLength = LeftLength; 1027 if (LeftLength > MaxPacketLength) { 1028 ActualSendLength = MaxPacketLength; 1029 } 1030 DataTd = OhciCreateTD (Ohc); 1031 if (DataTd == NULL) { 1032 Status = EFI_OUT_OF_RESOURCES; 1033 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n")); 1034 goto FREE_OHCI_TDBUFF; 1035 } 1036 OhciSetTDField (DataTd, TD_PDATA, 0); 1037 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); 1038 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); 1039 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); 1040 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); 1041 OhciSetTDField (DataTd, TD_ERROR_CNT, 0); 1042 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); 1043 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); 1044 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); 1045 OhciSetTDField (DataTd, TD_NEXT_PTR, 0); 1046 DataTd->ActualSendLength = (UINT32)ActualSendLength; 1047 DataTd->DataBuffer = (UINT32)MapPyhAddr; 1048 DataTd->NextTDPointer = 0; 1049 if (FirstTD) { 1050 HeadTd = DataTd; 1051 FirstTD = FALSE; 1052 } else { 1053 OhciLinkTD (HeadTd, DataTd); 1054 } 1055 *DataToggle ^= 1; 1056 MapPyhAddr += ActualSendLength; 1057 LeftLength -= ActualSendLength; 1058 } 1059 1060 EmptTd = OhciCreateTD (Ohc); 1061 if (EmptTd == NULL) { 1062 Status = EFI_OUT_OF_RESOURCES; 1063 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n")); 1064 goto FREE_OHCI_TDBUFF; 1065 } 1066 OhciSetTDField (EmptTd, TD_PDATA, 0); 1067 OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0); 1068 OhciSetTDField (EmptTd, TD_DIR_PID, 0); 1069 OhciSetTDField (EmptTd, TD_DELAY_INT, 0); 1070 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle); 1071 EmptTd->Word0.DataToggle = 0; 1072 OhciSetTDField (EmptTd, TD_ERROR_CNT, 0); 1073 OhciSetTDField (EmptTd, TD_COND_CODE, 0); 1074 OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0); 1075 OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0); 1076 OhciSetTDField (EmptTd, TD_NEXT_PTR, 0); 1077 EmptTd->ActualSendLength = 0; 1078 EmptTd->DataBuffer = 0; 1079 EmptTd->NextTDPointer = 0; 1080 OhciLinkTD (HeadTd, EmptTd); 1081 Ed->TdTailPointer = (UINT32)(UINTN)EmptTd; 1082 OhciAttachTDListToED (Ed, HeadTd); 1083 1084 if (OutputED != NULL) { 1085 *OutputED = Ed; 1086 } 1087 if (OutputTD != NULL) { 1088 *OutputTD = HeadTd; 1089 } 1090 1091 if (CallBackFunction != NULL) { 1092 Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY)); 1093 if (Entry == NULL) { 1094 goto FREE_OHCI_TDBUFF; 1095 } 1096 1097 Entry->DeviceAddress = DeviceAddress; 1098 Entry->EndPointAddress = EndPointAddress; 1099 Entry->Ed = Ed; 1100 Entry->DataTd = HeadTd; 1101 Entry->IsSlowDevice = IsSlowDevice; 1102 Entry->MaxPacketLength = MaxPacketLength; 1103 Entry->PollingInterval = PollingInterval; 1104 Entry->CallBackFunction = CallBackFunction; 1105 Entry->Context = Context; 1106 Entry->IsPeriodic = IsPeriodic; 1107 Entry->UCBuffer = UCBuffer; 1108 Entry->UCBufferMapping = Mapping; 1109 Entry->DataLength = DataLength; 1110 Entry->Toggle = DataToggle; 1111 Entry->NextEntry = NULL; 1112 OhciAddInterruptContextEntry (Ohc, Entry); 1113 } 1114 OhciSetEDField (Ed, ED_SKIP, 0); 1115 1116 if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) { 1117 Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); 1118 gBS->Stall (1000); 1119 } 1120 1121 return EFI_SUCCESS; 1122 1123FREE_OHCI_TDBUFF: 1124 while (HeadTd) { 1125 DataTd = HeadTd; 1126 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); 1127 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); 1128 } 1129 1130//FREE_OHCI_EDBUFF: 1131 if ((HeadEd != Ed) && HeadEd && Ed) { 1132 while(HeadEd->NextED != (UINT32)(UINTN)Ed) { 1133 HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED); 1134 } 1135 HeadEd->NextED = Ed->NextED; 1136 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); 1137 } 1138 1139UNMAP_OHCI_XBUFF: 1140 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); 1141 1142EXIT: 1143 return Status; 1144} 1145 1146/** 1147 1148 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. 1149 1150 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1151 @param DeviceAddress Represents the address of the target device on the USB, 1152 which is assigned during USB enumeration. 1153 @param EndPointAddress The combination of an endpoint number and an endpoint 1154 direction of the target USB device. Each endpoint address 1155 supports data transfer in one direction except the 1156 control endpoint (whose default endpoint address is 0). 1157 It is the caller's responsibility to make sure that 1158 the EndPointAddress represents an interrupt endpoint. 1159 @param IsSlowDevice Indicates whether the target device is slow device 1160 or full-speed device. 1161 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint 1162 is capable of sending or receiving. 1163 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between 1164 the host and the target interrupt endpoint. 1165 If FALSE, the specified asynchronous interrupt pipe 1166 is canceled. 1167 @param DataToggle A pointer to the data toggle value. On input, it is valid 1168 when IsNewTransfer is TRUE, and it indicates the initial 1169 data toggle value the asynchronous interrupt transfer 1170 should adopt. 1171 On output, it is valid when IsNewTransfer is FALSE, 1172 and it is updated to indicate the data toggle value of 1173 the subsequent asynchronous interrupt transfer. 1174 @param PollingInterval Indicates the interval, in milliseconds, that the 1175 asynchronous interrupt transfer is polled. 1176 This parameter is required when IsNewTransfer is TRUE. 1177 @param DataLength Indicates the length of data to be received at the 1178 rate specified by PollingInterval from the target 1179 asynchronous interrupt endpoint. This parameter 1180 is only required when IsNewTransfer is TRUE. 1181 @param CallBackFunction The Callback function.This function is called at the 1182 rate specified by PollingInterval.This parameter is 1183 only required when IsNewTransfer is TRUE. 1184 @param Context The context that is passed to the CallBackFunction. 1185 This is an optional parameter and may be NULL. 1186 1187 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully 1188 submitted or canceled. 1189 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 1190 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1191 1192**/ 1193 1194 1195EFI_STATUS 1196EFIAPI 1197OhciAsyncInterruptTransfer ( 1198 IN EFI_USB_HC_PROTOCOL *This, 1199 IN UINT8 DeviceAddress, 1200 IN UINT8 EndPointAddress, 1201 IN BOOLEAN IsSlowDevice, 1202 IN UINT8 MaxPacketLength, 1203 IN BOOLEAN IsNewTransfer, 1204 IN OUT UINT8 *DataToggle OPTIONAL, 1205 IN UINTN PollingInterval OPTIONAL, 1206 IN UINTN DataLength OPTIONAL, 1207 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, 1208 IN VOID *Context OPTIONAL 1209 ) 1210{ 1211 EFI_STATUS Status; 1212 USB_OHCI_HC_DEV *Ohc; 1213 VOID *UCBuffer; 1214 1215 if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 || 1216 (IsNewTransfer && (DataLength == 0 || 1217 (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) { 1218 return EFI_INVALID_PARAMETER; 1219 } 1220 1221 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1222 if ( IsNewTransfer ) { 1223 UCBuffer = AllocatePool(DataLength); 1224 if (UCBuffer == NULL) { 1225 return EFI_OUT_OF_RESOURCES; 1226 } 1227 } else { 1228 UCBuffer = NULL; 1229 } 1230 Status = OhciInterruptTransfer ( 1231 Ohc, 1232 DeviceAddress, 1233 EndPointAddress, 1234 IsSlowDevice, 1235 MaxPacketLength, 1236 IsNewTransfer, 1237 DataToggle, 1238 PollingInterval, 1239 UCBuffer, 1240 DataLength, 1241 CallBackFunction, 1242 Context, 1243 TRUE, 1244 NULL, 1245 NULL 1246 ); 1247 if ( IsNewTransfer ) { 1248 if (EFI_ERROR(Status)) { 1249 gBS->FreePool (UCBuffer); 1250 } 1251 } 1252 return Status; 1253} 1254 1255 1256/** 1257 1258 Submits synchronous interrupt transfer to an interrupt endpoint 1259 of a USB device. 1260 1261 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1262 @param DeviceAddress Represents the address of the target device on the USB, 1263 which is assigned during USB enumeration. 1264 @param EndPointAddress The combination of an endpoint number and an endpoint 1265 direction of the target USB device. Each endpoint 1266 address supports data transfer in one direction 1267 except the control endpoint (whose default 1268 endpoint address is 0). It is the caller's responsibility 1269 to make sure that the EndPointAddress represents 1270 an interrupt endpoint. 1271 @param IsSlowDevice Indicates whether the target device is slow device 1272 or full-speed device. 1273 @param MaxPacketLength Indicates the maximum packet size the target endpoint 1274 is capable of sending or receiving. 1275 @param Data A pointer to the buffer of data that will be transmitted 1276 to USB device or received from USB device. 1277 @param DataLength On input, the size, in bytes, of the data buffer specified 1278 by Data. On output, the number of bytes transferred. 1279 @param DataToggle A pointer to the data toggle value. On input, it indicates 1280 the initial data toggle value the synchronous interrupt 1281 transfer should adopt; 1282 on output, it is updated to indicate the data toggle value 1283 of the subsequent synchronous interrupt transfer. 1284 @param TimeOut Indicates the maximum time, in microseconds, which the 1285 transfer is allowed to complete. 1286 @param TransferResult A pointer to the detailed result information from 1287 the synchronous interrupt transfer. 1288 1289 @retval EFI_UNSUPPORTED This interface not available. 1290 @retval EFI_INVALID_PARAMETER Parameters not follow spec 1291 1292**/ 1293 1294 1295EFI_STATUS 1296EFIAPI 1297OhciSyncInterruptTransfer ( 1298 IN EFI_USB_HC_PROTOCOL *This, 1299 IN UINT8 DeviceAddress, 1300 IN UINT8 EndPointAddress, 1301 IN BOOLEAN IsSlowDevice, 1302 IN UINT8 MaxPacketLength, 1303 IN OUT VOID *Data, 1304 IN OUT UINTN *DataLength, 1305 IN OUT UINT8 *DataToggle, 1306 IN UINTN TimeOut, 1307 OUT UINT32 *TransferResult 1308 ) 1309{ 1310 USB_OHCI_HC_DEV *Ohc; 1311 EFI_STATUS Status; 1312 ED_DESCRIPTOR *Ed; 1313 TD_DESCRIPTOR *HeadTd; 1314 OHCI_ED_RESULT EdResult; 1315 VOID *UCBuffer; 1316 1317 if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 || 1318 (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) || 1319 DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) { 1320 return EFI_INVALID_PARAMETER; 1321 } 1322 1323 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1324 UCBuffer = AllocatePool (*DataLength); 1325 if (UCBuffer == NULL) { 1326 return EFI_OUT_OF_RESOURCES; 1327 } 1328 Status = OhciInterruptTransfer ( 1329 Ohc, 1330 DeviceAddress, 1331 EndPointAddress, 1332 IsSlowDevice, 1333 MaxPacketLength, 1334 TRUE, 1335 DataToggle, 1336 1, 1337 UCBuffer, 1338 *DataLength, 1339 NULL, 1340 NULL, 1341 FALSE, 1342 &Ed, 1343 &HeadTd 1344 ); 1345 1346 if (!EFI_ERROR (Status)) { 1347 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); 1348 while (Status == EFI_NOT_READY && TimeOut > 0) { 1349 gBS->Stall (1000); 1350 TimeOut--; 1351 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); 1352 } 1353 1354 *TransferResult = ConvertErrorCode (EdResult.ErrorCode); 1355 } 1356 CopyMem(Data, UCBuffer, *DataLength); 1357 Status = OhciInterruptTransfer ( 1358 Ohc, 1359 DeviceAddress, 1360 EndPointAddress, 1361 IsSlowDevice, 1362 MaxPacketLength, 1363 FALSE, 1364 DataToggle, 1365 0, 1366 NULL, 1367 0, 1368 NULL, 1369 NULL, 1370 FALSE, 1371 NULL, 1372 NULL 1373 ); 1374 1375 return Status; 1376} 1377/** 1378 1379 Submits isochronous transfer to a target USB device. 1380 1381 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1382 @param DeviceAddress Represents the address of the target device on the USB, 1383 which is assigned during USB enumeration. 1384 @param EndPointAddress End point address 1385 @param MaximumPacketLength Indicates the maximum packet size that the 1386 default control transfer endpoint is capable of 1387 sending or receiving. 1388 @param Data A pointer to the buffer of data that will be transmitted 1389 to USB device or received from USB device. 1390 @param DataLength Indicates the size, in bytes, of the data buffer 1391 specified by Data. 1392 @param TransferResult A pointer to the detailed result information generated 1393 by this control transfer. 1394 1395 @retval EFI_UNSUPPORTED This interface not available 1396 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL 1397 1398**/ 1399 1400 1401EFI_STATUS 1402EFIAPI 1403OhciIsochronousTransfer ( 1404 IN EFI_USB_HC_PROTOCOL *This, 1405 IN UINT8 DeviceAddress, 1406 IN UINT8 EndPointAddress, 1407 IN UINT8 MaximumPacketLength, 1408 IN OUT VOID *Data, 1409 IN OUT UINTN DataLength, 1410 OUT UINT32 *TransferResult 1411 ) 1412{ 1413 if (Data == NULL || DataLength == 0 || TransferResult == NULL) { 1414 return EFI_INVALID_PARAMETER; 1415 } 1416 1417 return EFI_UNSUPPORTED; 1418} 1419 1420/** 1421 1422 Submits Async isochronous transfer to a target USB device. 1423 1424 @param his A pointer to the EFI_USB_HC_PROTOCOL instance. 1425 @param DeviceAddress Represents the address of the target device on the USB, 1426 which is assigned during USB enumeration. 1427 @param EndPointAddress End point address 1428 @param MaximumPacketLength Indicates the maximum packet size that the 1429 default control transfer endpoint is capable of 1430 sending or receiving. 1431 @param Data A pointer to the buffer of data that will be transmitted 1432 to USB device or received from USB device. 1433 @param IsochronousCallBack When the transfer complete, the call back function will be called 1434 @param Context Pass to the call back function as parameter 1435 1436 @retval EFI_UNSUPPORTED This interface not available 1437 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 1438 1439**/ 1440 1441EFI_STATUS 1442EFIAPI 1443OhciAsyncIsochronousTransfer ( 1444 IN EFI_USB_HC_PROTOCOL *This, 1445 IN UINT8 DeviceAddress, 1446 IN UINT8 EndPointAddress, 1447 IN UINT8 MaximumPacketLength, 1448 IN OUT VOID *Data, 1449 IN OUT UINTN DataLength, 1450 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, 1451 IN VOID *Context OPTIONAL 1452 ) 1453{ 1454 1455 if (Data == NULL || DataLength == 0) { 1456 return EFI_INVALID_PARAMETER; 1457 } 1458 1459 return EFI_UNSUPPORTED; 1460} 1461 1462/** 1463 1464 Retrieves the number of root hub ports. 1465 1466 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1467 @param NumOfPorts A pointer to the number of the root hub ports. 1468 1469 @retval EFI_SUCCESS The port number was retrieved successfully. 1470**/ 1471EFI_STATUS 1472EFIAPI 1473OhciGetRootHubNumOfPorts ( 1474 IN EFI_USB_HC_PROTOCOL *This, 1475 OUT UINT8 *NumOfPorts 1476 ) 1477{ 1478 USB_OHCI_HC_DEV *Ohc; 1479 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1480 1481 if (NumOfPorts == NULL) { 1482 return EFI_INVALID_PARAMETER; 1483 } 1484 1485 *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); 1486 1487 return EFI_SUCCESS; 1488} 1489/** 1490 1491 Retrieves the current status of a USB root hub port. 1492 1493 @param This A pointer to the EFI_USB_HC_PROTOCOL. 1494 @param PortNumber Specifies the root hub port from which the status 1495 is to be retrieved. This value is zero-based. For example, 1496 if a root hub has two ports, then the first port is numbered 0, 1497 and the second port is numbered 1. 1498 @param PortStatus A pointer to the current port status bits and 1499 port status change bits. 1500 1501 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber 1502 was returned in PortStatus. 1503 @retval EFI_INVALID_PARAMETER Port number not valid 1504**/ 1505 1506 1507EFI_STATUS 1508EFIAPI 1509OhciGetRootHubPortStatus ( 1510 IN EFI_USB_HC_PROTOCOL *This, 1511 IN UINT8 PortNumber, 1512 OUT EFI_USB_PORT_STATUS *PortStatus 1513 ) 1514{ 1515 USB_OHCI_HC_DEV *Ohc; 1516 UINT8 NumOfPorts; 1517 1518 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1519 1520 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1521 if (PortNumber >= NumOfPorts) { 1522 return EFI_INVALID_PARAMETER; 1523 } 1524 PortStatus->PortStatus = 0; 1525 PortStatus->PortChangeStatus = 0; 1526 1527 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) { 1528 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; 1529 } 1530 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) { 1531 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; 1532 } 1533 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) { 1534 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; 1535 } 1536 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) { 1537 PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; 1538 } 1539 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) { 1540 PortStatus->PortStatus |= USB_PORT_STAT_RESET; 1541 } 1542 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) { 1543 PortStatus->PortStatus |= USB_PORT_STAT_POWER; 1544 } 1545 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) { 1546 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; 1547 } 1548 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) { 1549 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; 1550 } 1551 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) { 1552 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; 1553 } 1554 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) { 1555 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND; 1556 } 1557 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) { 1558 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; 1559 } 1560 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) { 1561 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; 1562 } 1563 1564 return EFI_SUCCESS; 1565} 1566/** 1567 1568 Sets a feature for the specified root hub port. 1569 1570 @param This A pointer to the EFI_USB_HC_PROTOCOL. 1571 @param PortNumber Specifies the root hub port whose feature 1572 is requested to be set. 1573 @param PortFeature Indicates the feature selector associated 1574 with the feature set request. 1575 1576 @retval EFI_SUCCESS The feature specified by PortFeature was set for the 1577 USB root hub port specified by PortNumber. 1578 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue 1579 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 1580**/ 1581EFI_STATUS 1582EFIAPI 1583OhciSetRootHubPortFeature ( 1584 IN EFI_USB_HC_PROTOCOL *This, 1585 IN UINT8 PortNumber, 1586 IN EFI_USB_PORT_FEATURE PortFeature 1587 ) 1588{ 1589 USB_OHCI_HC_DEV *Ohc; 1590 EFI_STATUS Status; 1591 UINT8 NumOfPorts; 1592 UINTN RetryTimes; 1593 1594 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1595 if (PortNumber >= NumOfPorts) { 1596 return EFI_INVALID_PARAMETER; 1597 } 1598 1599 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1600 1601 Status = EFI_SUCCESS; 1602 1603 1604 switch (PortFeature) { 1605 case EfiUsbPortPower: 1606 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER); 1607 1608 // 1609 // Verify the state 1610 // 1611 RetryTimes = 0; 1612 do { 1613 gBS->Stall (1000); 1614 RetryTimes++; 1615 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 && 1616 RetryTimes < MAX_RETRY_TIMES); 1617 1618 if (RetryTimes >= MAX_RETRY_TIMES) { 1619 return EFI_DEVICE_ERROR; 1620 } 1621 break; 1622 1623 case EfiUsbPortReset: 1624 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET); 1625 1626 // 1627 // Verify the state 1628 // 1629 RetryTimes = 0; 1630 do { 1631 gBS->Stall (1000); 1632 RetryTimes++; 1633 } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 || 1634 OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) && 1635 RetryTimes < MAX_RETRY_TIMES); 1636 1637 if (RetryTimes >= MAX_RETRY_TIMES) { 1638 return EFI_DEVICE_ERROR; 1639 } 1640 1641 OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); 1642 break; 1643 1644 case EfiUsbPortEnable: 1645 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE); 1646 1647 // 1648 // Verify the state 1649 // 1650 RetryTimes = 0; 1651 do { 1652 gBS->Stall (1000); 1653 RetryTimes++; 1654 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 && 1655 RetryTimes < MAX_RETRY_TIMES); 1656 1657 if (RetryTimes >= MAX_RETRY_TIMES) { 1658 return EFI_DEVICE_ERROR; 1659 } 1660 break; 1661 1662 1663 case EfiUsbPortSuspend: 1664 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND); 1665 1666 // 1667 // Verify the state 1668 // 1669 RetryTimes = 0; 1670 do { 1671 gBS->Stall (1000); 1672 RetryTimes++; 1673 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 && 1674 RetryTimes < MAX_RETRY_TIMES); 1675 1676 if (RetryTimes >= MAX_RETRY_TIMES) { 1677 return EFI_DEVICE_ERROR; 1678 } 1679 break; 1680 1681 default: 1682 return EFI_INVALID_PARAMETER; 1683 } 1684 1685 return Status; 1686} 1687 1688/** 1689 1690 Clears a feature for the specified root hub port. 1691 1692 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1693 @param PortNumber Specifies the root hub port whose feature 1694 is requested to be cleared. 1695 @param PortFeature Indicates the feature selector associated with the 1696 feature clear request. 1697 1698 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the 1699 USB root hub port specified by PortNumber. 1700 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 1701 @retval EFI_DEVICE_ERROR Some error happened when clearing feature 1702**/ 1703EFI_STATUS 1704EFIAPI 1705OhciClearRootHubPortFeature ( 1706 IN EFI_USB_HC_PROTOCOL *This, 1707 IN UINT8 PortNumber, 1708 IN EFI_USB_PORT_FEATURE PortFeature 1709 ) 1710{ 1711 USB_OHCI_HC_DEV *Ohc; 1712 EFI_STATUS Status; 1713 UINT8 NumOfPorts; 1714 UINTN RetryTimes; 1715 1716 1717 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1718 if (PortNumber >= NumOfPorts) { 1719 return EFI_INVALID_PARAMETER; 1720 } 1721 1722 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1723 1724 Status = EFI_SUCCESS; 1725 1726 switch (PortFeature) { 1727 case EfiUsbPortEnable: 1728 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE); 1729 1730 // 1731 // Verify the state 1732 // 1733 RetryTimes = 0; 1734 do { 1735 gBS->Stall (1000); 1736 RetryTimes++; 1737 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 && 1738 RetryTimes < MAX_RETRY_TIMES); 1739 1740 if (RetryTimes >= MAX_RETRY_TIMES) { 1741 return EFI_DEVICE_ERROR; 1742 } 1743 break; 1744 1745 case EfiUsbPortSuspend: 1746 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS); 1747 1748 // 1749 // Verify the state 1750 // 1751 RetryTimes = 0; 1752 do { 1753 gBS->Stall (1000); 1754 RetryTimes++; 1755 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 && 1756 RetryTimes < MAX_RETRY_TIMES); 1757 1758 if (RetryTimes >= MAX_RETRY_TIMES) { 1759 return EFI_DEVICE_ERROR; 1760 } 1761 break; 1762 1763 case EfiUsbPortReset: 1764 break; 1765 1766 case EfiUsbPortPower: 1767 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER); 1768 1769 // 1770 // Verify the state 1771 // 1772 RetryTimes = 0; 1773 do { 1774 gBS->Stall (1000); 1775 RetryTimes++; 1776 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 && 1777 RetryTimes < MAX_RETRY_TIMES); 1778 1779 if (RetryTimes >= MAX_RETRY_TIMES) { 1780 return EFI_DEVICE_ERROR; 1781 } 1782 break; 1783 1784 case EfiUsbPortConnectChange: 1785 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE); 1786 1787 // 1788 // Verify the state 1789 // 1790 RetryTimes = 0; 1791 do { 1792 gBS->Stall (1000); 1793 RetryTimes++; 1794 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 && 1795 RetryTimes < MAX_RETRY_TIMES); 1796 1797 if (RetryTimes >= MAX_RETRY_TIMES) { 1798 return EFI_DEVICE_ERROR; 1799 } 1800 break; 1801 1802 case EfiUsbPortResetChange: 1803 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); 1804 1805 // 1806 // Verify the state 1807 // 1808 RetryTimes = 0; 1809 do { 1810 gBS->Stall (1000); 1811 RetryTimes++; 1812 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 && 1813 RetryTimes < MAX_RETRY_TIMES); 1814 1815 if (RetryTimes >= MAX_RETRY_TIMES) { 1816 return EFI_DEVICE_ERROR; 1817 } 1818 break; 1819 1820 1821 case EfiUsbPortEnableChange: 1822 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE); 1823 1824 // 1825 // Verify the state 1826 // 1827 RetryTimes = 0; 1828 do { 1829 gBS->Stall (1000); 1830 RetryTimes++; 1831 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 && 1832 RetryTimes < MAX_RETRY_TIMES); 1833 1834 if (RetryTimes >= MAX_RETRY_TIMES) { 1835 return EFI_DEVICE_ERROR; 1836 } 1837 break; 1838 1839 case EfiUsbPortSuspendChange: 1840 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE); 1841 1842 // 1843 // Verify the state 1844 // 1845 RetryTimes = 0; 1846 do { 1847 gBS->Stall (1000); 1848 RetryTimes++; 1849 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 && 1850 RetryTimes < MAX_RETRY_TIMES); 1851 1852 if (RetryTimes >= MAX_RETRY_TIMES) { 1853 return EFI_DEVICE_ERROR; 1854 } 1855 break; 1856 1857 case EfiUsbPortOverCurrentChange: 1858 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE); 1859 1860 // 1861 // Verify the state 1862 // 1863 RetryTimes = 0; 1864 do { 1865 gBS->Stall (1000); 1866 RetryTimes++; 1867 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 && 1868 RetryTimes < MAX_RETRY_TIMES); 1869 1870 if (RetryTimes >= MAX_RETRY_TIMES) { 1871 return EFI_DEVICE_ERROR; 1872 } 1873 break; 1874 1875 default: 1876 return EFI_INVALID_PARAMETER; 1877 } 1878 1879 return Status; 1880} 1881 1882EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = { 1883 OHCIDriverBindingSupported, 1884 OHCIDriverBindingStart, 1885 OHCIDriverBindingStop, 1886 0x10, 1887 NULL, 1888 NULL 1889}; 1890 1891 1892/** 1893 Entry point for EFI drivers. 1894 1895 @param ImageHandle EFI_HANDLE. 1896 @param SystemTable EFI_SYSTEM_TABLE. 1897 1898 @retval EFI_SUCCESS Driver is successfully loaded. 1899 @return Others Failed. 1900 1901**/ 1902EFI_STATUS 1903EFIAPI 1904OHCIDriverEntryPoint ( 1905 IN EFI_HANDLE ImageHandle, 1906 IN EFI_SYSTEM_TABLE *SystemTable 1907 ) 1908{ 1909 return EfiLibInstallDriverBindingComponentName2 ( 1910 ImageHandle, 1911 SystemTable, 1912 &gOhciDriverBinding, 1913 ImageHandle, 1914 &gOhciComponentName, 1915 &gOhciComponentName2 1916 ); 1917} 1918 1919 1920/** 1921 Test to see if this driver supports ControllerHandle. Any 1922 ControllerHandle that has UsbHcProtocol installed will be supported. 1923 1924 @param This Protocol instance pointer. 1925 @param Controller Handle of device to test. 1926 @param RemainingDevicePath Not used. 1927 1928 @return EFI_SUCCESS This driver supports this device. 1929 @return EFI_UNSUPPORTED This driver does not support this device. 1930 1931**/ 1932EFI_STATUS 1933EFIAPI 1934OHCIDriverBindingSupported ( 1935 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1936 IN EFI_HANDLE Controller, 1937 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1938 ) 1939{ 1940 EFI_STATUS Status; 1941 EFI_PCI_IO_PROTOCOL *PciIo; 1942 USB_CLASSC UsbClassCReg; 1943 // 1944 // Test whether there is PCI IO Protocol attached on the controller handle. 1945 // 1946 Status = gBS->OpenProtocol ( 1947 Controller, 1948 &gEfiPciIoProtocolGuid, 1949 (VOID **) &PciIo, 1950 This->DriverBindingHandle, 1951 Controller, 1952 EFI_OPEN_PROTOCOL_BY_DRIVER 1953 ); 1954 1955 if (EFI_ERROR (Status)) { 1956 return EFI_UNSUPPORTED; 1957 } 1958 1959 Status = PciIo->Pci.Read ( 1960 PciIo, 1961 EfiPciIoWidthUint8, 1962 PCI_CLASSCODE_OFFSET, 1963 sizeof (USB_CLASSC) / sizeof (UINT8), 1964 &UsbClassCReg 1965 ); 1966 1967 if (EFI_ERROR (Status)) { 1968 Status = EFI_UNSUPPORTED; 1969 goto ON_EXIT; 1970 } 1971 // 1972 // Test whether the controller belongs to OHCI type 1973 // 1974 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || 1975 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || 1976 (UsbClassCReg.ProgInterface != PCI_IF_OHCI) 1977 ) { 1978 1979 Status = EFI_UNSUPPORTED; 1980 } 1981ON_EXIT: 1982 gBS->CloseProtocol ( 1983 Controller, 1984 &gEfiPciIoProtocolGuid, 1985 This->DriverBindingHandle, 1986 Controller 1987 ); 1988 1989 return Status; 1990 1991} 1992 1993/** 1994 1995 Allocate and initialize the empty OHCI device. 1996 1997 @param PciIo The PCIIO to use. 1998 @param OriginalPciAttributes The original PCI attributes. 1999 2000 @return Allocated OHCI device If err, return NULL. 2001 2002**/ 2003 2004USB_OHCI_HC_DEV * 2005OhciAllocateDev ( 2006 IN EFI_PCI_IO_PROTOCOL *PciIo, 2007 IN UINT64 OriginalPciAttributes 2008 ) 2009{ 2010 USB_OHCI_HC_DEV *Ohc; 2011 EFI_STATUS Status; 2012 VOID *Buf; 2013 EFI_PHYSICAL_ADDRESS PhyAddr; 2014 VOID *Map; 2015 UINTN Pages; 2016 UINTN Bytes; 2017 2018 Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV)); 2019 if (Ohc == NULL) { 2020 return NULL; 2021 } 2022 2023 Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE; 2024 Ohc->PciIo = PciIo; 2025 2026 Ohc->UsbHc.Reset = OhciReset; 2027 Ohc->UsbHc.GetState = OhciGetState; 2028 Ohc->UsbHc.SetState = OhciSetState; 2029 Ohc->UsbHc.ControlTransfer = OhciControlTransfer; 2030 Ohc->UsbHc.BulkTransfer = OhciBulkTransfer; 2031 Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer; 2032 Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer; 2033 Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer; 2034 Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer; 2035 Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; 2036 Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus; 2037 Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature; 2038 Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature; 2039 Ohc->UsbHc.MajorRevision = 0x1; 2040 Ohc->UsbHc.MinorRevision = 0x1; 2041 2042 Ohc->OriginalPciAttributes = OriginalPciAttributes; 2043 2044 Ohc->HccaMemoryBlock = NULL; 2045 Ohc->HccaMemoryMapping = NULL; 2046 Ohc->HccaMemoryBuf = NULL; 2047 Ohc->HccaMemoryPages = 0; 2048 Ohc->InterruptContextList = NULL; 2049 Ohc->ControllerNameTable = NULL; 2050 Ohc->HouseKeeperTimer = NULL; 2051 2052 Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0); 2053 if(Ohc->MemPool == NULL) { 2054 goto FREE_DEV_BUFFER; 2055 } 2056 2057 Bytes = 4096; 2058 Pages = EFI_SIZE_TO_PAGES (Bytes); 2059 2060 Status = PciIo->AllocateBuffer ( 2061 PciIo, 2062 AllocateAnyPages, 2063 EfiBootServicesData, 2064 Pages, 2065 &Buf, 2066 0 2067 ); 2068 2069 if (EFI_ERROR (Status)) { 2070 goto FREE_MEM_POOL; 2071 } 2072 2073 Status = PciIo->Map ( 2074 PciIo, 2075 EfiPciIoOperationBusMasterCommonBuffer, 2076 Buf, 2077 &Bytes, 2078 &PhyAddr, 2079 &Map 2080 ); 2081 2082 if (EFI_ERROR (Status) || (Bytes != 4096)) { 2083 goto FREE_MEM_PAGE; 2084 } 2085 2086 Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr; 2087 Ohc->HccaMemoryMapping = Map; 2088 Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf; 2089 Ohc->HccaMemoryPages = Pages; 2090 2091 return Ohc; 2092 2093FREE_MEM_PAGE: 2094 PciIo->FreeBuffer (PciIo, Pages, Buf); 2095FREE_MEM_POOL: 2096 UsbHcFreeMemPool (Ohc->MemPool); 2097FREE_DEV_BUFFER: 2098 FreePool(Ohc); 2099 2100 return NULL; 2101} 2102/** 2103 2104 Free the OHCI device and release its associated resources. 2105 2106 @param Ohc The OHCI device to release. 2107 2108**/ 2109VOID 2110OhciFreeDev ( 2111 IN USB_OHCI_HC_DEV *Ohc 2112 ) 2113{ 2114 OhciFreeFixedIntMemory (Ohc); 2115 2116 if (Ohc->HouseKeeperTimer != NULL) { 2117 gBS->CloseEvent (Ohc->HouseKeeperTimer); 2118 } 2119 2120 if (Ohc->ExitBootServiceEvent != NULL) { 2121 gBS->CloseEvent (Ohc->ExitBootServiceEvent); 2122 } 2123 2124 if (Ohc->MemPool != NULL) { 2125 UsbHcFreeMemPool (Ohc->MemPool); 2126 } 2127 2128 if (Ohc->HccaMemoryMapping != NULL ) { 2129 Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf); 2130 } 2131 2132 if (Ohc->ControllerNameTable != NULL) { 2133 FreeUnicodeStringTable (Ohc->ControllerNameTable); 2134 } 2135 2136 FreePool (Ohc); 2137} 2138/** 2139 2140 Uninstall all Ohci Interface. 2141 2142 @param Controller Controller handle. 2143 @param This Protocol instance pointer. 2144 2145**/ 2146VOID 2147OhciCleanDevUp ( 2148 IN EFI_HANDLE Controller, 2149 IN EFI_USB_HC_PROTOCOL *This 2150 ) 2151{ 2152 USB_OHCI_HC_DEV *Ohc; 2153 2154 // 2155 // Retrieve private context structure 2156 // 2157 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 2158 2159 // 2160 // Uninstall the USB_HC and USB_HC2 protocol 2161 // 2162 gBS->UninstallProtocolInterface ( 2163 Controller, 2164 &gEfiUsbHcProtocolGuid, 2165 &Ohc->UsbHc 2166 ); 2167 2168 // 2169 // Cancel the timer event 2170 // 2171 gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0); 2172 2173 // 2174 // Stop the host controller 2175 // 2176 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); 2177 This->Reset (This, EFI_USB_HC_RESET_GLOBAL); 2178 This->SetState (This, EfiUsbHcStateHalt); 2179 2180 // 2181 // Free resources 2182 // 2183 OhciFreeDynamicIntMemory (Ohc); 2184 2185 // 2186 // Restore original PCI attributes 2187 // 2188 Ohc->PciIo->Attributes ( 2189 Ohc->PciIo, 2190 EfiPciIoAttributeOperationSet, 2191 Ohc->OriginalPciAttributes, 2192 NULL 2193 ); 2194 2195 // 2196 // Free the private context structure 2197 // 2198 OhciFreeDev (Ohc); 2199} 2200 2201/** 2202 2203 One notified function to stop the Host Controller when gBS->ExitBootServices() called. 2204 2205 @param Event Pointer to this event 2206 @param Context Event handler private data 2207**/ 2208VOID 2209EFIAPI 2210OhcExitBootService ( 2211 EFI_EVENT Event, 2212 VOID *Context 2213 ) 2214{ 2215 USB_OHCI_HC_DEV *Ohc; 2216 EFI_USB_HC_PROTOCOL *UsbHc; 2217 Ohc = (USB_OHCI_HC_DEV *) Context; 2218 2219 UsbHc = &Ohc->UsbHc; 2220 // 2221 // Stop the Host Controller 2222 // 2223 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); 2224 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); 2225 UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL); 2226 UsbHc->SetState (UsbHc, EfiUsbHcStateHalt); 2227 2228 return; 2229} 2230 2231 2232/** 2233 Starting the Usb OHCI Driver. 2234 2235 @param This Protocol instance pointer. 2236 @param Controller Handle of device to test. 2237 @param RemainingDevicePath Not used. 2238 2239 @retval EFI_SUCCESS This driver supports this device. 2240 @retval EFI_UNSUPPORTED This driver does not support this device. 2241 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. 2242 EFI_OUT_OF_RESOURCES- Failed due to resource shortage. 2243 2244**/ 2245EFI_STATUS 2246EFIAPI 2247OHCIDriverBindingStart ( 2248 IN EFI_DRIVER_BINDING_PROTOCOL *This, 2249 IN EFI_HANDLE Controller, 2250 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 2251 ) 2252{ 2253 EFI_STATUS Status; 2254 EFI_PCI_IO_PROTOCOL *PciIo; 2255 USB_OHCI_HC_DEV *Ohc; 2256 UINT64 Supports; 2257 UINT64 OriginalPciAttributes; 2258 BOOLEAN PciAttributesSaved; 2259 2260 // 2261 // Open PCIIO, then enable the HC device and turn off emulation 2262 // 2263 Ohc = NULL; 2264 Status = gBS->OpenProtocol ( 2265 Controller, 2266 &gEfiPciIoProtocolGuid, 2267 (VOID **) &PciIo, 2268 This->DriverBindingHandle, 2269 Controller, 2270 EFI_OPEN_PROTOCOL_BY_DRIVER 2271 ); 2272 2273 if (EFI_ERROR (Status)) { 2274 return Status; 2275 } 2276 2277 PciAttributesSaved = FALSE; 2278 // 2279 // Save original PCI attributes 2280 // 2281 Status = PciIo->Attributes ( 2282 PciIo, 2283 EfiPciIoAttributeOperationGet, 2284 0, 2285 &OriginalPciAttributes 2286 ); 2287 2288 if (EFI_ERROR (Status)) { 2289 goto CLOSE_PCIIO; 2290 } 2291 PciAttributesSaved = TRUE; 2292 2293 // 2294 // Robustnesss improvement such as for UoL 2295 // Default is not required. 2296 // 2297 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) { 2298 // OhciTurnOffUsbEmulation (PciIo); 2299 //} 2300 2301 Status = PciIo->Attributes ( 2302 PciIo, 2303 EfiPciIoAttributeOperationSupported, 2304 0, 2305 &Supports 2306 ); 2307 if (!EFI_ERROR (Status)) { 2308 Supports &= EFI_PCI_DEVICE_ENABLE; 2309 Status = PciIo->Attributes ( 2310 PciIo, 2311 EfiPciIoAttributeOperationEnable, 2312 Supports, 2313 NULL 2314 ); 2315 } 2316 2317 if (EFI_ERROR (Status)) { 2318 goto CLOSE_PCIIO; 2319 } 2320 // 2321 //Allocate memory for OHC private data structure 2322 // 2323 Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes); 2324 if (Ohc == NULL){ 2325 Status = EFI_OUT_OF_RESOURCES; 2326 goto CLOSE_PCIIO; 2327 } 2328 2329 //Status = OhciInitializeInterruptList ( Uhc ); 2330 //if (EFI_ERROR (Status)) { 2331 // goto FREE_OHC; 2332 //} 2333 2334 // 2335 // Set 0.01 s timer 2336 // 2337 Status = gBS->CreateEvent ( 2338 EVT_TIMER | EVT_NOTIFY_SIGNAL, 2339 TPL_NOTIFY, 2340 OhciHouseKeeper, 2341 Ohc, 2342 &Ohc->HouseKeeperTimer 2343 ); 2344 if (EFI_ERROR (Status)) { 2345 goto FREE_OHC; 2346 } 2347 2348 Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10); 2349 if (EFI_ERROR (Status)) { 2350 goto FREE_OHC; 2351 } 2352 2353 // 2354 //Install Host Controller Protocol 2355 // 2356 Status = gBS->InstallProtocolInterface ( 2357 &Controller, 2358 &gEfiUsbHcProtocolGuid, 2359 EFI_NATIVE_INTERFACE, 2360 &Ohc->UsbHc 2361 ); 2362 if (EFI_ERROR (Status)) { 2363 DEBUG ((EFI_D_INFO, "Install protocol error")); 2364 goto FREE_OHC; 2365 } 2366 // 2367 // Create event to stop the HC when exit boot service. 2368 // 2369 Status = gBS->CreateEventEx ( 2370 EVT_NOTIFY_SIGNAL, 2371 TPL_NOTIFY, 2372 OhcExitBootService, 2373 Ohc, 2374 &gEfiEventExitBootServicesGuid, 2375 &Ohc->ExitBootServiceEvent 2376 ); 2377 if (EFI_ERROR (Status)) { 2378 DEBUG ((EFI_D_INFO, "Create exit boot event error")); 2379 goto UNINSTALL_USBHC; 2380 } 2381 AddUnicodeString2 ( 2382 "eng", 2383 gOhciComponentName.SupportedLanguages, 2384 &Ohc->ControllerNameTable, 2385 L"Usb Universal Host Controller", 2386 TRUE 2387 ); 2388 AddUnicodeString2 ( 2389 "en", 2390 gOhciComponentName2.SupportedLanguages, 2391 &Ohc->ControllerNameTable, 2392 L"Usb Universal Host Controller", 2393 FALSE 2394 ); 2395 2396 return EFI_SUCCESS; 2397 2398UNINSTALL_USBHC: 2399 gBS->UninstallMultipleProtocolInterfaces ( 2400 Controller, 2401 &gEfiUsbHcProtocolGuid, 2402 &Ohc->UsbHc, 2403 NULL 2404 ); 2405 2406FREE_OHC: 2407 OhciFreeDev (Ohc); 2408 2409CLOSE_PCIIO: 2410 if (PciAttributesSaved) { 2411 // 2412 // Restore original PCI attributes 2413 // 2414 PciIo->Attributes ( 2415 PciIo, 2416 EfiPciIoAttributeOperationSet, 2417 OriginalPciAttributes, 2418 NULL 2419 ); 2420 } 2421 2422 gBS->CloseProtocol ( 2423 Controller, 2424 &gEfiPciIoProtocolGuid, 2425 This->DriverBindingHandle, 2426 Controller 2427 ); 2428 return Status; 2429} 2430 2431/** 2432 Stop this driver on ControllerHandle. Support stopping any child handles 2433 created by this driver. 2434 2435 @param This Protocol instance pointer. 2436 @param Controller Handle of device to stop driver on. 2437 @param NumberOfChildren Number of Children in the ChildHandleBuffer. 2438 @param ChildHandleBuffer List of handles for the children we need to stop. 2439 2440 @return EFI_SUCCESS 2441 @return others 2442 2443**/ 2444EFI_STATUS 2445EFIAPI 2446OHCIDriverBindingStop ( 2447 IN EFI_DRIVER_BINDING_PROTOCOL *This, 2448 IN EFI_HANDLE Controller, 2449 IN UINTN NumberOfChildren, 2450 IN EFI_HANDLE *ChildHandleBuffer 2451 ) 2452{ 2453 EFI_STATUS Status; 2454 EFI_USB_HC_PROTOCOL *UsbHc; 2455 2456 Status = gBS->OpenProtocol ( 2457 Controller, 2458 &gEfiUsbHcProtocolGuid, 2459 (VOID **)&UsbHc, 2460 This->DriverBindingHandle, 2461 Controller, 2462 EFI_OPEN_PROTOCOL_GET_PROTOCOL 2463 ); 2464 if (EFI_ERROR (Status)) { 2465 return Status; 2466 } 2467 2468 OhciCleanDevUp(Controller, UsbHc); 2469 2470 gBS->CloseProtocol ( 2471 Controller, 2472 &gEfiPciIoProtocolGuid, 2473 This->DriverBindingHandle, 2474 Controller 2475 ); 2476 return EFI_SUCCESS; 2477} 2478 2479 2480