3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution. The
8 full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UsbBotPeim.h"
22 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList
= {
23 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
28 EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi
= {
29 BotGetNumberOfBlockDevices
,
34 EFI_PEI_RECOVERY_BLOCK_IO2_PPI mRecoveryBlkIo2Ppi
= {
35 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
36 BotGetNumberOfBlockDevices2
,
41 EFI_PEI_PPI_DESCRIPTOR mPpiList
[2] = {
43 EFI_PEI_PPI_DESCRIPTOR_PPI
,
44 &gEfiPeiVirtualBlockIoPpiGuid
,
48 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
49 &gEfiPeiVirtualBlockIo2PpiGuid
,
55 Detect whether the removable media is present and whether it has changed.
57 @param[in] PeiServices General-purpose services that are available to every
59 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
61 @retval EFI_SUCCESS The media status is successfully checked.
62 @retval Other Failed to detect media.
67 IN EFI_PEI_SERVICES
**PeiServices
,
68 IN PEI_BOT_DEVICE
*PeiBotDev
72 Initializes the Usb Bot.
74 @param FileHandle Handle of the file being invoked.
75 @param PeiServices Describes the list of possible PEI Services.
77 @retval EFI_SUCCESS Usb bot driver is successfully initialized.
78 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.
83 PeimInitializeUsbBot (
84 IN EFI_PEI_FILE_HANDLE FileHandle
,
85 IN CONST EFI_PEI_SERVICES
**PeiServices
89 UINTN UsbIoPpiInstance
;
90 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
91 PEI_USB_IO_PPI
*UsbIoPpi
;
94 // Shadow this PEIM to run from memory
96 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
101 // locate all usb io PPIs
103 for (UsbIoPpiInstance
= 0; UsbIoPpiInstance
< PEI_FAT_MAX_USB_IO_PPI
; UsbIoPpiInstance
++) {
105 Status
= PeiServicesLocatePpi (
111 if (EFI_ERROR (Status
)) {
116 // Register a notify function
118 return PeiServicesNotifyPpi (&mNotifyList
);
122 UsbIo installation notification function.
124 This function finds out all the current USB IO PPIs in the system and add them
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.
131 @retval EFI_SUCCESS The function completes successfully.
137 IN EFI_PEI_SERVICES
**PeiServices
,
138 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
142 PEI_USB_IO_PPI
*UsbIoPpi
;
144 UsbIoPpi
= (PEI_USB_IO_PPI
*) InvokePpi
;
146 InitUsbBot (PeiServices
, UsbIoPpi
);
152 Initialize the usb bot device.
154 @param[in] PeiServices General-purpose services that are available to every
156 @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
158 @retval EFI_SUCCESS The usb bot device is initialized successfully.
159 @retval Other Failed to initialize media.
164 IN EFI_PEI_SERVICES
**PeiServices
,
165 IN PEI_USB_IO_PPI
*UsbIoPpi
168 PEI_BOT_DEVICE
*PeiBotDevice
;
170 EFI_USB_INTERFACE_DESCRIPTOR
*InterfaceDesc
;
172 EFI_PHYSICAL_ADDRESS AllocateAddress
;
173 EFI_USB_ENDPOINT_DESCRIPTOR
*EndpointDesc
;
177 // Check its interface
179 Status
= UsbIoPpi
->UsbGetInterfaceDescriptor (
184 if (EFI_ERROR (Status
)) {
188 // Check if it is the BOT device we support
190 if ((InterfaceDesc
->InterfaceClass
!= 0x08) || (InterfaceDesc
->InterfaceProtocol
!= 0x50)) {
192 return EFI_NOT_FOUND
;
195 MemPages
= sizeof (PEI_BOT_DEVICE
) / EFI_PAGE_SIZE
+ 1;
196 Status
= PeiServicesAllocatePages (
201 if (EFI_ERROR (Status
)) {
205 PeiBotDevice
= (PEI_BOT_DEVICE
*) ((UINTN
) AllocateAddress
);
207 PeiBotDevice
->Signature
= PEI_BOT_DEVICE_SIGNATURE
;
208 PeiBotDevice
->UsbIoPpi
= UsbIoPpi
;
209 PeiBotDevice
->AllocateAddress
= (UINTN
) AllocateAddress
;
210 PeiBotDevice
->BotInterface
= InterfaceDesc
;
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
;
223 // Check its Bulk-in/Bulk-out endpoint
225 for (Index
= 0; Index
< 2; Index
++) {
226 Status
= UsbIoPpi
->UsbGetEndpointDescriptor (
233 if (EFI_ERROR (Status
)) {
237 if ((EndpointDesc
->EndpointAddress
& 0x80) != 0) {
238 PeiBotDevice
->BulkInEndpoint
= EndpointDesc
;
240 PeiBotDevice
->BulkOutEndpoint
= EndpointDesc
;
245 &(PeiBotDevice
->BlkIoPpi
),
247 sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI
)
250 &(PeiBotDevice
->BlkIo2Ppi
),
252 sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI
)
255 &(PeiBotDevice
->BlkIoPpiList
),
257 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
260 &(PeiBotDevice
->BlkIo2PpiList
),
262 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
264 PeiBotDevice
->BlkIoPpiList
.Ppi
= &PeiBotDevice
->BlkIoPpi
;
265 PeiBotDevice
->BlkIo2PpiList
.Ppi
= &PeiBotDevice
->BlkIo2Ppi
;
267 Status
= PeiUsbInquiry (PeiServices
, PeiBotDevice
);
268 if (EFI_ERROR (Status
)) {
272 Status
= PeiServicesAllocatePages (
277 if (EFI_ERROR (Status
)) {
281 PeiBotDevice
->SensePtr
= (ATAPI_REQUEST_SENSE_DATA
*) ((UINTN
) AllocateAddress
);
283 Status
= PeiServicesInstallPpi (&PeiBotDevice
->BlkIoPpiList
);
285 if (EFI_ERROR (Status
)) {
293 Gets the count of block I/O devices that one specific block driver detects.
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.
302 @param[in] PeiServices General-purpose services that are available
304 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
306 @param[out] NumberBlockDevices The number of block I/O devices discovered.
308 @retval EFI_SUCCESS Operation performed successfully.
313 BotGetNumberOfBlockDevices (
314 IN EFI_PEI_SERVICES
**PeiServices
,
315 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
316 OUT UINTN
*NumberBlockDevices
320 // For Usb devices, this value should be always 1
322 *NumberBlockDevices
= 1;
327 Gets a block device's media information.
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.
333 @param[in] PeiServices General-purpose services that are available to every
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
343 @param[out] MediaInfo The media information of the specified block media.
344 The caller is responsible for the ownership of this
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
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
362 PEI_BOT_DEVICE
*PeiBotDev
;
365 PeiBotDev
= PEI_BOT_DEVICE_FROM_THIS (This
);
368 // First test unit ready
370 PeiUsbTestUnitReady (
375 Status
= PeiBotDetectMedia (
380 if (EFI_ERROR (Status
)) {
381 return EFI_DEVICE_ERROR
;
387 sizeof (EFI_PEI_BLOCK_IO_MEDIA
)
394 Reads the requested number of blocks from the specified block device.
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.
400 @param[in] PeiServices General-purpose services that are available to
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
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
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.
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
,
438 PEI_BOT_DEVICE
*PeiBotDev
;
441 UINTN NumberOfBlocks
;
443 Status
= EFI_SUCCESS
;
444 PeiBotDev
= PEI_BOT_DEVICE_FROM_THIS (This
);
449 if (Buffer
== NULL
) {
450 return EFI_INVALID_PARAMETER
;
453 if (BufferSize
== 0) {
457 if (!PeiBotDev
->Media
.MediaPresent
) {
461 BlockSize
= PeiBotDev
->Media
.BlockSize
;
463 if (BufferSize
% BlockSize
!= 0) {
464 Status
= EFI_BAD_BUFFER_SIZE
;
467 if (StartLBA
> PeiBotDev
->Media2
.LastBlock
) {
468 Status
= EFI_INVALID_PARAMETER
;
471 NumberOfBlocks
= BufferSize
/ (PeiBotDev
->Media
.BlockSize
);
473 if (Status
== EFI_SUCCESS
) {
475 Status
= PeiUsbTestUnitReady (
479 if (Status
== EFI_SUCCESS
) {
480 Status
= PeiUsbRead10 (
490 // To generate sense data for DetectMedia use.
492 PeiUsbTestUnitReady (
498 if (EFI_ERROR (Status
)) {
500 // if any error encountered, detect what happened to the media and
501 // update the media info accordingly.
503 Status
= PeiBotDetectMedia (
507 if (Status
!= EFI_SUCCESS
) {
508 return EFI_DEVICE_ERROR
;
511 NumberOfBlocks
= BufferSize
/ PeiBotDev
->Media
.BlockSize
;
513 if (!(PeiBotDev
->Media
.MediaPresent
)) {
517 if (BufferSize
% (PeiBotDev
->Media
.BlockSize
) != 0) {
518 return EFI_BAD_BUFFER_SIZE
;
521 if (StartLBA
> PeiBotDev
->Media2
.LastBlock
) {
522 return EFI_INVALID_PARAMETER
;
525 if ((StartLBA
+ NumberOfBlocks
- 1) > PeiBotDev
->Media2
.LastBlock
) {
526 return EFI_INVALID_PARAMETER
;
529 Status
= PeiUsbRead10 (
543 return EFI_DEVICE_ERROR
;
548 Buffer
= (UINT8
*) Buffer
+ PeiBotDev
->Media
.BlockSize
;
550 if (NumberOfBlocks
== 0) {
554 Status
= PeiUsbRead10 (
567 return EFI_DEVICE_ERROR
;
574 Gets the count of block I/O devices that one specific block driver detects.
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.
583 @param[in] PeiServices General-purpose services that are available
585 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
587 @param[out] NumberBlockDevices The number of block I/O devices discovered.
589 @retval EFI_SUCCESS Operation performed successfully.
594 BotGetNumberOfBlockDevices2 (
595 IN EFI_PEI_SERVICES
**PeiServices
,
596 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
597 OUT UINTN
*NumberBlockDevices
601 // For Usb devices, this value should be always 1
603 *NumberBlockDevices
= 1;
608 Gets a block device's media information.
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.
614 @param[in] PeiServices General-purpose services that are available to every
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
624 @param[out] MediaInfo The media information of the specified block media.
625 The caller is responsible for the ownership of this
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
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
643 PEI_BOT_DEVICE
*PeiBotDev
;
646 PeiBotDev
= PEI_BOT_DEVICE2_FROM_THIS (This
);
648 Status
= BotGetMediaInfo (
650 &PeiBotDev
->BlkIoPpi
,
655 if (EFI_ERROR (Status
)) {
661 &(PeiBotDev
->Media2
),
662 sizeof (EFI_PEI_BLOCK_IO2_MEDIA
)
669 Reads the requested number of blocks from the specified block device.
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.
675 @param[in] PeiServices General-purpose services that are available to
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
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
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.
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
,
713 PEI_BOT_DEVICE
*PeiBotDev
;
717 return EFI_INVALID_PARAMETER
;
720 Status
= EFI_SUCCESS
;
721 PeiBotDev
= PEI_BOT_DEVICE2_FROM_THIS (This
);
723 Status
= BotReadBlocks (
725 &PeiBotDev
->BlkIoPpi
,
736 Detect whether the removable media is present and whether it has changed.
738 @param[in] PeiServices General-purpose services that are available to every
740 @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.
742 @retval EFI_SUCCESS The media status is successfully checked.
743 @retval Other Failed to detect media.
748 IN EFI_PEI_SERVICES
**PeiServices
,
749 IN PEI_BOT_DEVICE
*PeiBotDev
753 EFI_STATUS FloppyStatus
;
755 BOOLEAN NeedReadCapacity
;
756 EFI_PHYSICAL_ADDRESS AllocateAddress
;
757 ATAPI_REQUEST_SENSE_DATA
*SensePtr
;
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.
766 NeedReadCapacity
= TRUE
;
768 Status
= PeiServicesAllocatePages (
773 if (EFI_ERROR (Status
)) {
777 SensePtr
= PeiBotDev
->SensePtr
;
778 ZeroMem (SensePtr
, EFI_PAGE_SIZE
);
780 Status
= PeiUsbRequestSense (
787 if (Status
== EFI_SUCCESS
) {
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;
801 if (IsMediaChange (SensePtr
, SenseCounts
)) {
802 PeiBotDev
->Media
.MediaPresent
= TRUE
;
803 PeiBotDev
->Media2
.MediaPresent
= TRUE
;
808 if (IsMediaError (SensePtr
, SenseCounts
)) {
810 // if media error encountered, make it look like no media present.
812 PeiBotDev
->Media
.MediaPresent
= FALSE
;
813 PeiBotDev
->Media
.LastBlock
= 0;
814 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
815 PeiBotDev
->Media2
.LastBlock
= 0;
822 if (NeedReadCapacity
) {
824 // Retry at most 4 times to detect media info
826 for (Retry
= 0; Retry
< 4; Retry
++) {
827 switch (PeiBotDev
->DeviceType
) {
829 Status
= PeiUsbReadCapacity (
836 Status
= PeiUsbReadFormattedCapacity (
840 if (EFI_ERROR(Status
)||
841 !PeiBotDev
->Media
.MediaPresent
) {
843 // retry the ReadCapacity command
845 PeiBotDev
->DeviceType
= USBFLOPPY
;
846 Status
= EFI_DEVICE_ERROR
;
851 Status
= PeiUsbReadCapacity (
855 if (EFI_ERROR (Status
)) {
857 // retry the ReadFormatCapacity command
859 PeiBotDev
->DeviceType
= USBFLOPPY2
;
864 return EFI_INVALID_PARAMETER
;
868 ZeroMem (SensePtr
, EFI_PAGE_SIZE
);
870 if (Status
== EFI_SUCCESS
) {
874 FloppyStatus
= PeiUsbRequestSense (
882 // If Request Sense data failed,retry.
884 if (EFI_ERROR (FloppyStatus
)) {
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;
898 if (IsMediaError (SensePtr
, SenseCounts
)) {
900 // if media error encountered, make it look like no media present.
902 PeiBotDev
->Media
.MediaPresent
= FALSE
;
903 PeiBotDev
->Media
.LastBlock
= 0;
904 PeiBotDev
->Media2
.MediaPresent
= FALSE
;
905 PeiBotDev
->Media2
.LastBlock
= 0;
912 // tell whether the readcapacity process is successful or not
913 // ("Status" variable record the latest status returned
916 if (Status
!= EFI_SUCCESS
) {
917 return EFI_DEVICE_ERROR
;