/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { static BYTE MSDWriteState = MSD_WRITE10_WAIT; switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { if(LUNWriteProtectState()) { gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; msd_csw.bCSWStatus=0x01; //TODO: (DF) - what state should I return to? } else { MSDWriteState = MSD_WRITE10_SECTOR; } break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { break; } // if (status) { // msd_csw.bCSWStatus=0x01; // /* add some sense keys here*/ // } LBA.Val++; // One LBA is written. Write the next LBA TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } } return MSDWriteState; }
/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; //Initially assume success, unless handler code later encounters an //error condition and sets the status to 0x01 or 0x02. msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { //We finished receiving a sector worth of data from the host. //Check if the media is write protected before deciding what //to do with the data. if(LUNWriteProtectState()) { //The device appears to be write protected. //Let host know error occurred. The bCSWStatus flag is also used by //the write handler, to know not to even attempt the write sequence. msd_csw.bCSWStatus=0x01; //Set sense keys so the host knows what caused the error. gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; } MSDWriteState = MSD_WRITE10_SECTOR; break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { //Make sure that no error has been detected, before performing the write //operation. If there was an error, skip the write operation, but allow //the TransferLength to continue decrementing, so that we can eventually //receive all OUT bytes that the host is planning on sending us. Only //after that is complete will the host send the IN token for the CSW packet, //which will contain the bCSWStatus letting it know an error occurred. if(msd_csw.bCSWStatus == 0x00) { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { //The write operation failed for some reason. Keep track of retry //attempts and abort if repeated write attempts also fail. if(MSDRetryAttempt < MSD_FAILED_WRITE_MAX_ATTEMPTS) { MSDRetryAttempt++; break; } else { //Too many consecutive failed write attempts have occurred. //Need to give up and abandon the write attempt. msd_csw.bCSWStatus=0x01; // Error 0x01 Refer page#18 // of BOT specifications //Set error status sense keys, so the host can check them later //to determine how to proceed. gblSenseData[LUN_INDEX].SenseKey=S_MEDIUM_ERROR; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } } } //One LBA is written (unless an error occurred). Advance state //variables so we can eventually finish handling the CBW request. LBA.Val++; TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } default: //Illegal condition which should not occur. If for some reason it //does, try to let the host know know an error has occurred. msd_csw.bCSWStatus=0x02; //Phase Error MSDWriteState = MSD_WRITE10_WAIT; } return MSDWriteState; }