📄 usbmass.c
字号:
#include "reg51.h"
#include "read_reg.h"
#include "usbmass.h"
#define TRY_WAIT 100 //100
#define ERROR_WAIT 500
#define READCAP_STALL_CNT_MAX 5
int gLunSet = 0; //"LUN" for USB_XXX routines
XD U8 gCBW[31]; //SCSI CBW 31byte or
XD U8 gMaxLun; //gMaxLun = ??á??· LUN
XD U8 gLunFlag; //bitmap for LUN presence
XD U8 gLunMask; //bit=0: allow, bit=1: disable(CD or ...)
XD U32 gLastSec; //last PHYSICAL sector
extern XD U8 gDevAddr;
U32 gUsbReadUnit;
extern XD U8 gEPOUT; //out-endpoint
extern XD U8 gEPIN; //in-endpoint
extern XD U8 volatile gEP;
extern XD U8 gIrqEn;
extern XD U8 gLun; //"LUN" for USB_XXX routines
extern XD U8 gMxPkSz; //maximum packet size (bulk)
extern XD U8 gIFSC; //interface sub-class
extern XD U8 gUsbVer; //USB Version
extern U8 gStallMark;
extern int gSecCnt;
extern int gSecAddr;
extern XD U16 gVID;
extern XD U16 gPID;
U32 gUsbTrgCnt; //1=when to get CSW,0=no active read
XD U32 gTotSecCnt; //total sector including all system area (for current partition)
/******************************************************************************
* RETURN:
* RES_ERR/RES_OK
* NOTE:
* gCBW俊 31 byte CBW data甫 固府 盲款 饶 妮!
******************************************************************************/
U8 SCSI_SendCBW(void)
{
UH_SET_FIFO_SZ_EACH(0,31);
UH_FIFO_ROLLBACK_OUT();
UH_IRQ_EN(UH_IRQ_USB_PKT_DONE);
DEV_WriteRegMulti(RH_USB_HOST_BASE_ADDR, 31, (U8*)gCBW);
UH_Trigger(gEPOUT);
//if(DEV_WaitForIrq(UH_IRQ_USB_PKT_DONE)==0) return RES_ERR_SCSI_CBW;
return RES_OK;
}
/******************************************************************************
* INPUT:
* - totBytCnt : total byte count of DATA-IN
* - buf : pointer to a data buffer
* NULL if you want to discard the data
* RETURN:
* RES_ERR: timeout or CSW error
* RES_ERR+1: CSW error --> require REQUEST_SENSE
* RES_OK: success
* RES_OK+1: incomplete DATA-IN
* RES_OK+UH_IRQ_FAKE_STALL: stalled --> require CSW-IN
*
******************************************************************************/
U8 SCSI_GetDataIn(U16 totBytCnt, U8* buf)
{
U8 res;
U16 bytCnt;
res=RES_OK;
while(totBytCnt>0)
{
bytCnt = (totBytCnt>64)?64:totBytCnt;
res = DEV_SafeTriggerAndWaitForInPacket(gEPIN,bytCnt,2000);
if(UH_IRQ_FAKE_STALL==res) return (RES_OK+UH_IRQ_FAKE_STALL); // --> continue on CSW stage
if(0==res) return RES_ERR; //timeout
UH_FIFO_ROLLBACK_IN();
if(buf!=TxNULL){ DEV_ReadRegMulti(RH_USB_HOST_BASE_ADDR,bytCnt,buf); }
else{ DEV_ReadRegMultiAndDiscard(RH_USB_HOST_BASE_ADDR,bytCnt); }
if(!(UH_IRQ_READ_READY&res))//incomplete data-in
{
if((bytCnt<13)||(buf==TxNULL)) return RES_ERR; //we can't see CSW error flag
if(buf[0]==0&&buf[1]==0){ //ZERO packet arrived!
if(buf[2]==0x42&&buf[3]==0x43) return RES_OK+1; // only ZERO packet --> continue on CSW
if(buf[2]==0x55&&buf[3]==0x53){ //CSW followed ZERO packet
if(bytCnt>=15&&buf[4]==0x42&&buf[5]==0x53&&buf[14]==1) return RES_ERR+1;
return RES_ERR;
}
}
else if(buf[0]==0x55&&buf[1]==0x53&&buf[2]==0x42&&buf[3]==0x53){ //CSW arrived without DATA-IN
if(bytCnt>=13&&buf[12]==1) //SCSI_RequestSense(); //LIU TEST 11-29
return RES_ERR; //CSW
}
}
totBytCnt -=bytCnt;
if(buf!=TxNULL) buf += bytCnt;
}
return res;
}
U8 SCSI_RequestSense(void)
{
U8 res;
MemFill(gCBW+8,0,31-8);
DEV_WriteReg(RH_USB_HOST_BASE_LEN,gMxPkSz);
gCBW[13]=gLun;
SET_CBW_BULKIN();
SET_CBW_CMD(SCSI_CMD_REQUESTSENSE);
gCBW[14]=0x0C;
gCBW[8]=gCBW[19]=18;
SCSI_SendCBW();
if(DEV_WaitForIrq(UH_IRQ_USB_PKT_DONE)==0) return RES_ERR_SCSI_CBW;
res = SCSI_GetDataIn(18,(U8*)TxNULL);
if(ISERR(res)) return RES_ERR; //timeout or earlier CSW (no measure for CSW-error)
res = SCSI_SafeCSW();
if(ISERR(res)) return RES_ERR; //timeout or earlier CSW (no measure for CSW-error)
return RES_OK;
}
/******************************************************************************
* INPUT:
*
* RETURN:
* RES_ERR: timeout or CSW error
* RES_ERR+1: CSW error --> require REQUEST_SENSE
* RES_OK: success
* RES_OK+UH_IRQ_FAKE_STALL: stalled --> no measure
*
******************************************************************************/
U8 SCSI_SafeCSW(void)
{
U8 res;
res = DEV_SafeTriggerAndWaitForInPacket(gEPIN,13,2000);
if(res==0) return RES_ERR; //timeout --> no measure
if(UH_IRQ_FAKE_STALL==res) return UH_IRQ_FAKE_STALL;
UH_FIFO_ROLLBACK_IN();
res = DEV_ReadRegMultiAndDiscard(RH_USB_HOST_BASE_ADDR,13);
return (res==0)?RES_OK:RES_ERR+1;
}
/******************************************************************************
* IMPLICIT INPUT:
* - gLun : LUN number
*
* NOTE:
*
* Mode-Sense: subclass=6(SCSI-2) 捞搁 SCSI_CMD_MODESENSE6,
* 酒聪搁 SCSI_CMD_MODESENSE10
* * 林狼: 固府 buf[0] 俊 pageCode甫 持阑巴!!
*
* Prevent-Allow: buf=0(NULL) 捞搁 Allow,
* 弊寇绰 Prevent
*
* RETURN:
* RES_ERR_SCSI_CBW
* RES_ERR_SCSI_CMD_IGNORED
* RES_ERR_SCSI_DATA
* RES_ERR
* RES_OK
******************************************************************************/
U8 SCSI_CMD(IN U8 cmd, OUT U8* buf)
{
U8 res1,res2,bytCnt;
res1=res2=RES_OK;
bytCnt=0;
MemFill(gCBW+8,0,31-8);
gCBW[13]=gLun;
SET_CBW_CMD(cmd);
SET_CBW_BULKIN();
if(gIFSC==6) gCBW[14]=0x06; //CBW Length for subclass-6: non-fixed!!
else gCBW[14]=0x0C; //CBW Length for non-subclass-6: fixed to 0x0C
switch(cmd)
{
case SCSI_CMD_TESTUNITREADY: SET_CBW_BULKOUT();
break;
case SCSI_CMD_INQUIRY: bytCnt=0x24;
gCBW[8]=gCBW[19]=bytCnt;
break;
case SCSI_CMD_PREVENTALLOW: SET_CBW_BULKOUT();
gCBW[19]=(buf==NULL)?0:1; //1=prevent(disable removal)
break;
case SCSI_CMD_READFORMATCAP: bytCnt=12;
gCBW[8]=gCBW[23]=bytCnt;//0xFC;
if(gIFSC==6)gCBW[14]=0x0A;
break;
case SCSI_CMD_READCAPACITY: bytCnt=0x08;
gCBW[8]=bytCnt;
if(gIFSC==6)gCBW[14]=0x0A;
break;
case SCSI_CMD_TO_STALL_EPIN: bytCnt=1;
gCBW[8]=1;
break;
default:
return RES_ERR;
}
SCSI_SendCBW();
if(DEV_WaitForIrq(UH_IRQ_USB_PKT_DONE)==0) return RES_ERR_SCSI_CBW;
DEV_WaitMS(10);
res1 = SCSI_GetDataIn(bytCnt,buf);
if(res1==RES_ERR) return RES_ERR; //timeout
else if(res1==RES_ERR+1){ //earlier CSW(with error flag)
SCSI_RequestSense();
return RES_ERR;
}
res2 = SCSI_SafeCSW();
if(res2==RES_ERR+1){ //earlier CSW(with error flag)
SCSI_RequestSense();
return RES_ERR;
}
if((res1|res2)&UH_IRQ_FAKE_STALL) return RES_ERR+1;
if(ISERR(res2)) return RES_ERR;
return RES_OK;
}
U8 UM_SetLun(U8 bLun, U8* tBUF)
{
if(gLunMask&(1<<bLun)) return RES_ERR; //skip non-generic storage
//#if (UMO_EXACT_SECTOR_READ==0)
// if(gSecCnt>0){ UBI9021_FlushSectorRead(); }
//#endif
if(bLun<=gMaxLun)
{
gLun = bLun;
if(ISERR(SCSI_ReadCapacity(tBUF))){
DEV_WaitMS(1);
gLastSec = nOK32-1; //unknown size
}else{
gLastSec = (((U32)tBUF[0])<<24)+(((U32)tBUF[1])<<16)+(((U32)tBUF[2])<<8)+((U32)tBUF[3]);
}
gTotSecCnt = gLastSec+1;
return RES_OK;
}
return RES_ERR;
}
/******************************************************************************
*
* get lun count and initialize each LUN
*
* INPUT:
* - tBUF: tiny buffer for SCSI data-in
*
* OUTPUT:
* - gLunFlag = bitmap for LUN presence (each bit indicate presence of each LUN)
* - gMaxLun
*
* RETURN:
* return max LUN
* return RES_ERR(=0x80)
*
******************************************************************************/
U8 UM_InitMultiLun(U8* tBUF)
{
int i;
U8 res,rcscnt=0; //read-capacity stall count
U8 maxTryCnt=3;
///GET-MAX-LUN:
gMaxLun = 0;
gLunMask = 0;
if(ISOK(USB_ControlTransfer(USB_SETUP_GET_MAX_LUN,0,tBUF))){ gMaxLun = tBUF[0]; }
DEV_WriteReg(RH_USB_HOST_BASE_LEN,gMxPkSz);
if(gMaxLun>=16) gMaxLun=0;
if(gMaxLun>0) DEV_WaitMS(3000);//wait 3second for multi-card reader
else DEV_WaitMS(500);
for(gLun=0;gLun<=gMaxLun;gLun++)
{
DEV_WaitMS(TRY_WAIT); //100msec
if(ISERR(SCSI_Inquiry(tBUF))){
if(gDevAddr!=DEV_ReadReg(RH_DEV_ADDR)||0x5A!=DEV_ReadReg(RH_MASS_ADDR2)) return RES_ERR;
DEV_WaitMS(ERROR_WAIT);
continue;
}
else{
if(tBUF[0]!=0){ //check if generic Flash or HDD drive (0x05=CD)
gLunMask |= (1<<gLun);
continue;
}
}
// DEV_WaitMS(TRY_WAIT);
// if(ISERR(SCSI_ReadFormatCapacity(tBUF))){
// DEV_WaitMS(ERROR_WAIT);
// }
DEV_WaitMS(TRY_WAIT);
if(ISERR(SCSI_TestUnit())){
if(gDevAddr!=DEV_ReadReg(RH_DEV_ADDR)||0x5A!=DEV_ReadReg(RH_MASS_ADDR2)) return RES_ERR;
DEV_WaitMS(ERROR_WAIT);
}
}
IML_RETRY:
rcscnt=0;
for(gLun=0,gLunFlag=0;gLun<=gMaxLun;gLun++)
{
if(gLunMask&(1<<gLun))continue; //skip non-generic storage
DEV_WaitMS(TRY_WAIT);
if(rcscnt<READCAP_STALL_CNT_MAX){
res = SCSI_ReadCapacity(tBUF);
if(res==RES_ERR+1)rcscnt++;
if(ISERR(res)){
if(gDevAddr!=DEV_ReadReg(RH_DEV_ADDR)||0x5A!=DEV_ReadReg(RH_MASS_ADDR2)) return RES_ERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -