📄 usbmassstoragehelper.c
字号:
--*/
{
//
// status returned by Read Capacity Packet Command
//
EFI_STATUS Status;
ATAPI_PACKET_COMMAND Packet;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
//
// used for capacity data returned from Usb Floppy
//
READ_FORMAT_CAPACITY_DATA FormatData ;
EfiZeroMem(&FormatData,sizeof(FormatData));
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
EfiZeroMem(&Packet,sizeof(ATAPI_PACKET_COMMAND));
Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY ;
Packet.ReadFormatCapacity.allocation_length_lo = 12 ;
Status = USBFloppyPacketCommand (UsbFloppyDevice,
&Packet,
sizeof(ATAPI_PACKET_COMMAND),
(VOID *)&FormatData,
sizeof(READ_FORMAT_CAPACITY_DATA),
EfiUsbDataIn,
USBFLPTIMEOUT
) ;
if(EFI_ERROR(Status)) {
return EFI_DEVICE_ERROR;
}
if(FormatData.DesCode == 3) {
//
// Media is not present
//
UsbFloppyDevice->BlkIo.Media->MediaId = 0 ;
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE;
UsbFloppyDevice->BlkIo.Media->LastBlock = 0;
} else {
UsbFloppyDevice->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |
(FormatData.LastLba2 << 16) |
(FormatData.LastLba1 << 8) |
FormatData.LastLba0;
UsbFloppyDevice->BlkIo.Media->LastBlock--;
UsbFloppyDevice->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
(FormatData.BlockSize1 << 8) |
FormatData.BlockSize0;
UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE;
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200 ;
}
return EFI_SUCCESS ;
}
EFI_STATUS
UsbFloppyRequestSense (
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_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);
Ptr = (UINT8*)(UsbFloppyDevice->SenseData) ; // initialize pointer
//
// request sense data from device continuously
// until no sense data exists in the device.
//
for (SenseReq = TRUE; SenseReq == TRUE; ) {
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,FALSE);
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 += sizeof(REQUEST_SENSE_DATA) ; // Ptr is byte based pointer
(*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:
--*/
{
ATAPI_PACKET_COMMAND Packet;
EFI_STATUS Status;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
//
// fill command packet
//
EfiZeroMem(&Packet, sizeof(ATAPI_PACKET_COMMAND));
Packet.TestUnitReady.opcode = TEST_UNIT_READY;
//
// send command packet
//
Status = USBFloppyPacketCommand (UsbFloppyDevice,
&Packet,
sizeof(ATAPI_PACKET_COMMAND),
NULL,
0,
EfiUsbNoData,
USBFLPTIMEOUT
);
if(EFI_ERROR(Status)) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
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:
--*/
{
ATAPI_PACKET_COMMAND Packet;
READ10_CMD *Write10Packet;
UINT16 MaxBlock ;
UINT16 BlocksRemaining;
UINT16 SectorCount;
UINT32 Lba32;
UINT32 BlockSize, ByteCount;
VOID *ptrBuffer;
EFI_STATUS Status;
UINT16 TimeOut;
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
UINTN SenseCounts;
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 ;
}
//
// 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)) {
Status = UsbFloppyRequestSense (UsbFloppyDevice,&SenseCounts);
if (!EFI_ERROR(Status)) {
if (IsLogicalUnitCommunicationOverRun (
UsbFloppyDevice->SenseData,
SenseCounts)) {
Lba32 = (UINT32)Lba;
ptrBuffer = Buffer;
BlocksRemaining = (UINT16)NumberOfBlocks;
MaxBlock = (UINT16)(MaxBlock / 4);
if (MaxBlock < 1) {
MaxBlock = 1;
}
continue;
}
}
//
// retry write10 command
//
Status = USBFloppyPacketCommand(
UsbFloppyDevice,
&Packet,
sizeof(ATAPI_PACKET_COMMAND),
(void *)ptrBuffer,
ByteCount,
EfiUsbDataOut,
TimeOut
);
if (EFI_ERROR(Status)) {
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_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.
//
BOOLEAN NeedReadCapacity;
REQUEST_SENSE_DATA *SensePtr;
//
// init
//
Status = EFI_SUCCESS;
FloppyStatus = EFI_SUCCESS;
OldMediaInfo = *UsbFloppyDevice->BlkIo.Media;
*MediaChange = FALSE ;
NeedReadCapacity = TRUE;
//
// 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)) {
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 (NeedReadCapacity) {
//
// at most retry 5 times
//
MaximumRetryTimes = 5;
RetryTimes = 2 ; // initial retry twice
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 USBFLOPPY:
UsbFloppyModeSense1C (UsbFloppyDevice);
Status = USBFloppyReadFormatCapacity(UsbFloppyDevice);
if (EFI_ERROR(Status)) {
//
// retry the ReadCapacity command
//
UsbFloppyDevice->DeviceType = USBFLOPPY2;
}
break;
case USBFLOPPY2:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -