📄 msclass.c
字号:
case STATE_CSW_SENT:
//Get ready to receive the next CBW
//Setup and Arm our out endpoint
ActivateEndpoint (EP_FOR_OUT_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CBW_LENGTH);
PrepareOUTEPForXFer (EP_FOR_OUT_TRANSFERS);
ArmEndpoint (EP_FOR_OUT_TRANSFERS, EP_OUT);
//Dprintf ("OnInTransferComplete: Will wait for next CBW");
gCommandStatusState = STATE_WAITFOR_CBW;
break;
case STATE_SEND_DATA:
ShipDataUp ();
break;
}
}
}
/*------------------------------------------------------------
* OnOutTransferComplete
*
* Parameters:
* endpointNumber - the endpoint on which the transfer was completed.
* buffer - data buffer where the data was received
* numBytesReceived - number of bytes received
* wasPCAsserted - was the PC(packet complete) asserted when the TC interrup
* came in. If not, this could be a possible problem???
*
* Globals Used:
* gIsTransferActive, gCommandStatusState, gCurrentCBW, gRemainingDataToComeIn
*
* Description:
* This routine is called when a transfer is completed on one of the
* out endpoints.
*
* Returns:
* true to tell the isr to recycle the dma buffer, and setup
* things for the next transfer, false to tell the isr to
* free up the dma buffer, and disarm the endpoint.
*
*------------------------------------------------------------*/
bool OnOutTransferComplete (UCHAR endpointNumber, void *buffer, UINT numBytesReceived, bool wasPCAsserted)
{
void *pCSWBuffer;
bool validCBW = false;
if (endpointNumber != EP_FOR_OUT_TRANSFERS)
return(false);
switch (gCommandStatusState)
{
case STATE_WAITFOR_CBW:
//Dprintf ("Received CBW");
if (numBytesReceived >= CBW_LENGTH)
if (ExtractCBW (&gCurrentCBW, buffer))
{
validCBW = true;
//Dprintf ("Valid CBW");
return ProcessCBW (&gCurrentCBW);
}
if (!validCBW)
{
Dprintf ("Invalid CBW");
//Need to prepare an error CSW
StallEndpoint (EP_FOR_IN_TRANSFERS);
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_FAILED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
return (false);
}
break;
case STATE_WAITFOR_DATA:
//Dprintf1 ("More Data Received, remain: %08x", gRemainingDataToComeIn);
SCSI_ProcessData (buffer, numBytesReceived);
gRemainingDataToComeIn -= numBytesReceived;
if (gRemainingDataToComeIn)
{
ULONG inThisPass;
if (gRemainingDataToComeIn < BULKEP_MAX_TRANSFER_SIZE)
{
UnprepareEP (EP_FOR_OUT_TRANSFERS);
ActivateEndpoint (EP_FOR_OUT_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE,
gRemainingDataToComeIn);
PrepareOUTEPForXFer (EP_FOR_OUT_TRANSFERS);
}
return (true);
}
else
{
gIsTransferActive = false;
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_PASSED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
return (false);
}
//break;
default:
return(false);
}
return (false);
}
/*------------------------------------------------------------
* ProcessCBW
*
* Parameters:
* pCBW - pointer to a vaild CBW
*
* Globals Used:
* gCurrentCBW, gRemainingDataToComeIn, gpDataToShipUp, gResidue,
* gRemainingDataToShipUp, gCommandStatusState
*
* Description:
* This routine processes the Command Block Wrapper and decides
* what is to be done next!
*
* Returns:
* true to receive more data, false to not receive more data.
*
*------------------------------------------------------------*/
bool ProcessCBW (PCBW pCBW)
{
void *pBuffer;
void *pCSWBuffer;
ULONG validDataLen;
if (!IsCBWMeaningful(pCBW))
{
/*
void *pCSWBuffer;
//Need to prepare an error CSW
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_FAILED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
*/
Dprintf1 ("Unknown SCSI Opcode: %02x", pCBW->wcb[0]);
StallEndpoint (EP_FOR_IN_TRANSFERS);
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_FAILED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
return (false);
}
//If we're here the CBW is meaningful, let's do what the command asks us to do!
//Dprintf1 ("SCSI Opcode: %02x", pCBW->wcb[0]);
if (SCSI_ProcessCDB (pCBW->wcb, pCBW->wcbLength, pCBW->dataTransferLength, &pBuffer, &validDataLen))
{
if (pCBW->dataTransferLength == 0)
{
//no data involved, lets sutp the CSW
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_PASSED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
return (false);
}
//If the direction was device to host - start sending the data back
if (pCBW->flags & CDW_FLAG_DATA_FROM_DEVICE_TO_HOST)
{
gIsTransferActive = true;
gResidue = pCBW->dataTransferLength - validDataLen;
gRemainingDataToShipUp = pCBW->dataTransferLength;
gpDataToShipUp = pBuffer;
ShipDataUp ();
}
else
{
gIsTransferActive = true;
UnprepareEP (EP_FOR_OUT_TRANSFERS);
//wait for more data
gCommandStatusState = STATE_WAITFOR_DATA;
gRemainingDataToComeIn = pCBW->dataTransferLength;
ActivateEndpoint (EP_FOR_OUT_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE,
(gRemainingDataToComeIn > BULKEP_MAX_TRANSFER_SIZE) ? BULKEP_MAX_TRANSFER_SIZE : gRemainingDataToComeIn);
PrepareOUTEPForXFer (EP_FOR_OUT_TRANSFERS);
return (true);
}
}
else
{
//Need to prepare an error CSW
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_FAILED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
}
return (false);
}
/*------------------------------------------------------------
* IsCBWMeaningful
*
* Parameters:
* pCBW - the CBW to check.
*
* Globals Used:
* None
*
* Description:
* Determines if the provided CBW is meaningful. It
* depends on the SCSI implementation module to check
* the command block.
*
* Returns:
* true if it is meaningful, false otherwise.
*
*------------------------------------------------------------*/
bool IsCBWMeaningful (PCBW pCBW)
{
if (pCBW->lun > MAX_LUN)
return(false);
if (pCBW->wcbLength > CBW_WCB_LEN)
return(false);
//Check the command opcode
return SCSI_IsValidCommandBlock (&pCBW->wcb[0], pCBW->wcbLength);
}
/*------------------------------------------------------------
* ShipDataUp
*
* Parameters:
*
* Globals Used:
* gRemainingDataToShipUp, gpDataToShipUp
*
* Description:
* This routine takes care of preparing the IN endpoint
* to send data back to the host. It uses gRemainingDataToShipUp
* and gpDataToShipUp to decide how much data to ship up. If there
* is no data to ship up, it fills in a CSW and sets the endpoint
* to return the CSW.
*
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void ShipDataUp (void)
{
ULONG inThisPass;
void *pBuffer, *pCSWBuffer;
//Dprintf1 ("ShipDataUp: %d", gRemainingDataToShipUp);
if (gRemainingDataToShipUp)
{
inThisPass = (gRemainingDataToShipUp > BULKEP_MAX_TRANSFER_SIZE) ? BULKEP_MAX_TRANSFER_SIZE : gRemainingDataToShipUp;
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, inThisPass);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pBuffer);
memcpy (pBuffer, gpDataToShipUp, inThisPass);
gpDataToShipUp = ((PUCHAR)gpDataToShipUp + inThisPass);
gRemainingDataToShipUp -= inThisPass;
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_SEND_DATA;
}
else
{
gIsTransferActive = false;
//All data has been sent, so now send the CSW
ActivateEndpoint (EP_FOR_IN_TRANSFERS, USBD_TYP_BULK, BULKEP_MAX_PACKET_SIZE, CSW_LENGTH);
PrepareINEPForXFer (EP_FOR_IN_TRANSFERS, &pCSWBuffer);
BuildCSW (pCSWBuffer, gCurrentCBW.tag, 0, CSW_STATUS_COMMAND_PASSED);
ArmEndpoint (EP_FOR_IN_TRANSFERS, EP_IN);
gCommandStatusState = STATE_CSW_SENT;
}
}
/*------------------------------------------------------------
* OnNAKSent
*
* Parameters:
* endpointNumber - endpoint where the NAK was sent.
*
* Globals Used:
* gPrepareReport
*
* Description:
* This routine is called when the device has sent a NAK in response
* to an IN or OUT request while the DMA buffer for that endpoint
* has been emptied. Please note that this will only be called in
* response to an "expected" direction request - IN request for
* endpoints setup as IN endpoints and OUT request for endpoints
* setup as OUT endpoints.
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void OnNAKSent (UCHAR endpointNumber)
{
}
/*------------------------------------------------------------
* OnSuspend
*
* Parameters:
*
* Globals Used:
* gpOnSuspend, gIsTransferActive
*
* Description:
* This routine will be called when USBDriver detects a
* suspend condition. Currently, it quites the AC97 and forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnSuspend (void)
{
gIsTransferActive = false;
if (gpOnSuspend)
(gpOnSuspend)();
}
/*------------------------------------------------------------
* OnResume
*
* Parameters:
*
* Globals Used:
* gpOnResume, gIsDeviceConfigured
*
* Description:
* This routine will be called when the USBDriver detects that
* the bus is out of suspend. Currently, it simply forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnResume (void)
{
gIsDeviceConfigured = false;
MSReset ();
if (gpOnResume)
(gpOnResume) ();
}
/*------------------------------------------------------------
* OnSOF
*
* Parameters: None.
*
* Globals Used:
*
* Description:
* This routine will be called when the USBDriver receives an SOF
* interrupt. It is mainly used to see if the transfers have timed out.
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnSOF (void)
{
}
/*------------------------------------------------------------
* OnReset
*
* Parameters:
*
* Globals Used:
* gpOnReset, gIsDeviceConfigured, gIsTransferActive
*
* Description:
* This routine will be called when the USBDriver detects reset
* signalling on the bus. Currently, it quiets the codec and forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnReset (void)
{
gIsDeviceConfigured = false;
gIsTransferActive = false;
MSReset ();
if (gpOnReset)
(gpOnReset)();
}
/*------------------------------------------------------------
* ExtractCBW
*
* Parameters:
* pCBW - pointer to a CBW to fill.
* pBuffer - pointer to a buffer that contains data for the CBW.
*
* Globals Used:
* None
*
* Description:
* Extracts fields for the CBW from a data buffer.
*
* Returns:
* true if the signature matches, false otherwise.
*
*------------------------------------------------------------*/
bool ExtractCBW (PCBW pCBW, UCHAR *pBuffer)
{
pCBW->signature = *(PULONG)pBuffer;
pCBW->tag = *(PULONG)(pBuffer+CBW_TAG_OFFSET);
pCBW->dataTransferLength = *(PULONG)(pBuffer+CBW_DATA_TRANSFER_LENGTH_OFFSET);
pCBW->flags = *(PUCHAR)(pBuffer+CBW_FLAGS_OFFSET);
pCBW->lun = *(PUCHAR)(pBuffer+CBW_LUN_OFFSET);
pCBW->wcbLength = *(PUCHAR)(pBuffer+CBW_WCBLENGTH_OFFSET);
memcpy (&pCBW->wcb[0], pBuffer+CBW_WCB_OFFSET, CBW_WCB_LEN);
return (pCBW->signature == CBW_SIGNATURE);
}
/*------------------------------------------------------------
* BuildCSW
*
* Parameters:
* pBuffer - points to a buffer where the CSW must be built.
* tag - tag for the CSW
* dataResidue - for the CSW
* status - for the CSW
*
* Globals Used:
* None
*
* Description:
* Builds a CBW (buffer) from provided parameters.
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void BuildCSW (UCHAR *pBuffer, ULONG tag, ULONG dataResidue, UCHAR status)
{
*(PULONG)pBuffer = CSW_SIGNATURE;
*(PULONG)(pBuffer + CSW_TAG_OFFSET) = tag;
*(PULONG)(pBuffer + CSW_DATA_RESIDUE_OFFSET) = dataResidue;
*(pBuffer + CSW_STATUS_OFFSET) = status;
}
/*----------------------------------------------------------------------------------
* $Log: MSClass.c,v $
* Revision 1.4 2003/03/03 22:36:43 Devendra
* - Added documentation.
* - Some code cleanup.
*
* Revision 1.3 2003/03/03 21:38:44 Devendra
* - Changed the bulk transfer mechainsm to make it more efficient by using transfer lengths that are the same size as the disk block sizes.
*
* Revision 1.2 2003/03/03 21:26:41 Devendra
* - BugFix: Writes were not working correctly.
* - Changed to using the SDRAM for disk data storage.
* - Increased the disk capacity to 16MB.
* - Added disk init. routine to make it look like a FAT formatted 16MB disk.
*
* Revision 1.1 2003/03/03 18:13:45 Devendra
* First Rev, the device enumerates as Mass Storage Class
*
*
*---------------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -