1/** @file 2This file contains the implementation of Usb Hc Protocol. 3 4Copyright (c) 2013-2015 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 UINT8 EdDir; 641 UINT32 DataPidDir; 642 TD_DESCRIPTOR *HeadTd; 643 TD_DESCRIPTOR *DataTd; 644 TD_DESCRIPTOR *EmptyTd; 645 EFI_STATUS Status; 646 EFI_USB_DATA_DIRECTION TransferDirection; 647 UINT8 EndPointNum; 648 UINTN TimeCount; 649 OHCI_ED_RESULT EdResult; 650 651 EFI_PCI_IO_PROTOCOL_OPERATION MapOp; 652 VOID *Mapping; 653 UINTN MapLength; 654 EFI_PHYSICAL_ADDRESS MapPyhAddr; 655 UINTN LeftLength; 656 UINTN ActualSendLength; 657 BOOLEAN FirstTD; 658 659 Mapping = NULL; 660 MapLength = 0; 661 MapPyhAddr = 0; 662 LeftLength = 0; 663 Status = EFI_SUCCESS; 664 665 if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || 666 *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || 667 (MaxPacketLength != 8 && MaxPacketLength != 16 && 668 MaxPacketLength != 32 && MaxPacketLength != 64)) { 669 return EFI_INVALID_PARAMETER; 670 } 671 672 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 673 674 if ((EndPointAddress & 0x80) != 0) { 675 TransferDirection = EfiUsbDataIn; 676 EdDir = ED_IN_DIR; 677 DataPidDir = TD_IN_PID; 678 MapOp = EfiPciIoOperationBusMasterWrite; 679 } else { 680 TransferDirection = EfiUsbDataOut; 681 EdDir = ED_OUT_DIR; 682 DataPidDir = TD_OUT_PID; 683 MapOp = EfiPciIoOperationBusMasterRead; 684 } 685 686 EndPointNum = (EndPointAddress & 0xF); 687 EdResult.NextToggle = *DataToggle; 688 689 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0); 690 if (EFI_ERROR(Status)) { 691 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n")); 692 *TransferResult = EFI_USB_ERR_SYSTEM; 693 return EFI_DEVICE_ERROR; 694 } 695 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0); 696 if (EFI_ERROR(Status)) { 697 DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n")); 698 *TransferResult = EFI_USB_ERR_SYSTEM; 699 return EFI_DEVICE_ERROR; 700 } 701 gBS->Stall(20 * 1000); 702 703 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); 704 705 Ed = OhciCreateED (Ohc); 706 if (Ed == NULL) { 707 return EFI_OUT_OF_RESOURCES; 708 } 709 OhciSetEDField (Ed, ED_SKIP, 1); 710 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); 711 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); 712 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); 713 OhciSetEDField (Ed, ED_SPEED, HI_SPEED); 714 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); 715 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); 716 OhciSetEDField (Ed, ED_PDATA, 0); 717 OhciSetEDField (Ed, ED_ZERO, 0); 718 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); 719 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); 720 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); 721 HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); 722 723 if(Data != NULL) { 724 MapLength = *DataLength; 725 Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping); 726 if (EFI_ERROR(Status)) { 727 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n")); 728 goto FREE_ED_BUFF; 729 } 730 } 731 // 732 //Data Stage 733 // 734 LeftLength = MapLength; 735 ActualSendLength = MapLength; 736 HeadTd = NULL; 737 FirstTD = TRUE; 738 while (LeftLength > 0) { 739 ActualSendLength = LeftLength; 740 if (LeftLength > MaxPacketLength) { 741 ActualSendLength = MaxPacketLength; 742 } 743 DataTd = OhciCreateTD (Ohc); 744 if (DataTd == NULL) { 745 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n")); 746 Status = EFI_OUT_OF_RESOURCES; 747 goto FREE_OHCI_TDBUFF; 748 } 749 OhciSetTDField (DataTd, TD_PDATA, 0); 750 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); 751 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); 752 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); 753 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); 754 OhciSetTDField (DataTd, TD_ERROR_CNT, 0); 755 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); 756 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); 757 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); 758 OhciSetTDField (DataTd, TD_NEXT_PTR, 0); 759 DataTd->ActualSendLength = (UINT32)ActualSendLength; 760 DataTd->DataBuffer = (UINT32)MapPyhAddr; 761 DataTd->NextTDPointer = 0; 762 if (FirstTD) { 763 HeadTd = DataTd; 764 FirstTD = FALSE; 765 } else { 766 OhciLinkTD (HeadTd, DataTd); 767 } 768 *DataToggle ^= 1; 769 MapPyhAddr += ActualSendLength; 770 LeftLength -= ActualSendLength; 771 } 772 // 773 // Empty Stage 774 // 775 EmptyTd = OhciCreateTD (Ohc); 776 if (EmptyTd == NULL) { 777 Status = EFI_OUT_OF_RESOURCES; 778 DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n")); 779 goto FREE_OHCI_TDBUFF; 780 } 781 OhciSetTDField (EmptyTd, TD_PDATA, 0); 782 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); 783 OhciSetTDField (EmptyTd, TD_DIR_PID, 0); 784 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); 785 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); 786 EmptyTd->Word0.DataToggle = 0; 787 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); 788 OhciSetTDField (EmptyTd, TD_COND_CODE, 0); 789 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); 790 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); 791 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); 792 EmptyTd->ActualSendLength = 0; 793 EmptyTd->DataBuffer = 0; 794 EmptyTd->NextTDPointer = 0; 795 OhciLinkTD (HeadTd, EmptyTd); 796 Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; 797 OhciAttachTDListToED (Ed, HeadTd); 798 799 OhciSetEDField (Ed, ED_SKIP, 0); 800 Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); 801 if (EFI_ERROR(Status)) { 802 *TransferResult = EFI_USB_ERR_SYSTEM; 803 Status = EFI_DEVICE_ERROR; 804 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n")); 805 goto FREE_OHCI_TDBUFF; 806 } 807 Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1); 808 if (EFI_ERROR(Status)) { 809 *TransferResult = EFI_USB_ERR_SYSTEM; 810 Status = EFI_DEVICE_ERROR; 811 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n")); 812 goto FREE_OHCI_TDBUFF; 813 } 814 gBS->Stall(20 * 1000); 815 816 TimeCount = 0; 817 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); 818 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { 819 gBS->Stall (1000); 820 TimeCount++; 821 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); 822 } 823 824 *TransferResult = ConvertErrorCode (EdResult.ErrorCode); 825 826 if (EdResult.ErrorCode != TD_NO_ERROR) { 827 if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { 828 DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); 829 } else { 830 DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); 831 *DataToggle = EdResult.NextToggle; 832 } 833 *DataLength = 0; 834 } else { 835 DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n")); 836 } 837 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); 838 839FREE_OHCI_TDBUFF: 840 OhciSetEDField (Ed, ED_SKIP, 1); 841 if (HeadEd == Ed) { 842 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); 843 }else { 844 HeadEd->NextED = Ed->NextED; 845 } 846 while (HeadTd) { 847 DataTd = HeadTd; 848 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); 849 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); 850 } 851 852 if(Mapping != NULL) { 853 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); 854 } 855 856FREE_ED_BUFF: 857 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); 858 859 return Status; 860} 861/** 862 863 Submits an interrupt transfer to an interrupt endpoint of a USB device. 864 865 @param Ohc Device private data 866 @param DeviceAddress Represents the address of the target device on the USB, 867 which is assigned during USB enumeration. 868 @param EndPointAddress The combination of an endpoint number and an endpoint 869 direction of the target USB device. Each endpoint address 870 supports data transfer in one direction except the 871 control endpoint (whose default endpoint address is 0). 872 It is the caller's responsibility to make sure that 873 the EndPointAddress represents an interrupt endpoint. 874 @param IsSlowDevice Indicates whether the target device is slow device 875 or full-speed device. 876 @param MaxPacketLength Indicates the maximum packet size the target endpoint 877 is capable of sending or receiving. 878 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between 879 the host and the target interrupt endpoint. 880 If FALSE, the specified asynchronous interrupt pipe 881 is canceled. 882 @param DataToggle A pointer to the data toggle value. On input, it is valid 883 when IsNewTransfer is TRUE, and it indicates the initial 884 data toggle value the asynchronous interrupt transfer 885 should adopt. 886 On output, it is valid when IsNewTransfer is FALSE, 887 and it is updated to indicate the data toggle value of 888 the subsequent asynchronous interrupt transfer. 889 @param PollingInterval Indicates the interval, in milliseconds, that the 890 asynchronous interrupt transfer is polled. 891 This parameter is required when IsNewTransfer is TRUE. 892 @param UCBuffer Uncacheable buffer 893 @param DataLength Indicates the length of data to be received at the 894 rate specified by PollingInterval from the target 895 asynchronous interrupt endpoint. This parameter 896 is only required when IsNewTransfer is TRUE. 897 @param CallBackFunction The Callback function.This function is called at the 898 rate specified by PollingInterval.This parameter is 899 only required when IsNewTransfer is TRUE. 900 @param Context The context that is passed to the CallBackFunction. 901 This is an optional parameter and may be NULL. 902 @param IsPeriodic Periodic interrupt or not 903 @param OutputED The correspoding ED carried out 904 @param OutputTD The correspoding TD carried out 905 906 907 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully 908 submitted or canceled. 909 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 910 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 911 912**/ 913 914EFI_STATUS 915OhciInterruptTransfer ( 916 IN USB_OHCI_HC_DEV *Ohc, 917 IN UINT8 DeviceAddress, 918 IN UINT8 EndPointAddress, 919 IN BOOLEAN IsSlowDevice, 920 IN UINT8 MaxPacketLength, 921 IN BOOLEAN IsNewTransfer, 922 IN OUT UINT8 *DataToggle OPTIONAL, 923 IN UINTN PollingInterval OPTIONAL, 924 IN VOID *UCBuffer OPTIONAL, 925 IN UINTN DataLength OPTIONAL, 926 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, 927 IN VOID *Context OPTIONAL, 928 IN BOOLEAN IsPeriodic OPTIONAL, 929 OUT ED_DESCRIPTOR **OutputED OPTIONAL, 930 OUT TD_DESCRIPTOR **OutputTD OPTIONAL 931 ) 932{ 933 ED_DESCRIPTOR *Ed; 934 UINT8 EdDir; 935 ED_DESCRIPTOR *HeadEd; 936 TD_DESCRIPTOR *HeadTd; 937 TD_DESCRIPTOR *DataTd; 938 TD_DESCRIPTOR *EmptTd; 939 UINTN Depth; 940 UINTN Index; 941 EFI_STATUS Status; 942 UINT8 EndPointNum; 943 UINT32 DataPidDir; 944 EFI_USB_DATA_DIRECTION TransferDirection; 945 INTERRUPT_CONTEXT_ENTRY *Entry; 946 EFI_TPL OldTpl; 947 BOOLEAN FirstTD; 948 949 VOID *Mapping; 950 UINTN MapLength; 951 EFI_PHYSICAL_ADDRESS MapPyhAddr; 952 UINTN LeftLength; 953 UINTN ActualSendLength; 954 955 956 if (DataLength > MAX_BYTES_PER_TD) { 957 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n")); 958 return EFI_INVALID_PARAMETER; 959 } 960 961 if ((EndPointAddress & 0x80) != 0) { 962 TransferDirection = EfiUsbDataIn; 963 EdDir = ED_IN_DIR; 964 DataPidDir = TD_IN_PID; 965 } else { 966 TransferDirection = EfiUsbDataOut; 967 EdDir = ED_OUT_DIR; 968 DataPidDir = TD_OUT_PID; 969 } 970 971 EndPointNum = (EndPointAddress & 0xF); 972 973 if (!IsNewTransfer) { 974 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 975 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0); 976 OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle); 977 Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum); 978 OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); 979 gBS->RestoreTPL (OldTpl); 980 return Status; 981 } 982 MapLength = DataLength; 983 Status = Ohc->PciIo->Map( 984 Ohc->PciIo, 985 EfiPciIoOperationBusMasterWrite, 986 UCBuffer, 987 &MapLength, 988 &MapPyhAddr, 989 &Mapping 990 ); 991 if (EFI_ERROR (Status)) { 992 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n")); 993 goto EXIT; 994 } 995 Depth = 5; 996 Index = 1; 997 while (PollingInterval >= Index * 2 && Depth > 0) { 998 Index *= 2; 999 Depth--; 1000 } 1001 // 1002 //ED Stage 1003 // 1004 HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth); 1005 if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) { 1006 OhciSetEDField (Ed, ED_SKIP, 1); 1007 } else { 1008 Ed = OhciCreateED (Ohc); 1009 if (Ed == NULL) { 1010 Status = EFI_OUT_OF_RESOURCES; 1011 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n")); 1012 goto UNMAP_OHCI_XBUFF; 1013 } 1014 OhciSetEDField (Ed, ED_SKIP, 1); 1015 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); 1016 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); 1017 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); 1018 OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); 1019 OhciSetEDField (Ed, ED_FORMAT, 0); 1020 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); 1021 OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0); 1022 OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); 1023 OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); 1024 OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); 1025 OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd); 1026 } 1027 // 1028 //Data Stage 1029 // 1030 LeftLength = MapLength; 1031 ActualSendLength = MapLength; 1032 HeadTd = NULL; 1033 FirstTD = TRUE; 1034 while (LeftLength > 0) { 1035 ActualSendLength = LeftLength; 1036 if (LeftLength > MaxPacketLength) { 1037 ActualSendLength = MaxPacketLength; 1038 } 1039 DataTd = OhciCreateTD (Ohc); 1040 if (DataTd == NULL) { 1041 Status = EFI_OUT_OF_RESOURCES; 1042 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n")); 1043 goto FREE_OHCI_TDBUFF; 1044 } 1045 OhciSetTDField (DataTd, TD_PDATA, 0); 1046 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); 1047 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); 1048 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); 1049 OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); 1050 OhciSetTDField (DataTd, TD_ERROR_CNT, 0); 1051 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); 1052 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); 1053 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); 1054 OhciSetTDField (DataTd, TD_NEXT_PTR, 0); 1055 DataTd->ActualSendLength = (UINT32)ActualSendLength; 1056 DataTd->DataBuffer = (UINT32)MapPyhAddr; 1057 DataTd->NextTDPointer = 0; 1058 if (FirstTD) { 1059 HeadTd = DataTd; 1060 FirstTD = FALSE; 1061 } else { 1062 OhciLinkTD (HeadTd, DataTd); 1063 } 1064 *DataToggle ^= 1; 1065 MapPyhAddr += ActualSendLength; 1066 LeftLength -= ActualSendLength; 1067 } 1068 1069 EmptTd = OhciCreateTD (Ohc); 1070 if (EmptTd == NULL) { 1071 Status = EFI_OUT_OF_RESOURCES; 1072 DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n")); 1073 goto FREE_OHCI_TDBUFF; 1074 } 1075 OhciSetTDField (EmptTd, TD_PDATA, 0); 1076 OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0); 1077 OhciSetTDField (EmptTd, TD_DIR_PID, 0); 1078 OhciSetTDField (EmptTd, TD_DELAY_INT, 0); 1079 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle); 1080 EmptTd->Word0.DataToggle = 0; 1081 OhciSetTDField (EmptTd, TD_ERROR_CNT, 0); 1082 OhciSetTDField (EmptTd, TD_COND_CODE, 0); 1083 OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0); 1084 OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0); 1085 OhciSetTDField (EmptTd, TD_NEXT_PTR, 0); 1086 EmptTd->ActualSendLength = 0; 1087 EmptTd->DataBuffer = 0; 1088 EmptTd->NextTDPointer = 0; 1089 OhciLinkTD (HeadTd, EmptTd); 1090 Ed->TdTailPointer = (UINT32)(UINTN)EmptTd; 1091 OhciAttachTDListToED (Ed, HeadTd); 1092 1093 if (OutputED != NULL) { 1094 *OutputED = Ed; 1095 } 1096 if (OutputTD != NULL) { 1097 *OutputTD = HeadTd; 1098 } 1099 1100 if (CallBackFunction != NULL) { 1101 Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY)); 1102 if (Entry == NULL) { 1103 goto FREE_OHCI_TDBUFF; 1104 } 1105 1106 Entry->DeviceAddress = DeviceAddress; 1107 Entry->EndPointAddress = EndPointAddress; 1108 Entry->Ed = Ed; 1109 Entry->DataTd = HeadTd; 1110 Entry->IsSlowDevice = IsSlowDevice; 1111 Entry->MaxPacketLength = MaxPacketLength; 1112 Entry->PollingInterval = PollingInterval; 1113 Entry->CallBackFunction = CallBackFunction; 1114 Entry->Context = Context; 1115 Entry->IsPeriodic = IsPeriodic; 1116 Entry->UCBuffer = UCBuffer; 1117 Entry->UCBufferMapping = Mapping; 1118 Entry->DataLength = DataLength; 1119 Entry->Toggle = DataToggle; 1120 Entry->NextEntry = NULL; 1121 OhciAddInterruptContextEntry (Ohc, Entry); 1122 } 1123 OhciSetEDField (Ed, ED_SKIP, 0); 1124 1125 if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) { 1126 Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); 1127 gBS->Stall (1000); 1128 } 1129 1130 return EFI_SUCCESS; 1131 1132FREE_OHCI_TDBUFF: 1133 while (HeadTd) { 1134 DataTd = HeadTd; 1135 HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); 1136 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); 1137 } 1138 1139//FREE_OHCI_EDBUFF: 1140 if ((HeadEd != Ed) && HeadEd && Ed) { 1141 while(HeadEd->NextED != (UINT32)(UINTN)Ed) { 1142 HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED); 1143 } 1144 HeadEd->NextED = Ed->NextED; 1145 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); 1146 } 1147 1148UNMAP_OHCI_XBUFF: 1149 Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); 1150 1151EXIT: 1152 return Status; 1153} 1154 1155/** 1156 1157 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. 1158 1159 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1160 @param DeviceAddress Represents the address of the target device on the USB, 1161 which is assigned during USB enumeration. 1162 @param EndPointAddress The combination of an endpoint number and an endpoint 1163 direction of the target USB device. Each endpoint address 1164 supports data transfer in one direction except the 1165 control endpoint (whose default endpoint address is 0). 1166 It is the caller's responsibility to make sure that 1167 the EndPointAddress represents an interrupt endpoint. 1168 @param IsSlowDevice Indicates whether the target device is slow device 1169 or full-speed device. 1170 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint 1171 is capable of sending or receiving. 1172 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between 1173 the host and the target interrupt endpoint. 1174 If FALSE, the specified asynchronous interrupt pipe 1175 is canceled. 1176 @param DataToggle A pointer to the data toggle value. On input, it is valid 1177 when IsNewTransfer is TRUE, and it indicates the initial 1178 data toggle value the asynchronous interrupt transfer 1179 should adopt. 1180 On output, it is valid when IsNewTransfer is FALSE, 1181 and it is updated to indicate the data toggle value of 1182 the subsequent asynchronous interrupt transfer. 1183 @param PollingInterval Indicates the interval, in milliseconds, that the 1184 asynchronous interrupt transfer is polled. 1185 This parameter is required when IsNewTransfer is TRUE. 1186 @param DataLength Indicates the length of data to be received at the 1187 rate specified by PollingInterval from the target 1188 asynchronous interrupt endpoint. This parameter 1189 is only required when IsNewTransfer is TRUE. 1190 @param CallBackFunction The Callback function.This function is called at the 1191 rate specified by PollingInterval.This parameter is 1192 only required when IsNewTransfer is TRUE. 1193 @param Context The context that is passed to the CallBackFunction. 1194 This is an optional parameter and may be NULL. 1195 1196 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully 1197 submitted or canceled. 1198 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 1199 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1200 1201**/ 1202 1203 1204EFI_STATUS 1205EFIAPI 1206OhciAsyncInterruptTransfer ( 1207 IN EFI_USB_HC_PROTOCOL *This, 1208 IN UINT8 DeviceAddress, 1209 IN UINT8 EndPointAddress, 1210 IN BOOLEAN IsSlowDevice, 1211 IN UINT8 MaxPacketLength, 1212 IN BOOLEAN IsNewTransfer, 1213 IN OUT UINT8 *DataToggle OPTIONAL, 1214 IN UINTN PollingInterval OPTIONAL, 1215 IN UINTN DataLength OPTIONAL, 1216 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, 1217 IN VOID *Context OPTIONAL 1218 ) 1219{ 1220 EFI_STATUS Status; 1221 USB_OHCI_HC_DEV *Ohc; 1222 VOID *UCBuffer; 1223 1224 if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 || 1225 (IsNewTransfer && (DataLength == 0 || 1226 (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) { 1227 return EFI_INVALID_PARAMETER; 1228 } 1229 1230 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1231 if ( IsNewTransfer ) { 1232 UCBuffer = AllocatePool(DataLength); 1233 if (UCBuffer == NULL) { 1234 return EFI_OUT_OF_RESOURCES; 1235 } 1236 } else { 1237 UCBuffer = NULL; 1238 } 1239 Status = OhciInterruptTransfer ( 1240 Ohc, 1241 DeviceAddress, 1242 EndPointAddress, 1243 IsSlowDevice, 1244 MaxPacketLength, 1245 IsNewTransfer, 1246 DataToggle, 1247 PollingInterval, 1248 UCBuffer, 1249 DataLength, 1250 CallBackFunction, 1251 Context, 1252 TRUE, 1253 NULL, 1254 NULL 1255 ); 1256 if ( IsNewTransfer ) { 1257 if (EFI_ERROR(Status)) { 1258 gBS->FreePool (UCBuffer); 1259 } 1260 } 1261 return Status; 1262} 1263 1264 1265/** 1266 1267 Submits synchronous interrupt transfer to an interrupt endpoint 1268 of a USB device. 1269 1270 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1271 @param DeviceAddress Represents the address of the target device on the USB, 1272 which is assigned during USB enumeration. 1273 @param EndPointAddress The combination of an endpoint number and an endpoint 1274 direction of the target USB device. Each endpoint 1275 address supports data transfer in one direction 1276 except the control endpoint (whose default 1277 endpoint address is 0). It is the caller's responsibility 1278 to make sure that the EndPointAddress represents 1279 an interrupt endpoint. 1280 @param IsSlowDevice Indicates whether the target device is slow device 1281 or full-speed device. 1282 @param MaxPacketLength Indicates the maximum packet size the target endpoint 1283 is capable of sending or receiving. 1284 @param Data A pointer to the buffer of data that will be transmitted 1285 to USB device or received from USB device. 1286 @param DataLength On input, the size, in bytes, of the data buffer specified 1287 by Data. On output, the number of bytes transferred. 1288 @param DataToggle A pointer to the data toggle value. On input, it indicates 1289 the initial data toggle value the synchronous interrupt 1290 transfer should adopt; 1291 on output, it is updated to indicate the data toggle value 1292 of the subsequent synchronous interrupt transfer. 1293 @param TimeOut Indicates the maximum time, in microseconds, which the 1294 transfer is allowed to complete. 1295 @param TransferResult A pointer to the detailed result information from 1296 the synchronous interrupt transfer. 1297 1298 @retval EFI_UNSUPPORTED This interface not available. 1299 @retval EFI_INVALID_PARAMETER Parameters not follow spec 1300 1301**/ 1302 1303 1304EFI_STATUS 1305EFIAPI 1306OhciSyncInterruptTransfer ( 1307 IN EFI_USB_HC_PROTOCOL *This, 1308 IN UINT8 DeviceAddress, 1309 IN UINT8 EndPointAddress, 1310 IN BOOLEAN IsSlowDevice, 1311 IN UINT8 MaxPacketLength, 1312 IN OUT VOID *Data, 1313 IN OUT UINTN *DataLength, 1314 IN OUT UINT8 *DataToggle, 1315 IN UINTN TimeOut, 1316 OUT UINT32 *TransferResult 1317 ) 1318{ 1319 USB_OHCI_HC_DEV *Ohc; 1320 EFI_STATUS Status; 1321 ED_DESCRIPTOR *Ed; 1322 TD_DESCRIPTOR *HeadTd; 1323 OHCI_ED_RESULT EdResult; 1324 VOID *UCBuffer; 1325 1326 if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 || 1327 (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) || 1328 DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) { 1329 return EFI_INVALID_PARAMETER; 1330 } 1331 1332 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1333 UCBuffer = AllocatePool (*DataLength); 1334 if (UCBuffer == NULL) { 1335 return EFI_OUT_OF_RESOURCES; 1336 } 1337 Status = OhciInterruptTransfer ( 1338 Ohc, 1339 DeviceAddress, 1340 EndPointAddress, 1341 IsSlowDevice, 1342 MaxPacketLength, 1343 TRUE, 1344 DataToggle, 1345 1, 1346 UCBuffer, 1347 *DataLength, 1348 NULL, 1349 NULL, 1350 FALSE, 1351 &Ed, 1352 &HeadTd 1353 ); 1354 1355 if (!EFI_ERROR (Status)) { 1356 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); 1357 while (Status == EFI_NOT_READY && TimeOut > 0) { 1358 gBS->Stall (1000); 1359 TimeOut--; 1360 Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); 1361 } 1362 1363 *TransferResult = ConvertErrorCode (EdResult.ErrorCode); 1364 } 1365 CopyMem(Data, UCBuffer, *DataLength); 1366 Status = OhciInterruptTransfer ( 1367 Ohc, 1368 DeviceAddress, 1369 EndPointAddress, 1370 IsSlowDevice, 1371 MaxPacketLength, 1372 FALSE, 1373 DataToggle, 1374 0, 1375 NULL, 1376 0, 1377 NULL, 1378 NULL, 1379 FALSE, 1380 NULL, 1381 NULL 1382 ); 1383 1384 return Status; 1385} 1386/** 1387 1388 Submits isochronous transfer to a target USB device. 1389 1390 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1391 @param DeviceAddress Represents the address of the target device on the USB, 1392 which is assigned during USB enumeration. 1393 @param EndPointAddress End point address 1394 @param MaximumPacketLength Indicates the maximum packet size that the 1395 default control transfer endpoint is capable of 1396 sending or receiving. 1397 @param Data A pointer to the buffer of data that will be transmitted 1398 to USB device or received from USB device. 1399 @param DataLength Indicates the size, in bytes, of the data buffer 1400 specified by Data. 1401 @param TransferResult A pointer to the detailed result information generated 1402 by this control transfer. 1403 1404 @retval EFI_UNSUPPORTED This interface not available 1405 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL 1406 1407**/ 1408 1409 1410EFI_STATUS 1411EFIAPI 1412OhciIsochronousTransfer ( 1413 IN EFI_USB_HC_PROTOCOL *This, 1414 IN UINT8 DeviceAddress, 1415 IN UINT8 EndPointAddress, 1416 IN UINT8 MaximumPacketLength, 1417 IN OUT VOID *Data, 1418 IN OUT UINTN DataLength, 1419 OUT UINT32 *TransferResult 1420 ) 1421{ 1422 if (Data == NULL || DataLength == 0 || TransferResult == NULL) { 1423 return EFI_INVALID_PARAMETER; 1424 } 1425 1426 return EFI_UNSUPPORTED; 1427} 1428 1429/** 1430 1431 Submits Async isochronous transfer to a target USB device. 1432 1433 @param his A pointer to the EFI_USB_HC_PROTOCOL instance. 1434 @param DeviceAddress Represents the address of the target device on the USB, 1435 which is assigned during USB enumeration. 1436 @param EndPointAddress End point address 1437 @param MaximumPacketLength Indicates the maximum packet size that the 1438 default control transfer endpoint is capable of 1439 sending or receiving. 1440 @param Data A pointer to the buffer of data that will be transmitted 1441 to USB device or received from USB device. 1442 @param IsochronousCallBack When the transfer complete, the call back function will be called 1443 @param Context Pass to the call back function as parameter 1444 1445 @retval EFI_UNSUPPORTED This interface not available 1446 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 1447 1448**/ 1449 1450EFI_STATUS 1451EFIAPI 1452OhciAsyncIsochronousTransfer ( 1453 IN EFI_USB_HC_PROTOCOL *This, 1454 IN UINT8 DeviceAddress, 1455 IN UINT8 EndPointAddress, 1456 IN UINT8 MaximumPacketLength, 1457 IN OUT VOID *Data, 1458 IN OUT UINTN DataLength, 1459 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, 1460 IN VOID *Context OPTIONAL 1461 ) 1462{ 1463 1464 if (Data == NULL || DataLength == 0) { 1465 return EFI_INVALID_PARAMETER; 1466 } 1467 1468 return EFI_UNSUPPORTED; 1469} 1470 1471/** 1472 1473 Retrieves the number of root hub ports. 1474 1475 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1476 @param NumOfPorts A pointer to the number of the root hub ports. 1477 1478 @retval EFI_SUCCESS The port number was retrieved successfully. 1479**/ 1480EFI_STATUS 1481EFIAPI 1482OhciGetRootHubNumOfPorts ( 1483 IN EFI_USB_HC_PROTOCOL *This, 1484 OUT UINT8 *NumOfPorts 1485 ) 1486{ 1487 USB_OHCI_HC_DEV *Ohc; 1488 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1489 1490 if (NumOfPorts == NULL) { 1491 return EFI_INVALID_PARAMETER; 1492 } 1493 1494 *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); 1495 1496 return EFI_SUCCESS; 1497} 1498/** 1499 1500 Retrieves the current status of a USB root hub port. 1501 1502 @param This A pointer to the EFI_USB_HC_PROTOCOL. 1503 @param PortNumber Specifies the root hub port from which the status 1504 is to be retrieved. This value is zero-based. For example, 1505 if a root hub has two ports, then the first port is numbered 0, 1506 and the second port is numbered 1. 1507 @param PortStatus A pointer to the current port status bits and 1508 port status change bits. 1509 1510 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber 1511 was returned in PortStatus. 1512 @retval EFI_INVALID_PARAMETER Port number not valid 1513**/ 1514 1515 1516EFI_STATUS 1517EFIAPI 1518OhciGetRootHubPortStatus ( 1519 IN EFI_USB_HC_PROTOCOL *This, 1520 IN UINT8 PortNumber, 1521 OUT EFI_USB_PORT_STATUS *PortStatus 1522 ) 1523{ 1524 USB_OHCI_HC_DEV *Ohc; 1525 UINT8 NumOfPorts; 1526 1527 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1528 1529 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1530 if (PortNumber >= NumOfPorts) { 1531 return EFI_INVALID_PARAMETER; 1532 } 1533 PortStatus->PortStatus = 0; 1534 PortStatus->PortChangeStatus = 0; 1535 1536 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) { 1537 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; 1538 } 1539 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) { 1540 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; 1541 } 1542 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) { 1543 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; 1544 } 1545 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) { 1546 PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; 1547 } 1548 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) { 1549 PortStatus->PortStatus |= USB_PORT_STAT_RESET; 1550 } 1551 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) { 1552 PortStatus->PortStatus |= USB_PORT_STAT_POWER; 1553 } 1554 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) { 1555 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; 1556 } 1557 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) { 1558 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; 1559 } 1560 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) { 1561 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; 1562 } 1563 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) { 1564 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND; 1565 } 1566 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) { 1567 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; 1568 } 1569 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) { 1570 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; 1571 } 1572 1573 return EFI_SUCCESS; 1574} 1575/** 1576 1577 Sets a feature for the specified root hub port. 1578 1579 @param This A pointer to the EFI_USB_HC_PROTOCOL. 1580 @param PortNumber Specifies the root hub port whose feature 1581 is requested to be set. 1582 @param PortFeature Indicates the feature selector associated 1583 with the feature set request. 1584 1585 @retval EFI_SUCCESS The feature specified by PortFeature was set for the 1586 USB root hub port specified by PortNumber. 1587 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue 1588 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 1589**/ 1590EFI_STATUS 1591EFIAPI 1592OhciSetRootHubPortFeature ( 1593 IN EFI_USB_HC_PROTOCOL *This, 1594 IN UINT8 PortNumber, 1595 IN EFI_USB_PORT_FEATURE PortFeature 1596 ) 1597{ 1598 USB_OHCI_HC_DEV *Ohc; 1599 EFI_STATUS Status; 1600 UINT8 NumOfPorts; 1601 UINTN RetryTimes; 1602 1603 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1604 if (PortNumber >= NumOfPorts) { 1605 return EFI_INVALID_PARAMETER; 1606 } 1607 1608 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1609 1610 Status = EFI_SUCCESS; 1611 1612 1613 switch (PortFeature) { 1614 case EfiUsbPortPower: 1615 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER); 1616 1617 // 1618 // Verify the state 1619 // 1620 RetryTimes = 0; 1621 do { 1622 gBS->Stall (1000); 1623 RetryTimes++; 1624 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 && 1625 RetryTimes < MAX_RETRY_TIMES); 1626 1627 if (RetryTimes >= MAX_RETRY_TIMES) { 1628 return EFI_DEVICE_ERROR; 1629 } 1630 break; 1631 1632 case EfiUsbPortReset: 1633 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET); 1634 1635 // 1636 // Verify the state 1637 // 1638 RetryTimes = 0; 1639 do { 1640 gBS->Stall (1000); 1641 RetryTimes++; 1642 } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 || 1643 OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) && 1644 RetryTimes < MAX_RETRY_TIMES); 1645 1646 if (RetryTimes >= MAX_RETRY_TIMES) { 1647 return EFI_DEVICE_ERROR; 1648 } 1649 1650 OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); 1651 break; 1652 1653 case EfiUsbPortEnable: 1654 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE); 1655 1656 // 1657 // Verify the state 1658 // 1659 RetryTimes = 0; 1660 do { 1661 gBS->Stall (1000); 1662 RetryTimes++; 1663 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 && 1664 RetryTimes < MAX_RETRY_TIMES); 1665 1666 if (RetryTimes >= MAX_RETRY_TIMES) { 1667 return EFI_DEVICE_ERROR; 1668 } 1669 break; 1670 1671 1672 case EfiUsbPortSuspend: 1673 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND); 1674 1675 // 1676 // Verify the state 1677 // 1678 RetryTimes = 0; 1679 do { 1680 gBS->Stall (1000); 1681 RetryTimes++; 1682 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 && 1683 RetryTimes < MAX_RETRY_TIMES); 1684 1685 if (RetryTimes >= MAX_RETRY_TIMES) { 1686 return EFI_DEVICE_ERROR; 1687 } 1688 break; 1689 1690 default: 1691 return EFI_INVALID_PARAMETER; 1692 } 1693 1694 return Status; 1695} 1696 1697/** 1698 1699 Clears a feature for the specified root hub port. 1700 1701 @param This A pointer to the EFI_USB_HC_PROTOCOL instance. 1702 @param PortNumber Specifies the root hub port whose feature 1703 is requested to be cleared. 1704 @param PortFeature Indicates the feature selector associated with the 1705 feature clear request. 1706 1707 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the 1708 USB root hub port specified by PortNumber. 1709 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 1710 @retval EFI_DEVICE_ERROR Some error happened when clearing feature 1711**/ 1712EFI_STATUS 1713EFIAPI 1714OhciClearRootHubPortFeature ( 1715 IN EFI_USB_HC_PROTOCOL *This, 1716 IN UINT8 PortNumber, 1717 IN EFI_USB_PORT_FEATURE PortFeature 1718 ) 1719{ 1720 USB_OHCI_HC_DEV *Ohc; 1721 EFI_STATUS Status; 1722 UINT8 NumOfPorts; 1723 UINTN RetryTimes; 1724 1725 1726 OhciGetRootHubNumOfPorts (This, &NumOfPorts); 1727 if (PortNumber >= NumOfPorts) { 1728 return EFI_INVALID_PARAMETER; 1729 } 1730 1731 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 1732 1733 Status = EFI_SUCCESS; 1734 1735 switch (PortFeature) { 1736 case EfiUsbPortEnable: 1737 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE); 1738 1739 // 1740 // Verify the state 1741 // 1742 RetryTimes = 0; 1743 do { 1744 gBS->Stall (1000); 1745 RetryTimes++; 1746 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 && 1747 RetryTimes < MAX_RETRY_TIMES); 1748 1749 if (RetryTimes >= MAX_RETRY_TIMES) { 1750 return EFI_DEVICE_ERROR; 1751 } 1752 break; 1753 1754 case EfiUsbPortSuspend: 1755 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS); 1756 1757 // 1758 // Verify the state 1759 // 1760 RetryTimes = 0; 1761 do { 1762 gBS->Stall (1000); 1763 RetryTimes++; 1764 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 && 1765 RetryTimes < MAX_RETRY_TIMES); 1766 1767 if (RetryTimes >= MAX_RETRY_TIMES) { 1768 return EFI_DEVICE_ERROR; 1769 } 1770 break; 1771 1772 case EfiUsbPortReset: 1773 break; 1774 1775 case EfiUsbPortPower: 1776 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER); 1777 1778 // 1779 // Verify the state 1780 // 1781 RetryTimes = 0; 1782 do { 1783 gBS->Stall (1000); 1784 RetryTimes++; 1785 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 && 1786 RetryTimes < MAX_RETRY_TIMES); 1787 1788 if (RetryTimes >= MAX_RETRY_TIMES) { 1789 return EFI_DEVICE_ERROR; 1790 } 1791 break; 1792 1793 case EfiUsbPortConnectChange: 1794 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE); 1795 1796 // 1797 // Verify the state 1798 // 1799 RetryTimes = 0; 1800 do { 1801 gBS->Stall (1000); 1802 RetryTimes++; 1803 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 && 1804 RetryTimes < MAX_RETRY_TIMES); 1805 1806 if (RetryTimes >= MAX_RETRY_TIMES) { 1807 return EFI_DEVICE_ERROR; 1808 } 1809 break; 1810 1811 case EfiUsbPortResetChange: 1812 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); 1813 1814 // 1815 // Verify the state 1816 // 1817 RetryTimes = 0; 1818 do { 1819 gBS->Stall (1000); 1820 RetryTimes++; 1821 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 && 1822 RetryTimes < MAX_RETRY_TIMES); 1823 1824 if (RetryTimes >= MAX_RETRY_TIMES) { 1825 return EFI_DEVICE_ERROR; 1826 } 1827 break; 1828 1829 1830 case EfiUsbPortEnableChange: 1831 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE); 1832 1833 // 1834 // Verify the state 1835 // 1836 RetryTimes = 0; 1837 do { 1838 gBS->Stall (1000); 1839 RetryTimes++; 1840 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 && 1841 RetryTimes < MAX_RETRY_TIMES); 1842 1843 if (RetryTimes >= MAX_RETRY_TIMES) { 1844 return EFI_DEVICE_ERROR; 1845 } 1846 break; 1847 1848 case EfiUsbPortSuspendChange: 1849 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE); 1850 1851 // 1852 // Verify the state 1853 // 1854 RetryTimes = 0; 1855 do { 1856 gBS->Stall (1000); 1857 RetryTimes++; 1858 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 && 1859 RetryTimes < MAX_RETRY_TIMES); 1860 1861 if (RetryTimes >= MAX_RETRY_TIMES) { 1862 return EFI_DEVICE_ERROR; 1863 } 1864 break; 1865 1866 case EfiUsbPortOverCurrentChange: 1867 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE); 1868 1869 // 1870 // Verify the state 1871 // 1872 RetryTimes = 0; 1873 do { 1874 gBS->Stall (1000); 1875 RetryTimes++; 1876 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 && 1877 RetryTimes < MAX_RETRY_TIMES); 1878 1879 if (RetryTimes >= MAX_RETRY_TIMES) { 1880 return EFI_DEVICE_ERROR; 1881 } 1882 break; 1883 1884 default: 1885 return EFI_INVALID_PARAMETER; 1886 } 1887 1888 return Status; 1889} 1890 1891EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = { 1892 OHCIDriverBindingSupported, 1893 OHCIDriverBindingStart, 1894 OHCIDriverBindingStop, 1895 0x10, 1896 NULL, 1897 NULL 1898}; 1899 1900 1901/** 1902 Entry point for EFI drivers. 1903 1904 @param ImageHandle EFI_HANDLE. 1905 @param SystemTable EFI_SYSTEM_TABLE. 1906 1907 @retval EFI_SUCCESS Driver is successfully loaded. 1908 @return Others Failed. 1909 1910**/ 1911EFI_STATUS 1912EFIAPI 1913OHCIDriverEntryPoint ( 1914 IN EFI_HANDLE ImageHandle, 1915 IN EFI_SYSTEM_TABLE *SystemTable 1916 ) 1917{ 1918 return EfiLibInstallDriverBindingComponentName2 ( 1919 ImageHandle, 1920 SystemTable, 1921 &gOhciDriverBinding, 1922 ImageHandle, 1923 &gOhciComponentName, 1924 &gOhciComponentName2 1925 ); 1926} 1927 1928 1929/** 1930 Test to see if this driver supports ControllerHandle. Any 1931 ControllerHandle that has UsbHcProtocol installed will be supported. 1932 1933 @param This Protocol instance pointer. 1934 @param Controller Handle of device to test. 1935 @param RemainingDevicePath Not used. 1936 1937 @return EFI_SUCCESS This driver supports this device. 1938 @return EFI_UNSUPPORTED This driver does not support this device. 1939 1940**/ 1941EFI_STATUS 1942EFIAPI 1943OHCIDriverBindingSupported ( 1944 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1945 IN EFI_HANDLE Controller, 1946 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 1947 ) 1948{ 1949 EFI_STATUS Status; 1950 EFI_PCI_IO_PROTOCOL *PciIo; 1951 USB_CLASSC UsbClassCReg; 1952 // 1953 // Test whether there is PCI IO Protocol attached on the controller handle. 1954 // 1955 Status = gBS->OpenProtocol ( 1956 Controller, 1957 &gEfiPciIoProtocolGuid, 1958 (VOID **) &PciIo, 1959 This->DriverBindingHandle, 1960 Controller, 1961 EFI_OPEN_PROTOCOL_BY_DRIVER 1962 ); 1963 1964 if (EFI_ERROR (Status)) { 1965 return EFI_UNSUPPORTED; 1966 } 1967 1968 Status = PciIo->Pci.Read ( 1969 PciIo, 1970 EfiPciIoWidthUint8, 1971 PCI_CLASSCODE_OFFSET, 1972 sizeof (USB_CLASSC) / sizeof (UINT8), 1973 &UsbClassCReg 1974 ); 1975 1976 if (EFI_ERROR (Status)) { 1977 Status = EFI_UNSUPPORTED; 1978 goto ON_EXIT; 1979 } 1980 // 1981 // Test whether the controller belongs to OHCI type 1982 // 1983 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || 1984 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || 1985 (UsbClassCReg.ProgInterface != PCI_IF_OHCI) 1986 ) { 1987 1988 Status = EFI_UNSUPPORTED; 1989 } 1990ON_EXIT: 1991 gBS->CloseProtocol ( 1992 Controller, 1993 &gEfiPciIoProtocolGuid, 1994 This->DriverBindingHandle, 1995 Controller 1996 ); 1997 1998 return Status; 1999 2000} 2001 2002/** 2003 2004 Allocate and initialize the empty OHCI device. 2005 2006 @param PciIo The PCIIO to use. 2007 @param OriginalPciAttributes The original PCI attributes. 2008 2009 @return Allocated OHCI device If err, return NULL. 2010 2011**/ 2012 2013USB_OHCI_HC_DEV * 2014OhciAllocateDev ( 2015 IN EFI_PCI_IO_PROTOCOL *PciIo, 2016 IN UINT64 OriginalPciAttributes 2017 ) 2018{ 2019 USB_OHCI_HC_DEV *Ohc; 2020 EFI_STATUS Status; 2021 VOID *Buf; 2022 EFI_PHYSICAL_ADDRESS PhyAddr; 2023 VOID *Map; 2024 UINTN Pages; 2025 UINTN Bytes; 2026 2027 Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV)); 2028 if (Ohc == NULL) { 2029 return NULL; 2030 } 2031 2032 Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE; 2033 Ohc->PciIo = PciIo; 2034 2035 Ohc->UsbHc.Reset = OhciReset; 2036 Ohc->UsbHc.GetState = OhciGetState; 2037 Ohc->UsbHc.SetState = OhciSetState; 2038 Ohc->UsbHc.ControlTransfer = OhciControlTransfer; 2039 Ohc->UsbHc.BulkTransfer = OhciBulkTransfer; 2040 Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer; 2041 Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer; 2042 Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer; 2043 Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer; 2044 Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; 2045 Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus; 2046 Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature; 2047 Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature; 2048 Ohc->UsbHc.MajorRevision = 0x1; 2049 Ohc->UsbHc.MinorRevision = 0x1; 2050 2051 Ohc->OriginalPciAttributes = OriginalPciAttributes; 2052 2053 Ohc->HccaMemoryBlock = NULL; 2054 Ohc->HccaMemoryMapping = NULL; 2055 Ohc->HccaMemoryBuf = NULL; 2056 Ohc->HccaMemoryPages = 0; 2057 Ohc->InterruptContextList = NULL; 2058 Ohc->ControllerNameTable = NULL; 2059 Ohc->HouseKeeperTimer = NULL; 2060 2061 Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0); 2062 if(Ohc->MemPool == NULL) { 2063 goto FREE_DEV_BUFFER; 2064 } 2065 2066 Bytes = 4096; 2067 Pages = EFI_SIZE_TO_PAGES (Bytes); 2068 2069 Status = PciIo->AllocateBuffer ( 2070 PciIo, 2071 AllocateAnyPages, 2072 EfiBootServicesData, 2073 Pages, 2074 &Buf, 2075 0 2076 ); 2077 2078 if (EFI_ERROR (Status)) { 2079 goto FREE_MEM_POOL; 2080 } 2081 2082 Status = PciIo->Map ( 2083 PciIo, 2084 EfiPciIoOperationBusMasterCommonBuffer, 2085 Buf, 2086 &Bytes, 2087 &PhyAddr, 2088 &Map 2089 ); 2090 2091 if (EFI_ERROR (Status) || (Bytes != 4096)) { 2092 goto FREE_MEM_PAGE; 2093 } 2094 2095 Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr; 2096 Ohc->HccaMemoryMapping = Map; 2097 Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf; 2098 Ohc->HccaMemoryPages = Pages; 2099 2100 return Ohc; 2101 2102FREE_MEM_PAGE: 2103 PciIo->FreeBuffer (PciIo, Pages, Buf); 2104FREE_MEM_POOL: 2105 UsbHcFreeMemPool (Ohc->MemPool); 2106FREE_DEV_BUFFER: 2107 FreePool(Ohc); 2108 2109 return NULL; 2110} 2111/** 2112 2113 Free the OHCI device and release its associated resources. 2114 2115 @param Ohc The OHCI device to release. 2116 2117**/ 2118VOID 2119OhciFreeDev ( 2120 IN USB_OHCI_HC_DEV *Ohc 2121 ) 2122{ 2123 OhciFreeFixedIntMemory (Ohc); 2124 2125 if (Ohc->HouseKeeperTimer != NULL) { 2126 gBS->CloseEvent (Ohc->HouseKeeperTimer); 2127 } 2128 2129 if (Ohc->ExitBootServiceEvent != NULL) { 2130 gBS->CloseEvent (Ohc->ExitBootServiceEvent); 2131 } 2132 2133 if (Ohc->MemPool != NULL) { 2134 UsbHcFreeMemPool (Ohc->MemPool); 2135 } 2136 2137 if (Ohc->HccaMemoryMapping != NULL ) { 2138 Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf); 2139 } 2140 2141 if (Ohc->ControllerNameTable != NULL) { 2142 FreeUnicodeStringTable (Ohc->ControllerNameTable); 2143 } 2144 2145 FreePool (Ohc); 2146} 2147/** 2148 2149 Uninstall all Ohci Interface. 2150 2151 @param Controller Controller handle. 2152 @param This Protocol instance pointer. 2153 2154**/ 2155VOID 2156OhciCleanDevUp ( 2157 IN EFI_HANDLE Controller, 2158 IN EFI_USB_HC_PROTOCOL *This 2159 ) 2160{ 2161 USB_OHCI_HC_DEV *Ohc; 2162 2163 // 2164 // Retrieve private context structure 2165 // 2166 Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); 2167 2168 // 2169 // Uninstall the USB_HC and USB_HC2 protocol 2170 // 2171 gBS->UninstallProtocolInterface ( 2172 Controller, 2173 &gEfiUsbHcProtocolGuid, 2174 &Ohc->UsbHc 2175 ); 2176 2177 // 2178 // Cancel the timer event 2179 // 2180 gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0); 2181 2182 // 2183 // Stop the host controller 2184 // 2185 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); 2186 This->Reset (This, EFI_USB_HC_RESET_GLOBAL); 2187 This->SetState (This, EfiUsbHcStateHalt); 2188 2189 // 2190 // Free resources 2191 // 2192 OhciFreeDynamicIntMemory (Ohc); 2193 2194 // 2195 // Restore original PCI attributes 2196 // 2197 Ohc->PciIo->Attributes ( 2198 Ohc->PciIo, 2199 EfiPciIoAttributeOperationSet, 2200 Ohc->OriginalPciAttributes, 2201 NULL 2202 ); 2203 2204 // 2205 // Free the private context structure 2206 // 2207 OhciFreeDev (Ohc); 2208} 2209 2210/** 2211 2212 One notified function to stop the Host Controller when gBS->ExitBootServices() called. 2213 2214 @param Event Pointer to this event 2215 @param Context Event hanlder private data 2216**/ 2217VOID 2218EFIAPI 2219OhcExitBootService ( 2220 EFI_EVENT Event, 2221 VOID *Context 2222 ) 2223{ 2224 USB_OHCI_HC_DEV *Ohc; 2225 EFI_USB_HC_PROTOCOL *UsbHc; 2226 Ohc = (USB_OHCI_HC_DEV *) Context; 2227 2228 UsbHc = &Ohc->UsbHc; 2229 // 2230 // Stop the Host Controller 2231 // 2232 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); 2233 OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); 2234 UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL); 2235 UsbHc->SetState (UsbHc, EfiUsbHcStateHalt); 2236 2237 return; 2238} 2239 2240 2241/** 2242 Starting the Usb OHCI Driver. 2243 2244 @param This Protocol instance pointer. 2245 @param Controller Handle of device to test. 2246 @param RemainingDevicePath Not used. 2247 2248 @retval EFI_SUCCESS This driver supports this device. 2249 @retval EFI_UNSUPPORTED This driver does not support this device. 2250 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. 2251 EFI_OUT_OF_RESOURCES- Failed due to resource shortage. 2252 2253**/ 2254EFI_STATUS 2255EFIAPI 2256OHCIDriverBindingStart ( 2257 IN EFI_DRIVER_BINDING_PROTOCOL *This, 2258 IN EFI_HANDLE Controller, 2259 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 2260 ) 2261{ 2262 EFI_STATUS Status; 2263 EFI_PCI_IO_PROTOCOL *PciIo; 2264 USB_OHCI_HC_DEV *Ohc; 2265 UINT64 Supports; 2266 UINT64 OriginalPciAttributes; 2267 BOOLEAN PciAttributesSaved; 2268 2269 // 2270 // Open PCIIO, then enable the HC device and turn off emulation 2271 // 2272 Ohc = NULL; 2273 Status = gBS->OpenProtocol ( 2274 Controller, 2275 &gEfiPciIoProtocolGuid, 2276 (VOID **) &PciIo, 2277 This->DriverBindingHandle, 2278 Controller, 2279 EFI_OPEN_PROTOCOL_BY_DRIVER 2280 ); 2281 2282 if (EFI_ERROR (Status)) { 2283 return Status; 2284 } 2285 2286 PciAttributesSaved = FALSE; 2287 // 2288 // Save original PCI attributes 2289 // 2290 Status = PciIo->Attributes ( 2291 PciIo, 2292 EfiPciIoAttributeOperationGet, 2293 0, 2294 &OriginalPciAttributes 2295 ); 2296 2297 if (EFI_ERROR (Status)) { 2298 goto CLOSE_PCIIO; 2299 } 2300 PciAttributesSaved = TRUE; 2301 2302 // 2303 // Robustnesss improvement such as for UoL 2304 // Default is not required. 2305 // 2306 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) { 2307 // OhciTurnOffUsbEmulation (PciIo); 2308 //} 2309 2310 Status = PciIo->Attributes ( 2311 PciIo, 2312 EfiPciIoAttributeOperationSupported, 2313 0, 2314 &Supports 2315 ); 2316 if (!EFI_ERROR (Status)) { 2317 Supports &= EFI_PCI_DEVICE_ENABLE; 2318 Status = PciIo->Attributes ( 2319 PciIo, 2320 EfiPciIoAttributeOperationEnable, 2321 Supports, 2322 NULL 2323 ); 2324 } 2325 2326 if (EFI_ERROR (Status)) { 2327 goto CLOSE_PCIIO; 2328 } 2329 // 2330 //Allocate memory for OHC private data structure 2331 // 2332 Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes); 2333 if (Ohc == NULL){ 2334 Status = EFI_OUT_OF_RESOURCES; 2335 goto CLOSE_PCIIO; 2336 } 2337 2338 //Status = OhciInitializeInterruptList ( Uhc ); 2339 //if (EFI_ERROR (Status)) { 2340 // goto FREE_OHC; 2341 //} 2342 2343 // 2344 // Set 0.01 s timer 2345 // 2346 Status = gBS->CreateEvent ( 2347 EVT_TIMER | EVT_NOTIFY_SIGNAL, 2348 TPL_NOTIFY, 2349 OhciHouseKeeper, 2350 Ohc, 2351 &Ohc->HouseKeeperTimer 2352 ); 2353 if (EFI_ERROR (Status)) { 2354 goto FREE_OHC; 2355 } 2356 2357 Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10); 2358 if (EFI_ERROR (Status)) { 2359 goto FREE_OHC; 2360 } 2361 2362 // 2363 //Install Host Controller Protocol 2364 // 2365 Status = gBS->InstallProtocolInterface ( 2366 &Controller, 2367 &gEfiUsbHcProtocolGuid, 2368 EFI_NATIVE_INTERFACE, 2369 &Ohc->UsbHc 2370 ); 2371 if (EFI_ERROR (Status)) { 2372 DEBUG ((EFI_D_INFO, "Install protocol error")); 2373 goto FREE_OHC; 2374 } 2375 // 2376 // Create event to stop the HC when exit boot service. 2377 // 2378 Status = gBS->CreateEventEx ( 2379 EVT_NOTIFY_SIGNAL, 2380 TPL_NOTIFY, 2381 OhcExitBootService, 2382 Ohc, 2383 &gEfiEventExitBootServicesGuid, 2384 &Ohc->ExitBootServiceEvent 2385 ); 2386 if (EFI_ERROR (Status)) { 2387 DEBUG ((EFI_D_INFO, "Create exit boot event error")); 2388 goto UNINSTALL_USBHC; 2389 } 2390 AddUnicodeString2 ( 2391 "eng", 2392 gOhciComponentName.SupportedLanguages, 2393 &Ohc->ControllerNameTable, 2394 L"Usb Universal Host Controller", 2395 TRUE 2396 ); 2397 AddUnicodeString2 ( 2398 "en", 2399 gOhciComponentName2.SupportedLanguages, 2400 &Ohc->ControllerNameTable, 2401 L"Usb Universal Host Controller", 2402 FALSE 2403 ); 2404 2405 return EFI_SUCCESS; 2406 2407UNINSTALL_USBHC: 2408 gBS->UninstallMultipleProtocolInterfaces ( 2409 Controller, 2410 &gEfiUsbHcProtocolGuid, 2411 &Ohc->UsbHc, 2412 NULL 2413 ); 2414 2415FREE_OHC: 2416 OhciFreeDev (Ohc); 2417 2418CLOSE_PCIIO: 2419 if (PciAttributesSaved) { 2420 // 2421 // Restore original PCI attributes 2422 // 2423 PciIo->Attributes ( 2424 PciIo, 2425 EfiPciIoAttributeOperationSet, 2426 OriginalPciAttributes, 2427 NULL 2428 ); 2429 } 2430 2431 gBS->CloseProtocol ( 2432 Controller, 2433 &gEfiPciIoProtocolGuid, 2434 This->DriverBindingHandle, 2435 Controller 2436 ); 2437 return Status; 2438} 2439 2440/** 2441 Stop this driver on ControllerHandle. Support stoping any child handles 2442 created by this driver. 2443 2444 @param This Protocol instance pointer. 2445 @param Controller Handle of device to stop driver on. 2446 @param NumberOfChildren Number of Children in the ChildHandleBuffer. 2447 @param ChildHandleBuffer List of handles for the children we need to stop. 2448 2449 @return EFI_SUCCESS 2450 @return others 2451 2452**/ 2453EFI_STATUS 2454EFIAPI 2455OHCIDriverBindingStop ( 2456 IN EFI_DRIVER_BINDING_PROTOCOL *This, 2457 IN EFI_HANDLE Controller, 2458 IN UINTN NumberOfChildren, 2459 IN EFI_HANDLE *ChildHandleBuffer 2460 ) 2461{ 2462 EFI_STATUS Status; 2463 EFI_USB_HC_PROTOCOL *UsbHc; 2464 2465 Status = gBS->OpenProtocol ( 2466 Controller, 2467 &gEfiUsbHcProtocolGuid, 2468 (VOID **)&UsbHc, 2469 This->DriverBindingHandle, 2470 Controller, 2471 EFI_OPEN_PROTOCOL_GET_PROTOCOL 2472 ); 2473 if (EFI_ERROR (Status)) { 2474 return Status; 2475 } 2476 2477 OhciCleanDevUp(Controller, UsbHc); 2478 2479 gBS->CloseProtocol ( 2480 Controller, 2481 &gEfiPciIoProtocolGuid, 2482 This->DriverBindingHandle, 2483 Controller 2484 ); 2485 return EFI_SUCCESS; 2486} 2487 2488 2489