📄 stor.c
字号:
/****************************************************************
* MT View Silicon Tech. Inc.
*
* Copyright 2007, MT View Silicon Tech. Inc., ShangHai, China
* All rights reserved.
*
*
* Filename: stor.c
*
* Programmer: Grey
*
* Created: 01/xx/2008
*
* Description: usb mass storage device driver
*
*
*****************************************************************/
#include "stor.h"
#include <string.h>
STORAGE XDATA gStor[TOTAL_STOR_NUM];
BYTE XDATA gStorMap = 0;
LOGICAL_UNIT XDATA gLu[TOTAL_LOGICAL_UNIT_NUM];
WORD XDATA gLuMap = 0;
/*------------------Allocate storage source------------------*/
extern STORAGE*
AllocStorage(VOID)
{
BYTE DATA i;
STORAGE* DATA stor;
i = SearchMapZero(&gStorMap, TOTAL_STOR_NUM);
if (i == TOTAL_STOR_NUM)
return NULL;
SetMap(&gStorMap, i);
stor = &gStor[i];
memset(stor, 0, sizeof(STORAGE));
stor->Set = i;
return stor;
}
extern VOID
FreeStorage(
STORAGE *stor
)
{
BYTE DATA i;
for (i = 0; i < MAX_STOR_LOGICAL_UNIT_NUM; ++i)
{
if (stor->Lu[i] != NULL)
FreeLogicalUnit(stor->Lu[i]);
}
ClearMap(&gStorMap, stor->Set);
}
extern LOGICAL_UNIT*
AllocLogicalUnit(VOID)
{
BYTE DATA i;
LOGICAL_UNIT* DATA lu;
i = SearchMapZero(&gLuMap, TOTAL_LOGICAL_UNIT_NUM);
if (i == TOTAL_LOGICAL_UNIT_NUM)
return NULL;
SetMap(&gLuMap, i);
lu = &gLu[i];
memset(lu, 0, sizeof(LOGICAL_UNIT));
lu->Set = i;
return lu;
}
extern VOID
FreeLogicalUnit(
LOGICAL_UNIT *lu
)
{
ClearMap(&gLuMap, lu->Set);
}
/*-----------------------------------------------------------*/
/*--------------------storage control pipe-------------------*/
extern BYTE
StorGetMaxLUN(
STORAGE *stor
)
{
/* send get max lun request */
return UsbControlMsg(stor->Device,
stor->Device->PipeCtrlIn,
US_BULK_GET_MAX_LUN,
(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
0,
stor->InterfaceNum,
1,
&stor->MaxLogicalUnitNum
);
}
extern BYTE
StorResetRecovery(
STORAGE *stor
)
{
/* send get max lun request */
return UsbControlMsg(stor->Device,
stor->Device->PipeCtrlOut,
US_BULK_RESET_REQUEST,
(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
0,
stor->InterfaceNum,
0,
NULL
);
}
extern BYTE
StorClearHalt(
STORAGE *stor,
DWORD pipe
)
{
return UsbClearHalt(stor->Device, pipe);
}
extern VOID
StorFillScsiCmd(
BYTE *buf,
SCSI_CMD *scsiCmd
)
{
memset(buf, 0, 16);
switch(scsiCmd->Cmd)
{
case INQUIRY:
buf[0] = INQUIRY;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
buf[4] = 36; /* set transfer length */
break;
case TEST_UNIT_READY:
buf[0] = TEST_UNIT_READY;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
buf[4] = 0; /* set transfer length */
break;
case REQUEST_SENSE:
buf[0] = REQUEST_SENSE;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
buf[4] = 18; /* set transfer length */
break;
case READ_CAPACITY:
buf[0] = READ_CAPACITY;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
buf[4] = 8; /* set transfer length */
break;
case MODE_SENSE:
buf[0] = MODE_SENSE;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
case READ_10:
buf[0] = READ_10;
buf[1] = scsiCmd->Lun; /* set scsi command lun */
buf[1] <<= 5;
buf[2] = (scsiCmd->Lba >> 24); /* set LBA */
buf[3] = (scsiCmd->Lba >> 16);
buf[4] = (scsiCmd->Lba >> 8);
buf[5] = scsiCmd->Lba;
buf[7] = ((scsiCmd->BufLen / scsiCmd->BlockSize) >> 8); /* set transfer length */
buf[8] = scsiCmd->BufLen / scsiCmd->BlockSize;
default:
break;
}/* end switch */
}
extern BYTE
StorBulkTransport(
STORAGE *stor,
SCSI_CMD *scsiCmd
)
{
CBW cbw;
WORD actLength;
DWORD pipe;
BYTE scsi[16];
CSW csw;
BYTE err;
BYTE transportStatus = 0;
BYTE to;
/* fill scsi command buffer */
StorFillScsiCmd(scsi, scsiCmd);
/* config CBW */
memset(&cbw, 0, sizeof(CBW));
cbw.Signature = LE32ToCPU(US_BULK_CB_SIGN);
cbw.Tag = GetSysTime();
cbw.DataTransferLength = LE32ToCPU(scsiCmd->BufLen);
cbw.Flags = (scsiCmd->DataDirection << 7);
cbw.Lun = scsiCmd->Lun;
cbw.Length = scsiCmd->CmdLen;
memcpy(cbw.CDB, scsi, sizeof(cbw.CDB));
/* bulk transfer status stream control */
to = 10;
while(to)
{
if (transportStatus == 0)
{
/* send CBW */
err = UsbBulkMsg(stor->Device,
stor->PipeBulkOut,
&cbw,
sizeof(CBW),
FALSE,
&actLength
);
if (err == STALL)
{
/* mass storage spec 5.3.1 and 5.3.4 */
if (StorResetRecovery(stor) != NO_ERROR)
return STOR_TRANSPORT_ERR;
if (StorClearHalt(stor, stor->PipeBulkIn) != NO_ERROR)
return STOR_TRANSPORT_ERR;
if (StorClearHalt(stor, stor->PipeBulkOut) != NO_ERROR)
return STOR_TRANSPORT_ERR;
/* recovery storage successful and resend the cbw */
}
else if (err == DEVICE_NOT_RESPONDING)
{
return STOR_TRANSPORT_ERR;
}
else if (err == ERR)
{
return STOR_TRANSPORT_ERR;
}
else if (err == NO_ERROR)
{
transportStatus = (cbw.DataTransferLength != 0) ? 1 : 2;
}
else
{
return UNKNOW;
}
}
else if (transportStatus == 1)
{
/* send or receive data */
pipe = (scsiCmd->DataDirection == US_BULK_FLAG_IN) ? stor->PipeBulkIn : stor->PipeBulkOut;
err = UsbBulkMsg(stor->Device,
pipe,
scsiCmd->Buf,
scsiCmd->BufLen,
(scsiCmd->Cmd == READ_10 || scsiCmd->Cmd == WRITE_10),
&actLength
);
if (err == STALL)
{
/* if data transport stall, there is a bug in the code, return failed directly */
StorClearHalt(stor, pipe);
return STOR_TRANSPORT_ERR;
}
else if (err == DEVICE_NOT_RESPONDING)
{
return STOR_TRANSPORT_ERR;
}
else if (err == ERR)
{
return STOR_TRANSPORT_ERR;
}
else if (err == NO_ERROR)
{
transportStatus = 2;
}
else
{
return UNKNOW;
}
}
else if (transportStatus == 2)
{
/* receive csw */
err = UsbBulkMsg(stor->Device,
stor->PipeBulkIn,
&csw,
sizeof(CSW),
FALSE,
&actLength
);
if (err == STALL || err == DEVICE_NOT_RESPONDING)
{
if (StorClearHalt(stor, stor->PipeBulkIn) != NO_ERROR)
return STOR_TRANSPORT_ERR;
}
else if (err == ERR)
{
return STOR_TRANSPORT_ERR;
}
else if (LE32ToCPU(csw.Signature) != US_BULK_CS_SIGN || csw.Tag != cbw.Tag)
{
/* invalid csw, recorvery storage device and resend cbw */
if (StorResetRecovery(stor) != NO_ERROR)
return US_BULK_STAT_FAIL;
transportStatus = 0;
}
else if (csw.Status == US_BULK_STAT_FAIL)
{
return US_BULK_STAT_FAIL;
}
else if (csw.Status == US_BULK_STAT_PHASE)
{
return STOR_TRANSPORT_ERR;
}
else
{
return US_BULK_STAT_OK;
}
}
else
{
return UNKNOW;
}
to--;
}/* end while */
return STOR_TRANSPORT_ERR;
}
extern BYTE
StorInquiry(
STORAGE *stor,
BYTE lun,
BYTE *buf,
BYTE size
)
{
SCSI_CMD scsiCmd;
scsiCmd.Cmd = INQUIRY;
scsiCmd.CmdLen = 6;
scsiCmd.Lun = lun;
scsiCmd.DataDirection = US_BULK_FLAG_IN;
scsiCmd.Buf = buf;
scsiCmd.BufLen = size;
return StorBulkTransport(stor, &scsiCmd);
}
extern BYTE
StorTestUnitReady(
STORAGE *stor,
BYTE lun
)
{
SCSI_CMD scsiCmd;
scsiCmd.Cmd = TEST_UNIT_READY;
scsiCmd.CmdLen = 6;
scsiCmd.Lun = lun;
scsiCmd.DataDirection = US_BULK_FLAG_OUT;
scsiCmd.Buf = NULL;
scsiCmd.BufLen = 0;
return StorBulkTransport(stor, &scsiCmd);
}
extern BYTE
StorRequestSense(
STORAGE *stor,
BYTE lun,
BYTE *buf,
BYTE size
)
{
SCSI_CMD scsiCmd;
scsiCmd.Cmd = REQUEST_SENSE;
scsiCmd.CmdLen = 12;
scsiCmd.Lun = lun;
scsiCmd.DataDirection = US_BULK_FLAG_IN;
scsiCmd.Buf = buf;
scsiCmd.BufLen = size;
return StorBulkTransport(stor, &scsiCmd);
}
extern BYTE
StorReadCapacity(
STORAGE *stor,
BYTE lun,
BYTE *buf,
BYTE size
)
{
SCSI_CMD scsiCmd;
scsiCmd.Cmd = READ_CAPACITY;
scsiCmd.CmdLen = 10;
scsiCmd.Lun = lun;
scsiCmd.DataDirection = US_BULK_FLAG_IN;
scsiCmd.Buf = buf;
scsiCmd.BufLen = size;
return StorBulkTransport(stor, &scsiCmd);
}
/*-----------------------------------------------------------*/
/*-------------------file system interface-------------------*/
extern BYTE
StorReadBlock(
BYTE lun,
DWORD lba,
VOID *buf,
WORD size
)
{
LOGICAL_UNIT *lu;
SCSI_CMD scsiCmd;
lu = &gLu[lun];
if (lba > lu->LastLBA)
return STOR_TRANSPORT_ERR;
scsiCmd.Cmd = READ_10;
scsiCmd.CmdLen = 10;
scsiCmd.Lun = lun;
scsiCmd.DataDirection = US_BULK_FLAG_IN;
scsiCmd.Buf = buf;
scsiCmd.BufLen = size * lu->BlockSize;
scsiCmd.Lba = lba;
scsiCmd.BlockSize = lu->BlockSize;
return StorBulkTransport(lu->Stor, &scsiCmd);
}
extern BYTE
GetStorLun(VOID)
{
BYTE i, retVal = 0;
for (i = 0; i < TOTAL_LOGICAL_UNIT_NUM; ++i)
{
if ((gLuMap & (0x01 << i)) != 0
&& gLu[i].BlockSize != 0)
retVal++;
}
return retVal;
}
/*-----------------------------------------------------------*/
/*--------------------init storage device--------------------*/
extern BOOL
OpenStor(
STORAGE *stor,
USB_DEVICE *device,
USB_CONFIG *config,
USB_INTERFACE *interface
)
{
USB_ENDPOINT *endpoint;
LOGICAL_UNIT *lu;
DWORD temp;
BYTE i, j;
BYTE buffer[64];
BYTE to;
stor->Device = device;
stor->Interface = interface;
stor->InterfaceNum = interface->InterfaceDescriptor.bInterfaceNumber;
stor->SubClass = interface->InterfaceDescriptor.bInterfaceSubClass;
stor->Protocol = interface->InterfaceDescriptor.bInterfaceProtocol;
/* open pipe */
for (i = 0; i < interface->InterfaceDescriptor.bNumEndpoints; ++i)
{
endpoint = interface->Endpoint[i];
if ((endpoint->EndpointDescriptor.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
{
if ((endpoint->EndpointDescriptor.bEndpointAddress & USB_DIR_IN) == USB_DIR_IN)
{
/* load bulk in pipe */
stor->PipeBulkIn = 0xC0000080;
temp = (endpoint->EndpointDescriptor.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
temp <<= 15;
stor->PipeBulkIn |= temp;
temp = device->DevAddress;
temp <<= 8;
stor->PipeBulkIn |= temp;
temp = LE16ToCPU(endpoint->EndpointDescriptor.wMaxPacketSize);
j = 0;
while(temp > 0x0008)
{
j++;
temp >>= 1;
}
stor->PipeBulkIn |= j;
}
else
{
/* load bulk out pipe */
stor->PipeBulkOut = 0xC0000000;
temp = (endpoint->EndpointDescriptor.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
temp <<= 15;
stor->PipeBulkOut |= temp;
temp = device->DevAddress;
temp <<= 8;
stor->PipeBulkOut |= temp;
temp = LE16ToCPU(endpoint->EndpointDescriptor.wMaxPacketSize);
j = 0;
while(temp > 0x0008)
{
j++;
temp >>= 1;
}
stor->PipeBulkOut |= j;
}
}
else
{
/* ignore other endpoint */
continue;
}
}/* end for */
/* set usb device configuration */
if (UsbSetDeviceConfig(device, config, interface) != NO_ERROR)
return FALSE;
/* get storage max lun */
if (StorGetMaxLUN(stor) != NO_ERROR)
return FALSE;
for (i = 0; i < stor->MaxLogicalUnitNum + 1; ++i)
{
lu = AllocLogicalUnit();
if (lu == NULL)
return FALSE;
stor->Lu[i] = lu;
lu->Stor = stor;
lu->LogicalUnitNum = i;
if (StorInquiry(stor, i, buffer, 36) != US_BULK_STAT_OK)
return FALSE;
for (to = 0; to < 3; ++to)
{
if (StorTestUnitReady(stor, i) != US_BULK_STAT_OK)
{
if (StorRequestSense(stor, i, buffer, 18) != US_BULK_STAT_OK)
break;
continue;
}/* end if */
if (StorReadCapacity(stor, i, buffer, 8) != US_BULK_STAT_OK)
continue;
lu->LastLBA = *(DWORD *)buffer;
lu->BlockSize = *(DWORD *)(buffer + 4);
break;
}/* end for (to = 0; to < 3; ++to) */
}/* end for (i = 0; i < stor->MaxLogicalUnitNum + 1; ++i) */
return TRUE;
}
/*-----------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -