1/** @file 2 3Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 4 5This program and the accompanying materials 6are licensed and made available under the terms and conditions 7of the BSD License which accompanies this distribution. The 8full 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#include "UsbBotPeim.h" 17#include "BotPeim.h" 18 19// 20// Global function 21// 22EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { 23 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 24 &gPeiUsbIoPpiGuid, 25 NotifyOnUsbIoPpi 26}; 27 28EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi = { 29 BotGetNumberOfBlockDevices, 30 BotGetMediaInfo, 31 BotReadBlocks 32}; 33 34EFI_PEI_RECOVERY_BLOCK_IO2_PPI mRecoveryBlkIo2Ppi = { 35 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, 36 BotGetNumberOfBlockDevices2, 37 BotGetMediaInfo2, 38 BotReadBlocks2 39}; 40 41EFI_PEI_PPI_DESCRIPTOR mPpiList[2] = { 42 { 43 EFI_PEI_PPI_DESCRIPTOR_PPI, 44 &gEfiPeiVirtualBlockIoPpiGuid, 45 NULL 46 }, 47 { 48 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 49 &gEfiPeiVirtualBlockIo2PpiGuid, 50 NULL 51 } 52}; 53 54/** 55 Detect whether the removable media is present and whether it has changed. 56 57 @param[in] PeiServices General-purpose services that are available to every 58 PEIM. 59 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance. 60 61 @retval EFI_SUCCESS The media status is successfully checked. 62 @retval Other Failed to detect media. 63 64**/ 65EFI_STATUS 66PeiBotDetectMedia ( 67 IN EFI_PEI_SERVICES **PeiServices, 68 IN PEI_BOT_DEVICE *PeiBotDev 69 ); 70 71/** 72 Initializes the Usb Bot. 73 74 @param FileHandle Handle of the file being invoked. 75 @param PeiServices Describes the list of possible PEI Services. 76 77 @retval EFI_SUCCESS Usb bot driver is successfully initialized. 78 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. 79 80**/ 81EFI_STATUS 82EFIAPI 83PeimInitializeUsbBot ( 84 IN EFI_PEI_FILE_HANDLE FileHandle, 85 IN CONST EFI_PEI_SERVICES **PeiServices 86 ) 87{ 88 EFI_STATUS Status; 89 UINTN UsbIoPpiInstance; 90 EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; 91 PEI_USB_IO_PPI *UsbIoPpi; 92 93 // 94 // Shadow this PEIM to run from memory 95 // 96 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 97 return EFI_SUCCESS; 98 } 99 100 // 101 // locate all usb io PPIs 102 // 103 for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) { 104 105 Status = PeiServicesLocatePpi ( 106 &gPeiUsbIoPpiGuid, 107 UsbIoPpiInstance, 108 &TempPpiDescriptor, 109 (VOID **) &UsbIoPpi 110 ); 111 if (EFI_ERROR (Status)) { 112 break; 113 } 114 } 115 // 116 // Register a notify function 117 // 118 return PeiServicesNotifyPpi (&mNotifyList); 119} 120 121/** 122 UsbIo installation notification function. 123 124 This function finds out all the current USB IO PPIs in the system and add them 125 into private data. 126 127 @param PeiServices Indirect reference to the PEI Services Table. 128 @param NotifyDesc Address of the notification descriptor data structure. 129 @param InvokePpi Address of the PPI that was invoked. 130 131 @retval EFI_SUCCESS The function completes successfully. 132 133**/ 134EFI_STATUS 135EFIAPI 136NotifyOnUsbIoPpi ( 137 IN EFI_PEI_SERVICES **PeiServices, 138 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, 139 IN VOID *InvokePpi 140 ) 141{ 142 PEI_USB_IO_PPI *UsbIoPpi; 143 144 UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi; 145 146 InitUsbBot (PeiServices, UsbIoPpi); 147 148 return EFI_SUCCESS; 149} 150 151/** 152 Initialize the usb bot device. 153 154 @param[in] PeiServices General-purpose services that are available to every 155 PEIM. 156 @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance. 157 158 @retval EFI_SUCCESS The usb bot device is initialized successfully. 159 @retval Other Failed to initialize media. 160 161**/ 162EFI_STATUS 163InitUsbBot ( 164 IN EFI_PEI_SERVICES **PeiServices, 165 IN PEI_USB_IO_PPI *UsbIoPpi 166 ) 167{ 168 PEI_BOT_DEVICE *PeiBotDevice; 169 EFI_STATUS Status; 170 EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc; 171 UINTN MemPages; 172 EFI_PHYSICAL_ADDRESS AllocateAddress; 173 EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc; 174 UINT8 Index; 175 176 // 177 // Check its interface 178 // 179 Status = UsbIoPpi->UsbGetInterfaceDescriptor ( 180 PeiServices, 181 UsbIoPpi, 182 &InterfaceDesc 183 ); 184 if (EFI_ERROR (Status)) { 185 return Status; 186 } 187 // 188 // Check if it is the BOT device we support 189 // 190 if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) { 191 192 return EFI_NOT_FOUND; 193 } 194 195 MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1; 196 Status = PeiServicesAllocatePages ( 197 EfiBootServicesCode, 198 MemPages, 199 &AllocateAddress 200 ); 201 if (EFI_ERROR (Status)) { 202 return Status; 203 } 204 205 PeiBotDevice = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress); 206 207 PeiBotDevice->Signature = PEI_BOT_DEVICE_SIGNATURE; 208 PeiBotDevice->UsbIoPpi = UsbIoPpi; 209 PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress; 210 PeiBotDevice->BotInterface = InterfaceDesc; 211 212 // 213 // Default value 214 // 215 PeiBotDevice->Media.DeviceType = UsbMassStorage; 216 PeiBotDevice->Media.BlockSize = 0x200; 217 PeiBotDevice->Media2.InterfaceType = MSG_USB_DP; 218 PeiBotDevice->Media2.BlockSize = 0x200; 219 PeiBotDevice->Media2.RemovableMedia = FALSE; 220 PeiBotDevice->Media2.ReadOnly = FALSE; 221 222 // 223 // Check its Bulk-in/Bulk-out endpoint 224 // 225 for (Index = 0; Index < 2; Index++) { 226 Status = UsbIoPpi->UsbGetEndpointDescriptor ( 227 PeiServices, 228 UsbIoPpi, 229 Index, 230 &EndpointDesc 231 ); 232 233 if (EFI_ERROR (Status)) { 234 return Status; 235 } 236 237 if ((EndpointDesc->EndpointAddress & 0x80) != 0) { 238 PeiBotDevice->BulkInEndpoint = EndpointDesc; 239 } else { 240 PeiBotDevice->BulkOutEndpoint = EndpointDesc; 241 } 242 } 243 244 CopyMem ( 245 &(PeiBotDevice->BlkIoPpi), 246 &mRecoveryBlkIoPpi, 247 sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI) 248 ); 249 CopyMem ( 250 &(PeiBotDevice->BlkIo2Ppi), 251 &mRecoveryBlkIo2Ppi, 252 sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI) 253 ); 254 CopyMem ( 255 &(PeiBotDevice->BlkIoPpiList), 256 &mPpiList[0], 257 sizeof (EFI_PEI_PPI_DESCRIPTOR) 258 ); 259 CopyMem ( 260 &(PeiBotDevice->BlkIo2PpiList), 261 &mPpiList[1], 262 sizeof (EFI_PEI_PPI_DESCRIPTOR) 263 ); 264 PeiBotDevice->BlkIoPpiList.Ppi = &PeiBotDevice->BlkIoPpi; 265 PeiBotDevice->BlkIo2PpiList.Ppi = &PeiBotDevice->BlkIo2Ppi; 266 267 Status = PeiUsbInquiry (PeiServices, PeiBotDevice); 268 if (EFI_ERROR (Status)) { 269 return Status; 270 } 271 272 Status = PeiServicesAllocatePages ( 273 EfiBootServicesCode, 274 1, 275 &AllocateAddress 276 ); 277 if (EFI_ERROR (Status)) { 278 return Status; 279 } 280 281 PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress); 282 283 Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList); 284 285 if (EFI_ERROR (Status)) { 286 return Status; 287 } 288 289 return EFI_SUCCESS; 290} 291 292/** 293 Gets the count of block I/O devices that one specific block driver detects. 294 295 This function is used for getting the count of block I/O devices that one 296 specific block driver detects. To the PEI ATAPI driver, it returns the number 297 of all the detected ATAPI devices it detects during the enumeration process. 298 To the PEI legacy floppy driver, it returns the number of all the legacy 299 devices it finds during its enumeration process. If no device is detected, 300 then the function will return zero. 301 302 @param[in] PeiServices General-purpose services that are available 303 to every PEIM. 304 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 305 instance. 306 @param[out] NumberBlockDevices The number of block I/O devices discovered. 307 308 @retval EFI_SUCCESS Operation performed successfully. 309 310**/ 311EFI_STATUS 312EFIAPI 313BotGetNumberOfBlockDevices ( 314 IN EFI_PEI_SERVICES **PeiServices, 315 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 316 OUT UINTN *NumberBlockDevices 317 ) 318{ 319 // 320 // For Usb devices, this value should be always 1 321 // 322 *NumberBlockDevices = 1; 323 return EFI_SUCCESS; 324} 325 326/** 327 Gets a block device's media information. 328 329 This function will provide the caller with the specified block device's media 330 information. If the media changes, calling this function will update the media 331 information accordingly. 332 333 @param[in] PeiServices General-purpose services that are available to every 334 PEIM 335 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 336 @param[in] DeviceIndex Specifies the block device to which the function wants 337 to talk. Because the driver that implements Block I/O 338 PPIs will manage multiple block devices, the PPIs that 339 want to talk to a single device must specify the 340 device index that was assigned during the enumeration 341 process. This index is a number from one to 342 NumberBlockDevices. 343 @param[out] MediaInfo The media information of the specified block media. 344 The caller is responsible for the ownership of this 345 data structure. 346 347 @retval EFI_SUCCESS Media information about the specified block device 348 was obtained successfully. 349 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 350 error. 351 352**/ 353EFI_STATUS 354EFIAPI 355BotGetMediaInfo ( 356 IN EFI_PEI_SERVICES **PeiServices, 357 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 358 IN UINTN DeviceIndex, 359 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo 360 ) 361{ 362 PEI_BOT_DEVICE *PeiBotDev; 363 EFI_STATUS Status; 364 365 PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This); 366 367 // 368 // First test unit ready 369 // 370 PeiUsbTestUnitReady ( 371 PeiServices, 372 PeiBotDev 373 ); 374 375 Status = PeiBotDetectMedia ( 376 PeiServices, 377 PeiBotDev 378 ); 379 380 if (EFI_ERROR (Status)) { 381 return EFI_DEVICE_ERROR; 382 } 383 384 CopyMem ( 385 MediaInfo, 386 &(PeiBotDev->Media), 387 sizeof (EFI_PEI_BLOCK_IO_MEDIA) 388 ); 389 390 return EFI_SUCCESS; 391} 392 393/** 394 Reads the requested number of blocks from the specified block device. 395 396 The function reads the requested number of blocks from the device. All the 397 blocks are read, or an error is returned. If there is no media in the device, 398 the function returns EFI_NO_MEDIA. 399 400 @param[in] PeiServices General-purpose services that are available to 401 every PEIM. 402 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 403 @param[in] DeviceIndex Specifies the block device to which the function wants 404 to talk. Because the driver that implements Block I/O 405 PPIs will manage multiple block devices, the PPIs that 406 want to talk to a single device must specify the device 407 index that was assigned during the enumeration process. 408 This index is a number from one to NumberBlockDevices. 409 @param[in] StartLBA The starting logical block address (LBA) to read from 410 on the device 411 @param[in] BufferSize The size of the Buffer in bytes. This number must be 412 a multiple of the intrinsic block size of the device. 413 @param[out] Buffer A pointer to the destination buffer for the data. 414 The caller is responsible for the ownership of the 415 buffer. 416 417 @retval EFI_SUCCESS The data was read correctly from the device. 418 @retval EFI_DEVICE_ERROR The device reported an error while attempting 419 to perform the read operation. 420 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 421 valid, or the buffer is not properly aligned. 422 @retval EFI_NO_MEDIA There is no media in the device. 423 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 424 the intrinsic block size of the device. 425 426**/ 427EFI_STATUS 428EFIAPI 429BotReadBlocks ( 430 IN EFI_PEI_SERVICES **PeiServices, 431 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 432 IN UINTN DeviceIndex, 433 IN EFI_PEI_LBA StartLBA, 434 IN UINTN BufferSize, 435 OUT VOID *Buffer 436 ) 437{ 438 PEI_BOT_DEVICE *PeiBotDev; 439 EFI_STATUS Status; 440 UINTN BlockSize; 441 UINTN NumberOfBlocks; 442 443 Status = EFI_SUCCESS; 444 PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This); 445 446 // 447 // Check parameters 448 // 449 if (Buffer == NULL) { 450 return EFI_INVALID_PARAMETER; 451 } 452 453 if (BufferSize == 0) { 454 return EFI_SUCCESS; 455 } 456 457 if (!PeiBotDev->Media.MediaPresent) { 458 return EFI_NO_MEDIA; 459 } 460 461 BlockSize = PeiBotDev->Media.BlockSize; 462 463 if (BufferSize % BlockSize != 0) { 464 Status = EFI_BAD_BUFFER_SIZE; 465 } 466 467 if (StartLBA > PeiBotDev->Media2.LastBlock) { 468 Status = EFI_INVALID_PARAMETER; 469 } 470 471 NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize); 472 473 if (Status == EFI_SUCCESS) { 474 475 Status = PeiUsbTestUnitReady ( 476 PeiServices, 477 PeiBotDev 478 ); 479 if (Status == EFI_SUCCESS) { 480 Status = PeiUsbRead10 ( 481 PeiServices, 482 PeiBotDev, 483 Buffer, 484 StartLBA, 485 1 486 ); 487 } 488 } else { 489 // 490 // To generate sense data for DetectMedia use. 491 // 492 PeiUsbTestUnitReady ( 493 PeiServices, 494 PeiBotDev 495 ); 496 } 497 498 if (EFI_ERROR (Status)) { 499 // 500 // if any error encountered, detect what happened to the media and 501 // update the media info accordingly. 502 // 503 Status = PeiBotDetectMedia ( 504 PeiServices, 505 PeiBotDev 506 ); 507 if (Status != EFI_SUCCESS) { 508 return EFI_DEVICE_ERROR; 509 } 510 511 NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize; 512 513 if (!(PeiBotDev->Media.MediaPresent)) { 514 return EFI_NO_MEDIA; 515 } 516 517 if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) { 518 return EFI_BAD_BUFFER_SIZE; 519 } 520 521 if (StartLBA > PeiBotDev->Media2.LastBlock) { 522 return EFI_INVALID_PARAMETER; 523 } 524 525 if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media2.LastBlock) { 526 return EFI_INVALID_PARAMETER; 527 } 528 529 Status = PeiUsbRead10 ( 530 PeiServices, 531 PeiBotDev, 532 Buffer, 533 StartLBA, 534 NumberOfBlocks 535 ); 536 537 switch (Status) { 538 539 case EFI_SUCCESS: 540 return EFI_SUCCESS; 541 542 default: 543 return EFI_DEVICE_ERROR; 544 } 545 } else { 546 StartLBA += 1; 547 NumberOfBlocks -= 1; 548 Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize; 549 550 if (NumberOfBlocks == 0) { 551 return EFI_SUCCESS; 552 } 553 554 Status = PeiUsbRead10 ( 555 PeiServices, 556 PeiBotDev, 557 Buffer, 558 StartLBA, 559 NumberOfBlocks 560 ); 561 switch (Status) { 562 563 case EFI_SUCCESS: 564 return EFI_SUCCESS; 565 566 default: 567 return EFI_DEVICE_ERROR; 568 569 } 570 } 571} 572 573/** 574 Gets the count of block I/O devices that one specific block driver detects. 575 576 This function is used for getting the count of block I/O devices that one 577 specific block driver detects. To the PEI ATAPI driver, it returns the number 578 of all the detected ATAPI devices it detects during the enumeration process. 579 To the PEI legacy floppy driver, it returns the number of all the legacy 580 devices it finds during its enumeration process. If no device is detected, 581 then the function will return zero. 582 583 @param[in] PeiServices General-purpose services that are available 584 to every PEIM. 585 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI 586 instance. 587 @param[out] NumberBlockDevices The number of block I/O devices discovered. 588 589 @retval EFI_SUCCESS Operation performed successfully. 590 591**/ 592EFI_STATUS 593EFIAPI 594BotGetNumberOfBlockDevices2 ( 595 IN EFI_PEI_SERVICES **PeiServices, 596 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 597 OUT UINTN *NumberBlockDevices 598 ) 599{ 600 // 601 // For Usb devices, this value should be always 1 602 // 603 *NumberBlockDevices = 1; 604 return EFI_SUCCESS; 605} 606 607/** 608 Gets a block device's media information. 609 610 This function will provide the caller with the specified block device's media 611 information. If the media changes, calling this function will update the media 612 information accordingly. 613 614 @param[in] PeiServices General-purpose services that are available to every 615 PEIM 616 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 617 @param[in] DeviceIndex Specifies the block device to which the function wants 618 to talk. Because the driver that implements Block I/O 619 PPIs will manage multiple block devices, the PPIs that 620 want to talk to a single device must specify the 621 device index that was assigned during the enumeration 622 process. This index is a number from one to 623 NumberBlockDevices. 624 @param[out] MediaInfo The media information of the specified block media. 625 The caller is responsible for the ownership of this 626 data structure. 627 628 @retval EFI_SUCCESS Media information about the specified block device 629 was obtained successfully. 630 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 631 error. 632 633**/ 634EFI_STATUS 635EFIAPI 636BotGetMediaInfo2 ( 637 IN EFI_PEI_SERVICES **PeiServices, 638 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 639 IN UINTN DeviceIndex, 640 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo 641 ) 642{ 643 PEI_BOT_DEVICE *PeiBotDev; 644 EFI_STATUS Status; 645 646 PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This); 647 648 Status = BotGetMediaInfo ( 649 PeiServices, 650 &PeiBotDev->BlkIoPpi, 651 DeviceIndex, 652 &PeiBotDev->Media 653 ); 654 655 if (EFI_ERROR (Status)) { 656 return Status; 657 } 658 659 CopyMem ( 660 MediaInfo, 661 &(PeiBotDev->Media2), 662 sizeof (EFI_PEI_BLOCK_IO2_MEDIA) 663 ); 664 665 return EFI_SUCCESS; 666} 667 668/** 669 Reads the requested number of blocks from the specified block device. 670 671 The function reads the requested number of blocks from the device. All the 672 blocks are read, or an error is returned. If there is no media in the device, 673 the function returns EFI_NO_MEDIA. 674 675 @param[in] PeiServices General-purpose services that are available to 676 every PEIM. 677 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 678 @param[in] DeviceIndex Specifies the block device to which the function wants 679 to talk. Because the driver that implements Block I/O 680 PPIs will manage multiple block devices, the PPIs that 681 want to talk to a single device must specify the device 682 index that was assigned during the enumeration process. 683 This index is a number from one to NumberBlockDevices. 684 @param[in] StartLBA The starting logical block address (LBA) to read from 685 on the device 686 @param[in] BufferSize The size of the Buffer in bytes. This number must be 687 a multiple of the intrinsic block size of the device. 688 @param[out] Buffer A pointer to the destination buffer for the data. 689 The caller is responsible for the ownership of the 690 buffer. 691 692 @retval EFI_SUCCESS The data was read correctly from the device. 693 @retval EFI_DEVICE_ERROR The device reported an error while attempting 694 to perform the read operation. 695 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 696 valid, or the buffer is not properly aligned. 697 @retval EFI_NO_MEDIA There is no media in the device. 698 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 699 the intrinsic block size of the device. 700 701**/ 702EFI_STATUS 703EFIAPI 704BotReadBlocks2 ( 705 IN EFI_PEI_SERVICES **PeiServices, 706 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 707 IN UINTN DeviceIndex, 708 IN EFI_PEI_LBA StartLBA, 709 IN UINTN BufferSize, 710 OUT VOID *Buffer 711 ) 712{ 713 PEI_BOT_DEVICE *PeiBotDev; 714 EFI_STATUS Status; 715 716 if (This == NULL) { 717 return EFI_INVALID_PARAMETER; 718 } 719 720 Status = EFI_SUCCESS; 721 PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This); 722 723 Status = BotReadBlocks ( 724 PeiServices, 725 &PeiBotDev->BlkIoPpi, 726 DeviceIndex, 727 StartLBA, 728 BufferSize, 729 Buffer 730 ); 731 732 return Status; 733} 734 735/** 736 Detect whether the removable media is present and whether it has changed. 737 738 @param[in] PeiServices General-purpose services that are available to every 739 PEIM. 740 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance. 741 742 @retval EFI_SUCCESS The media status is successfully checked. 743 @retval Other Failed to detect media. 744 745**/ 746EFI_STATUS 747PeiBotDetectMedia ( 748 IN EFI_PEI_SERVICES **PeiServices, 749 IN PEI_BOT_DEVICE *PeiBotDev 750 ) 751{ 752 EFI_STATUS Status; 753 EFI_STATUS FloppyStatus; 754 UINTN SenseCounts; 755 BOOLEAN NeedReadCapacity; 756 EFI_PHYSICAL_ADDRESS AllocateAddress; 757 ATAPI_REQUEST_SENSE_DATA *SensePtr; 758 UINTN Retry; 759 760 // 761 // if there is no media present,or media not changed, 762 // the request sense command will detect faster than read capacity command. 763 // read capacity command can be bypassed, thus improve performance. 764 // 765 SenseCounts = 0; 766 NeedReadCapacity = TRUE; 767 768 Status = PeiServicesAllocatePages ( 769 EfiBootServicesCode, 770 1, 771 &AllocateAddress 772 ); 773 if (EFI_ERROR (Status)) { 774 return Status; 775 } 776 777 SensePtr = PeiBotDev->SensePtr; 778 ZeroMem (SensePtr, EFI_PAGE_SIZE); 779 780 Status = PeiUsbRequestSense ( 781 PeiServices, 782 PeiBotDev, 783 &SenseCounts, 784 (UINT8 *) SensePtr 785 ); 786 787 if (Status == EFI_SUCCESS) { 788 // 789 // No Media 790 // 791 if (IsNoMedia (SensePtr, SenseCounts)) { 792 NeedReadCapacity = FALSE; 793 PeiBotDev->Media.MediaPresent = FALSE; 794 PeiBotDev->Media.LastBlock = 0; 795 PeiBotDev->Media2.MediaPresent = FALSE; 796 PeiBotDev->Media2.LastBlock = 0; 797 } else { 798 // 799 // Media Changed 800 // 801 if (IsMediaChange (SensePtr, SenseCounts)) { 802 PeiBotDev->Media.MediaPresent = TRUE; 803 PeiBotDev->Media2.MediaPresent = TRUE; 804 } 805 // 806 // Media Error 807 // 808 if (IsMediaError (SensePtr, SenseCounts)) { 809 // 810 // if media error encountered, make it look like no media present. 811 // 812 PeiBotDev->Media.MediaPresent = FALSE; 813 PeiBotDev->Media.LastBlock = 0; 814 PeiBotDev->Media2.MediaPresent = FALSE; 815 PeiBotDev->Media2.LastBlock = 0; 816 } 817 818 } 819 820 } 821 822 if (NeedReadCapacity) { 823 // 824 // Retry at most 4 times to detect media info 825 // 826 for (Retry = 0; Retry < 4; Retry++) { 827 switch (PeiBotDev->DeviceType) { 828 case USBCDROM: 829 Status = PeiUsbReadCapacity ( 830 PeiServices, 831 PeiBotDev 832 ); 833 break; 834 835 case USBFLOPPY2: 836 Status = PeiUsbReadFormattedCapacity ( 837 PeiServices, 838 PeiBotDev 839 ); 840 if (EFI_ERROR(Status)|| 841 !PeiBotDev->Media.MediaPresent) { 842 // 843 // retry the ReadCapacity command 844 // 845 PeiBotDev->DeviceType = USBFLOPPY; 846 Status = EFI_DEVICE_ERROR; 847 } 848 break; 849 850 case USBFLOPPY: 851 Status = PeiUsbReadCapacity ( 852 PeiServices, 853 PeiBotDev 854 ); 855 if (EFI_ERROR (Status)) { 856 // 857 // retry the ReadFormatCapacity command 858 // 859 PeiBotDev->DeviceType = USBFLOPPY2; 860 } 861 break; 862 863 default: 864 return EFI_INVALID_PARAMETER; 865 } 866 867 SenseCounts = 0; 868 ZeroMem (SensePtr, EFI_PAGE_SIZE); 869 870 if (Status == EFI_SUCCESS) { 871 break; 872 } 873 874 FloppyStatus = PeiUsbRequestSense ( 875 PeiServices, 876 PeiBotDev, 877 &SenseCounts, 878 (UINT8 *) SensePtr 879 ); 880 881 // 882 // If Request Sense data failed,retry. 883 // 884 if (EFI_ERROR (FloppyStatus)) { 885 continue; 886 } 887 // 888 // No Media 889 // 890 if (IsNoMedia (SensePtr, SenseCounts)) { 891 PeiBotDev->Media.MediaPresent = FALSE; 892 PeiBotDev->Media.LastBlock = 0; 893 PeiBotDev->Media2.MediaPresent = FALSE; 894 PeiBotDev->Media2.LastBlock = 0; 895 break; 896 } 897 898 if (IsMediaError (SensePtr, SenseCounts)) { 899 // 900 // if media error encountered, make it look like no media present. 901 // 902 PeiBotDev->Media.MediaPresent = FALSE; 903 PeiBotDev->Media.LastBlock = 0; 904 PeiBotDev->Media2.MediaPresent = FALSE; 905 PeiBotDev->Media2.LastBlock = 0; 906 break; 907 } 908 } 909 // 910 // ENDFOR 911 // 912 // tell whether the readcapacity process is successful or not 913 // ("Status" variable record the latest status returned 914 // by ReadCapacity ) 915 // 916 if (Status != EFI_SUCCESS) { 917 return EFI_DEVICE_ERROR; 918 } 919 } 920 921 return EFI_SUCCESS; 922} 923