usbmassstoragehelper.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,603 行 · 第 1/3 页
C
1,603 行
IN USB_FLOPPY_DEV *UsbFloppyDevice,
OUT UINTN *SenseCounts
)
/*++
Routine Description:
Retrieves Sense Data from device via
sending Request Sense Packet Command.
Arguments:
UsbFloppyDevice - The USB_FLOPPY_DEV instance.
SenseCounts - A pointer to the number of Sense Data returned.
Returns:
EFI_DEVICE_ERROR - Hardware error
EFI_SUCCESS - Success
--*/
{
EFI_STATUS Status;
REQUEST_SENSE_DATA *Sense;
UINT8 *Ptr;
BOOLEAN SenseReq;
ATAPI_PACKET_COMMAND Packet;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
*SenseCounts = 0;
EfiZeroMem (
UsbFloppyDevice->SenseData,
sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber)
);
//
// fill command packet for Request Sense Packet Command
//
EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
Packet.RequestSense.opcode = REQUEST_SENSE;
Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA);
//
// initialize pointer
//
Ptr = (UINT8 *) (UsbFloppyDevice->SenseData);
//
// request sense data from device continuously
// until no sense data exists in the device.
//
for (SenseReq = TRUE; SenseReq;) {
Sense = (REQUEST_SENSE_DATA *) Ptr;
//
// send out Request Sense Packet Command and get one Sense
// data from device.
//
Status = USBFloppyPacketCommand (
UsbFloppyDevice,
&Packet,
sizeof (ATAPI_PACKET_COMMAND),
(VOID *) Ptr,
sizeof (REQUEST_SENSE_DATA),
EfiUsbDataIn,
USBFLPTIMEOUT
);
//
// failed to get Sense data
//
if (EFI_ERROR (Status)) {
//
// Recovery the device back to normal state.
//
UsbFloppyDevice->AtapiProtocol->UsbAtapiReset (
UsbFloppyDevice->AtapiProtocol,
TRUE
);
if (*SenseCounts == 0) {
//
// never retrieved any sense data from device,
// just return error.
//
return EFI_DEVICE_ERROR;
} else {
//
// has retrieved some sense data from device,
// so return success.
//
return EFI_SUCCESS;
}
}
if (Sense->sense_key != SK_NO_SENSE) {
//
// Ptr is byte based pointer
//
Ptr += sizeof (REQUEST_SENSE_DATA);
(*SenseCounts)++;
} else {
//
// when no sense key, skip out the loop
//
SenseReq = FALSE;
}
//
// If the sense key numbers exceed Sense Data Buffer size,
// just skip the loop and do not fetch the sense key in this function.
//
if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) {
SenseReq = FALSE;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
UsbFloppyTestUnitReady (
IN USB_FLOPPY_DEV *UsbFloppyDevice
)
/*++
Routine Description:
Sends Test Unit ReadyPacket Command to the device.
Arguments:
UsbFloppyDevice - The USB_FLOPPY_DEV instance.
Returns:
EFI_DEVICE_ERROR - Hardware error
EFI_SUCCESS - Success
--*/
{
ATAPI_PACKET_COMMAND Packet;
EFI_STATUS Status;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
UINT32 RetryIndex;
UINT32 MaximumRetryTimes;
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
MaximumRetryTimes = 2;
//
// fill command packet
//
EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
Packet.TestUnitReady.opcode = TEST_UNIT_READY;
//
// send command packet
//
Status = EFI_DEVICE_ERROR;
for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) {
Status = USBFloppyPacketCommand (
UsbFloppyDevice,
&Packet,
sizeof (ATAPI_PACKET_COMMAND),
NULL,
0,
EfiUsbNoData,
USBFLPTIMEOUT
);
if (EFI_ERROR (Status)) {
gBS->Stall (100 * STALL_1_MILLI_SECOND);
}
}
return Status;
}
EFI_STATUS
USBFloppyWrite10 (
IN USB_FLOPPY_DEV *UsbFloppyDevice,
IN VOID *Buffer,
IN EFI_LBA Lba,
IN UINTN NumberOfBlocks
)
/*++
Routine Description:
Sends Write10 Packet Command to device to perform data transfer
from host to device.
Arguments:
UsbFloppyDevice - The USB_FLOPPY_DEV instance.
Buffer - A pointer to the source buffer for the data.
The caller is responsible for either having implicit
or explicit ownership of the buffer.
Lba - The starting logical block address to written to
the device.
NumberOfBlocks - Indicates the number of blocks that the write
operation requests.
Returns:
EFI_DEVICE_ERROR - Hardware error
EFI_SUCCESS - Success
--*/
{
ATAPI_PACKET_COMMAND Packet;
READ10_CMD *Write10Packet;
UINT16 MaxBlock;
UINT16 BlocksRemaining;
UINT16 SectorCount;
UINT32 Lba32;
UINT32 BlockSize;
UINT32 ByteCount;
VOID *ptrBuffer;
EFI_STATUS Status;
UINT16 TimeOut;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
UINT8 Index;
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
//
// prepare command packet for the Write10 Packet Command.
//
EfiZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
Write10Packet = &Packet.Read10;
Lba32 = (UINT32) Lba;
ptrBuffer = Buffer;
BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize;
MaxBlock = (UINT16) (65536 / BlockSize);
BlocksRemaining = (UINT16) NumberOfBlocks;
Status = EFI_SUCCESS;
while (BlocksRemaining > 0) {
if (BlocksRemaining <= MaxBlock) {
SectorCount = BlocksRemaining;
} else {
SectorCount = MaxBlock;
}
for (Index = 0; Index < 3; Index ++) {
//
// fill the Packet data structure
//
Write10Packet->opcode = WRITE_10;
//
// Lba0 ~ Lba3 specify the start logical block address
// of the data transfer.
// Lba0 is MSB, Lba3 is LSB
//
Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
Write10Packet->Lba2 = (UINT8) (Lba32 >> 8);
Write10Packet->Lba1 = (UINT8) (Lba32 >> 16);
Write10Packet->Lba0 = (UINT8) (Lba32 >> 24);
//
// TranLen0 ~ TranLen1 specify the transfer length in block unit.
// TranLen0 is MSB, TranLen is LSB
//
Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
ByteCount = SectorCount * BlockSize;
TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT);
Status = USBFloppyPacketCommand (
UsbFloppyDevice,
&Packet,
sizeof (ATAPI_PACKET_COMMAND),
(VOID *) ptrBuffer,
ByteCount,
EfiUsbDataOut,
TimeOut
);
if (!EFI_ERROR (Status)) {
break;
}
}
if (Index == 3) {
return EFI_DEVICE_ERROR;
}
Lba32 += SectorCount;
ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize;
BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
}
return Status;
}
EFI_STATUS
UsbFloppyDetectMedia (
IN USB_FLOPPY_DEV *UsbFloppyDevice,
OUT BOOLEAN *MediaChange
)
/*++
Routine Description:
Retrieves media information.
Arguments:
UsbFloppyDevice - The USB_FLOPPY_DEV instance.
MediaChange - Indicates whether media was changed.
Returns:
EFI_DEVICE_ERROR - Hardware error
EFI_SUCCESS - Success
EFI_INVALID_PARAMETER - Parameter is error
--*/
{
EFI_STATUS Status;
EFI_STATUS FloppyStatus;
//
// the following variables are used to record previous media information
//
EFI_BLOCK_IO_MEDIA OldMediaInfo;
UINTN SenseCounts;
UINTN RetryIndex;
UINTN RetryTimes;
UINTN MaximumRetryTimes;
BOOLEAN NeedRetry;
//
// a flag used to determine whether need to perform Read Capacity command.
//
REQUEST_SENSE_DATA *SensePtr;
//
// init
//
Status = EFI_SUCCESS;
FloppyStatus = EFI_SUCCESS;
OldMediaInfo = *UsbFloppyDevice->BlkIo.Media;
*MediaChange = FALSE;
//
// if there is no media present,or media not changed,
// the request sense command will detect faster than read capacity command.
// read capacity command can be bypassed, thus improve performance.
//
SenseCounts = 0;
Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
if (!EFI_ERROR (Status)) {
SensePtr = UsbFloppyDevice->SenseData;
//
// No Media
//
if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {
UsbFloppyDevice->NeedReadCapacity = FALSE;
UsbFloppyDevice->BlkIo.Media->MediaId = 0;
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
} else {
//
// Media Changed
//
if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) {
UsbFloppyDevice->BlkIo.Media->MediaId++;
}
//
// Media Write-protected
//
if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
}
//
// Media Error
//
if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
//
// if media error encountered, make it look like no media present.
//
UsbFloppyDevice->BlkIo.Media->MediaId = 0;
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
}
}
}
if (UsbFloppyDevice->NeedReadCapacity) {
//
// at most retry 5 times
//
MaximumRetryTimes = 5;
//
// initial retry twice
//
RetryTimes = 2;
for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) {
//
// Using different command to retrieve media capacity.
//
switch (UsbFloppyDevice->DeviceType) {
case USBCDROM:
Status = USBFloppyReadCapacity (UsbFloppyDevice);
break;
case USBFLOPPY2:
UsbMassStorageModeSense (UsbFloppyDevice);
Status = USBFloppyReadFormatCapacity (UsbFloppyDevice);
if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) {
//
// retry the ReadCapacity command
//
UsbFloppyDevice->DeviceType = USBFLOPPY;
Status = EFI_DEVICE_ERROR;
} else {
UsbFloppyDevice->NeedReadCapacity = FALSE;
}
break;
case USBFLOPPY:
UsbMassStorageModeSense (UsbFloppyDevice);
Status = USBFloppyReadCapacity (UsbFloppyDevice);
if (EFI_ERROR (Status)) {
//
// retry the ReadFormatCapacity command
//
UsbFloppyDevice->DeviceType = USBFLOPPY2;
} else {
UsbFloppyDevice->NeedReadCapacity = FALSE;
}
//
// force the BlockSize to be 0x200.
//
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200;
break;
default:
return EFI_INVALID_PARAMETER;
}
if (!EFI_ERROR (Status)) {
//
// skip the loop when read capacity succeeds.
//
break;
}
SenseCounts = 0;
FloppyStatus = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts);
//
// If Request Sense data failed,retry.
//
if (EFI_ERROR (FloppyStatus)) {
//
// retry once more
//
RetryTimes++;
continue;
}
//
// No Media
//
if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) {
UsbFloppyDevice->BlkIo.Media->MediaId = 0;
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
break;
}
if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) {
//
// if media error encountered, make it look like no media present.
//
UsbFloppyDevice->BlkIo.Media->MediaId = 0;
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
break;
}
if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) {
UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE;
continue;
}
if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) {
//
// Drive not ready: if NeedRetry, then retry once more;
// else return error
//
if (NeedRetry) {
//
// Stall 0.1 second to wait for drive becoming ready
//
gBS->Stall (100 * STALL_1_MILLI_SECOND);
//
// reset retry variable to zero,
// to make it retry for "drive in progress of becoming ready".
//
RetryIndex = 0;
continue;
} else {
return EFI_DEVICE_ERROR;
}
}
//
// if read capacity fail not for above reasons, retry once more
//
RetryTimes++;
}
//
// ENDFOR
//
//
// tell whether the readcapacity process is successful or not
// ("Status" variable record the latest status returned
// by ReadCapacity AND "FloppyStatus" record the latest status
// returned by RequestSense)
//
if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) {
return EFI_DEVICE_ERROR;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?