Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet.

Removed scheduler and memory allocation libraries.

Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated).

Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt.
This commit is contained in:
Dean Camera 2009-06-01 11:03:39 +00:00
parent 2440ca268a
commit d1e5266036
106 changed files with 3072 additions and 5760 deletions

View file

@ -46,7 +46,7 @@
* \param BlockAddress Data block starting address for the write sequence
* \param TotalBlocks Number of blocks of data to write
*/
void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks)
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
@ -142,7 +142,7 @@ void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlo
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
if (MSInterfaceInfo->IsMassStoreReset)
return;
}
@ -171,7 +171,7 @@ void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlo
* \param BlockAddress Data block starting address for the read sequence
* \param TotalBlocks Number of blocks of data to read
*/
void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks)
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
@ -250,7 +250,7 @@ void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBloc
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
if (MSInterfaceInfo->IsMassStoreReset)
return;
}
@ -341,11 +341,7 @@ void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t Tota
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
BytesInBlockDiv16++;
}
/* Decrement the blocks remaining counter and reset the sub block counter */
@ -421,10 +417,6 @@ void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t Total
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Decrement the blocks remaining counter */

View file

@ -64,8 +64,8 @@
#define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
/* Function Prototypes: */
void DataflashManager_WriteBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks);
void DataflashManager_ReadBlocks(const uint32_t BlockAddress, uint16_t TotalBlocks);
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks);
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks);
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,
uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks,

View file

@ -84,37 +84,37 @@ SCSI_Request_Sense_Response_t SenseData =
* to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns
* a command failure due to a ILLEGAL REQUEST.
*/
void SCSI_DecodeSCSICommand(void)
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
bool CommandSuccess = false;
/* Run the appropriate SCSI command hander function based on the passed command */
switch (CommandBlock.SCSICommandData[0])
switch (MSInterfaceInfo->CommandBlock.SCSICommandData[0])
{
case SCSI_CMD_INQUIRY:
CommandSuccess = SCSI_Command_Inquiry();
CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo);
break;
case SCSI_CMD_REQUEST_SENSE:
CommandSuccess = SCSI_Command_Request_Sense();
CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo);
break;
case SCSI_CMD_READ_CAPACITY_10:
CommandSuccess = SCSI_Command_Read_Capacity_10();
CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
break;
case SCSI_CMD_SEND_DIAGNOSTIC:
CommandSuccess = SCSI_Command_Send_Diagnostic();
CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
break;
case SCSI_CMD_WRITE_10:
CommandSuccess = SCSI_Command_ReadWrite_10(DATA_WRITE);
CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
break;
case SCSI_CMD_READ_10:
CommandSuccess = SCSI_Command_ReadWrite_10(DATA_READ);
CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
break;
case SCSI_CMD_TEST_UNIT_READY:
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
case SCSI_CMD_VERIFY_10:
/* These commands should just succeed, no handling required */
CommandSuccess = true;
CommandBlock.DataTransferLength = 0;
MSInterfaceInfo->CommandBlock.DataTransferLength = 0;
break;
default:
/* Update the SENSE key to reflect the invalid command */
@ -123,22 +123,18 @@ void SCSI_DecodeSCSICommand(void)
SCSI_ASENSEQ_NO_QUALIFIER);
break;
}
/* Check if command was successfully processed */
if (CommandSuccess)
{
/* Command succeeded - set the CSW status and update the SENSE key */
CommandStatus.Status = Command_Pass;
SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
SCSI_ASENSEQ_NO_QUALIFIER);
}
else
{
/* Command failed - set the CSW status - failed command function updates the SENSE key */
CommandStatus.Status = Command_Fail;
SCSI_ASENSEQ_NO_QUALIFIER);
return true;
}
return false;
}
/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
@ -146,16 +142,16 @@ void SCSI_DecodeSCSICommand(void)
*
* \return Boolean true if the command completed successfully, false otherwise.
*/
static bool SCSI_Command_Inquiry(void)
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
uint16_t AllocationLength = (((uint16_t)CommandBlock.SCSICommandData[3] << 8) |
CommandBlock.SCSICommandData[4]);
uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->CommandBlock.SCSICommandData[3] << 8) |
MSInterfaceInfo->CommandBlock.SCSICommandData[4]);
uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength :
sizeof(InquiryData);
/* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
if ((CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
CommandBlock.SCSICommandData[2])
if ((MSInterfaceInfo->CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
MSInterfaceInfo->CommandBlock.SCSICommandData[2])
{
/* Optional but unsupported bits set - update the SENSE key and fail the request */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
@ -164,20 +160,19 @@ static bool SCSI_Command_Inquiry(void)
return false;
}
/* Write the INQUIRY data to the endpoint */
Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, StreamCallback_AbortOnMassStoreReset);
Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK);
uint8_t PadBytes[AllocationLength - BytesTransferred];
/* Pad out remaining bytes with 0x00 */
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), StreamCallback_AbortOnMassStoreReset);
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
CommandBlock.DataTransferLength -= BytesTransferred;
MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred;
return true;
}
@ -187,24 +182,19 @@ static bool SCSI_Command_Inquiry(void)
*
* \return Boolean true if the command completed successfully, false otherwise.
*/
static bool SCSI_Command_Request_Sense(void)
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
uint8_t AllocationLength = CommandBlock.SCSICommandData[4];
uint8_t AllocationLength = MSInterfaceInfo->CommandBlock.SCSICommandData[4];
uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
/* Send the SENSE data - this indicates to the host the status of the last command */
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, StreamCallback_AbortOnMassStoreReset);
uint8_t PadBytes[AllocationLength - BytesTransferred];
/* Pad out remaining bytes with 0x00 */
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), StreamCallback_AbortOnMassStoreReset);
/* Finalize the stream transfer to send the last packet */
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
CommandBlock.DataTransferLength -= BytesTransferred;
MSInterfaceInfo->CommandBlock.DataTransferLength -= BytesTransferred;
return true;
}
@ -214,23 +204,17 @@ static bool SCSI_Command_Request_Sense(void)
*
* \return Boolean true if the command completed successfully, false otherwise.
*/
static bool SCSI_Command_Read_Capacity_10(void)
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
/* Send the total number of logical blocks in the current LUN */
Endpoint_Write_DWord_BE(LUN_MEDIA_BLOCKS - 1);
uint32_t TotalLUNs = (LUN_MEDIA_BLOCKS - 1);
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
/* Send the logical block size of the device (must be 512 bytes) */
Endpoint_Write_DWord_BE(VIRTUAL_MEMORY_BLOCK_SIZE);
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
/* Send the endpoint data packet to the host */
Endpoint_Write_Stream_BE(&TotalLUNs, sizeof(TotalLUNs), NO_STREAM_CALLBACK);
Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
CommandBlock.DataTransferLength -= 8;
MSInterfaceInfo->CommandBlock.DataTransferLength -= 8;
return true;
}
@ -241,12 +225,12 @@ static bool SCSI_Command_Read_Capacity_10(void)
*
* \return Boolean true if the command completed successfully, false otherwise.
*/
static bool SCSI_Command_Send_Diagnostic(void)
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
uint8_t ReturnByte;
/* Check to see if the SELF TEST bit is not set */
if (!(CommandBlock.SCSICommandData[1] & (1 << 2)))
if (!(MSInterfaceInfo->CommandBlock.SCSICommandData[1] & (1 << 2)))
{
/* Only self-test supported - update SENSE key and fail the command */
SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
@ -293,7 +277,7 @@ static bool SCSI_Command_Send_Diagnostic(void)
#endif
/* Succeed the command and update the bytes transferred counter */
CommandBlock.DataTransferLength = 0;
MSInterfaceInfo->CommandBlock.DataTransferLength = 0;
return true;
}
@ -306,20 +290,20 @@ static bool SCSI_Command_Send_Diagnostic(void)
*
* \return Boolean true if the command completed successfully, false otherwise.
*/
static bool SCSI_Command_ReadWrite_10(const bool IsDataRead)
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_t* MSInterfaceInfo, const bool IsDataRead)
{
uint32_t BlockAddress;
uint16_t TotalBlocks;
/* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */
((uint8_t*)&BlockAddress)[3] = CommandBlock.SCSICommandData[2];
((uint8_t*)&BlockAddress)[2] = CommandBlock.SCSICommandData[3];
((uint8_t*)&BlockAddress)[1] = CommandBlock.SCSICommandData[4];
((uint8_t*)&BlockAddress)[0] = CommandBlock.SCSICommandData[5];
((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->CommandBlock.SCSICommandData[2];
((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->CommandBlock.SCSICommandData[3];
((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->CommandBlock.SCSICommandData[4];
((uint8_t*)&BlockAddress)[0] = MSInterfaceInfo->CommandBlock.SCSICommandData[5];
/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */
((uint8_t*)&TotalBlocks)[1] = CommandBlock.SCSICommandData[7];
((uint8_t*)&TotalBlocks)[0] = CommandBlock.SCSICommandData[8];
((uint8_t*)&TotalBlocks)[1] = MSInterfaceInfo->CommandBlock.SCSICommandData[7];
((uint8_t*)&TotalBlocks)[0] = MSInterfaceInfo->CommandBlock.SCSICommandData[8];
/* Check if the block address is outside the maximum allowable value for the LUN */
if (BlockAddress >= LUN_MEDIA_BLOCKS)
@ -334,17 +318,17 @@ static bool SCSI_Command_ReadWrite_10(const bool IsDataRead)
#if (TOTAL_LUNS > 1)
/* Adjust the given block address to the real media address based on the selected LUN */
BlockAddress += ((uint32_t)CommandBlock.LUN * LUN_MEDIA_BLOCKS);
BlockAddress += ((uint32_t)MSInterfaceInfo->CommandBlock.LUN * LUN_MEDIA_BLOCKS);
#endif
/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
if (IsDataRead == DATA_READ)
DataflashManager_ReadBlocks(BlockAddress, TotalBlocks);
DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
else
DataflashManager_WriteBlocks(BlockAddress, TotalBlocks);
DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
/* Update the bytes transferred counter and succeed the command */
CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
MSInterfaceInfo->CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
return true;
}

View file

@ -40,9 +40,8 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <LUFA/Common/Common.h> // Function Attribute, Atomic, Debug and ISR Macros
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/Device/MassStorage.h>
#include "MassStorage.h"
#include "Descriptors.h"
@ -63,16 +62,16 @@
SenseData.AdditionalSenseQualifier = aqual; }MACROE
/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
#define DATA_READ true
#define DATA_READ true
/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
#define DATA_WRITE false
#define DATA_WRITE false
/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */
#define DEVICE_TYPE_BLOCK 0x00
#define DEVICE_TYPE_BLOCK 0x00
/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
#define DEVICE_TYPE_CDROM 0x05
#define DEVICE_TYPE_CDROM 0x05
/* Type Defines: */
/** Type define for a SCSI response structure to a SCSI INQUIRY command. For details of the
@ -136,14 +135,14 @@
} SCSI_Request_Sense_Response_t;
/* Function Prototypes: */
void SCSI_DecodeSCSICommand(void);
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_t* MSInterfaceInfo);
#if defined(INCLUDE_FROM_SCSI_C)
static bool SCSI_Command_Inquiry(void);
static bool SCSI_Command_Request_Sense(void);
static bool SCSI_Command_Read_Capacity_10(void);
static bool SCSI_Command_Send_Diagnostic(void);
static bool SCSI_Command_ReadWrite_10(const bool IsDataRead);
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_t* MSInterfaceInfo);
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_t* MSInterfaceInfo);
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_t* MSInterfaceInfo);
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_t* MSInterfaceInfo);
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_t* MSInterfaceInfo, const bool IsDataRead);
#endif
#endif

View file

@ -28,35 +28,35 @@
this software.
*/
/** \file
*
* Main source file for the Mass Storage demo. This file contains the main tasks of the demo and
* is responsible for the initial application hardware configuration.
*/
#define INCLUDE_FROM_MASSSTORAGE_C
#include "MassStorage.h"
/* Scheduler Task List */
TASK_LIST
{
{ .Task = USB_MassStorage , .TaskStatus = TASK_STOP },
};
USB_ClassInfo_MS_t Disk_MS_Interface =
{
.InterfaceNumber = 0,
/* Global Variables */
/** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */
CommandBlockWrapper_t CommandBlock;
.DataINEndpointNumber = MASS_STORAGE_IN_EPNUM,
.DataINEndpointSize = MASS_STORAGE_IO_EPSIZE,
/** Structure to hold the latest Command Status Wrapper to return to the host, containing the status of the last issued command. */
CommandStatusWrapper_t CommandStatus = { .Signature = CSW_SIGNATURE };
.DataOUTEndpointNumber = MASS_STORAGE_OUT_EPNUM,
.DataOUTEndpointSize = MASS_STORAGE_IO_EPSIZE,
/** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */
volatile bool IsMassStoreReset = false;
.TotalLUNs = TOTAL_LUNS,
};
/** Main program entry point. This routine configures the hardware required by the application, then
* starts the scheduler to run the application tasks.
*/
int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
for (;;)
{
USB_MS_USBTask(&Disk_MS_Interface);
USB_USBTask();
}
}
void SetupHardware(void)
{
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF);
@ -68,303 +68,42 @@ int main(void)
/* Hardware Initialization */
LEDs_Init();
Dataflash_Init(SPI_SPEED_FCPU_DIV_2);
USB_Init();
/* Clear Dataflash sector protections, if enabled */
DataflashManager_ResetDataflashProtections();
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
/* Initialize Scheduler so that it can be used */
Scheduler_Init();
/* Initialize USB Subsystem */
USB_Init();
/* Scheduling - routine never returns, so put this last in the main function */
Scheduler_Start();
}
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */
void EVENT_USB_Connect(void)
{
/* Indicate USB enumerating */
UpdateStatus(Status_USBEnumerating);
/* Reset the MSReset flag upon connection */
IsMassStoreReset = false;
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
}
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
* the status LEDs and stops the Mass Storage management task.
*/
void EVENT_USB_Disconnect(void)
{
/* Stop running mass storage task */
Scheduler_SetTaskMode(USB_MassStorage, TASK_STOP);
/* Indicate USB not ready */
UpdateStatus(Status_USBNotReady);
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
* of the USB device after enumeration - the device endpoints are configured and the Mass Storage management task started.
*/
void EVENT_USB_ConfigurationChanged(void)
{
/* Setup Mass Storage In and Out Endpoints */
Endpoint_ConfigureEndpoint(MASS_STORAGE_IN_EPNUM, EP_TYPE_BULK,
ENDPOINT_DIR_IN, MASS_STORAGE_IO_EPSIZE,
ENDPOINT_BANK_DOUBLE);
LEDs_SetAllLEDs(LEDMASK_USB_READY);
Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPNUM, EP_TYPE_BULK,
ENDPOINT_DIR_OUT, MASS_STORAGE_IO_EPSIZE,
ENDPOINT_BANK_DOUBLE);
/* Indicate USB connected and ready */
UpdateStatus(Status_USBReady);
/* Start mass storage task */
Scheduler_SetTaskMode(USB_MassStorage, TASK_RUN);
if (!(USB_MS_ConfigureEndpoints(&Disk_MS_Interface)))
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
}
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
* control requests that are not handled internally by the USB library (including the Mass Storage class-specific
* requests) so that they can be handled appropriately for the application.
*/
void EVENT_USB_UnhandledControlPacket(void)
{
/* Process UFI specific control requests */
switch (USB_ControlRequest.bRequest)
{
case REQ_MassStorageReset:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
/* Indicate that the current transfer should be aborted */
IsMassStoreReset = true;
/* Acknowledge status stage */
while (!(Endpoint_IsINReady()));
Endpoint_ClearIN();
}
break;
case REQ_GetMaxLUN:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
/* Indicate to the host the number of supported LUNs (virtual disks) on the device */
Endpoint_Write_Byte(TOTAL_LUNS - 1);
Endpoint_ClearIN();
/* Acknowledge status stage */
while (!(Endpoint_IsOUTReceived()));
Endpoint_ClearOUT();
}
break;
}
USB_MS_ProcessControlPacket(&Disk_MS_Interface);
}
/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
* log to a serial port, or anything else that is suitable for status updates.
*
* \param CurrentStatus Current status of the system, from the MassStorage_StatusCodes_t enum
*/
void UpdateStatus(uint8_t CurrentStatus)
bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo)
{
uint8_t LEDMask = LEDS_NO_LEDS;
bool CommandSuccess;
/* Set the LED mask to the appropriate LED mask based on the given status code */
switch (CurrentStatus)
{
case Status_USBNotReady:
LEDMask = (LEDS_LED1);
break;
case Status_USBEnumerating:
LEDMask = (LEDS_LED1 | LEDS_LED2);
break;
case Status_USBReady:
LEDMask = (LEDS_LED2 | LEDS_LED4);
break;
case Status_CommandBlockError:
LEDMask = (LEDS_LED1);
break;
case Status_ProcessingCommandBlock:
LEDMask = (LEDS_LED1 | LEDS_LED2);
break;
}
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
LEDs_SetAllLEDs(LEDMASK_USB_READY);
/* Set the board LEDs to the new LED mask */
LEDs_SetAllLEDs(LEDMask);
}
/** Task to manage the Mass Storage interface, reading in Command Block Wrappers from the host, processing the SCSI commands they
* contain, and returning Command Status Wrappers back to the host to indicate the success or failure of the last issued command.
*/
TASK(USB_MassStorage)
{
/* Check if the USB System is connected to a Host */
if (USB_IsConnected)
{
/* Select the Data Out Endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
/* Check to see if a command from the host has been issued */
if (Endpoint_IsReadWriteAllowed())
{
/* Indicate busy */
UpdateStatus(Status_ProcessingCommandBlock);
/* Process sent command block from the host */
if (ReadInCommandBlock())
{
/* Check direction of command, select Data IN endpoint if data is from the device */
if (CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN)
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
/* Decode the received SCSI command */
SCSI_DecodeSCSICommand();
/* Load in the CBW tag into the CSW to link them together */
CommandStatus.Tag = CommandBlock.Tag;
/* Load in the data residue counter into the CSW */
CommandStatus.DataTransferResidue = CommandBlock.DataTransferLength;
/* Stall the selected data pipe if command failed (if data is still to be transferred) */
if ((CommandStatus.Status == Command_Fail) && (CommandStatus.DataTransferResidue))
Endpoint_StallTransaction();
/* Return command status block to the host */
ReturnCommandStatus();
/* Check if a Mass Storage Reset occurred */
if (IsMassStoreReset)
{
/* Reset the data endpoint banks */
Endpoint_ResetFIFO(MASS_STORAGE_OUT_EPNUM);
Endpoint_ResetFIFO(MASS_STORAGE_IN_EPNUM);
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
Endpoint_ClearStall();
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
Endpoint_ClearStall();
/* Clear the abort transfer flag */
IsMassStoreReset = false;
}
/* Indicate ready */
UpdateStatus(Status_USBReady);
}
else
{
/* Indicate error reading in the command block from the host */
UpdateStatus(Status_CommandBlockError);
}
}
}
}
/** Function to read in a command block from the host, via the bulk data OUT endpoint. This function reads in the next command block
* if one has been issued, and performs validation to ensure that the block command is valid.
*
* \return Boolean true if a valid command block has been read in from the endpoint, false otherwise
*/
static bool ReadInCommandBlock(void)
{
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
/* Read in command block header */
Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)),
StreamCallback_AbortOnMassStoreReset);
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
/* Verify the command block - abort if invalid */
if ((CommandBlock.Signature != CBW_SIGNATURE) ||
(CommandBlock.LUN >= TOTAL_LUNS) ||
(CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH))
{
/* Stall both data pipes until reset by host */
Endpoint_StallTransaction();
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
Endpoint_StallTransaction();
return false;
}
/* Read in command block command data */
Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData,
CommandBlock.SCSICommandLength,
StreamCallback_AbortOnMassStoreReset);
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
return true;
}
/** Returns the filled Command Status Wrapper back to the host via the bulk data IN endpoint, waiting for the host to clear any
* stalled data endpoints as needed.
*/
static void ReturnCommandStatus(void)
{
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
while (Endpoint_IsStalled())
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Select the Data In endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
while (Endpoint_IsStalled())
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Write the CSW to the endpoint */
Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus),
StreamCallback_AbortOnMassStoreReset);
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
}
/** Stream callback function for the Endpoint stream read and write functions. This callback will abort the current stream transfer
* if a Mass Storage Reset request has been issued to the control endpoint.
*/
uint8_t StreamCallback_AbortOnMassStoreReset(void)
{
/* Abort if a Mass Storage reset command was received */
if (IsMassStoreReset)
return STREAMCALLBACK_Abort;
/* Continue with the current stream operation */
return STREAMCALLBACK_Continue;
return CommandSuccess;
}

View file

@ -46,104 +46,33 @@
#include "Lib/SCSI.h"
#include "Lib/DataflashManager.h"
#include <LUFA/Version.h> // Library Version Information
#include <LUFA/Drivers/USB/USB.h> // USB Functionality
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
#include <LUFA/Drivers/Board/Dataflash.h> // Dataflash chip driver
#include <LUFA/Scheduler/Scheduler.h> // Simple scheduler for task management
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/Joystick.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Buttons.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/USB/Class/Device/MassStorage.h>
/* Macros: */
/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */
#define REQ_MassStorageReset 0xFF
/** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */
#define REQ_GetMaxLUN 0xFE
/** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */
#define MAX_SCSI_COMMAND_LENGTH 16
#define LEDMASK_USB_NOTREADY LEDS_LED1
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
#define LEDMASK_USB_BUSY LEDS_LED2
/** Total number of Logical Units (drives) in the device. The total device capacity is shared equally between
* each drive - this can be set to any positive non-zero amount.
*/
#define TOTAL_LUNS 2
#define TOTAL_LUNS 2
/** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
#define LUN_MEDIA_BLOCKS (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */
#define CBW_SIGNATURE 0x43425355UL
/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */
#define CSW_SIGNATURE 0x53425355UL
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */
#define COMMAND_DIRECTION_DATA_OUT (0 << 7)
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */
#define COMMAND_DIRECTION_DATA_IN (1 << 7)
/* Type defines: */
/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
typedef struct
{
uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */
uint8_t Flags; /**< Command block flags, indicating command data direction */
uint8_t LUN; /**< Logical Unit number this command is issued to */
uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */
uint8_t SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */
} CommandBlockWrapper_t;
/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
typedef struct
{
uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */
uint8_t Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */
} CommandStatusWrapper_t;
/* Enums: */
/** Enum for the possible command status wrapper return status codes. */
enum MassStorage_CommandStatusCodes_t
{
Command_Pass = 0, /**< Command completed with no error */
Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */
Phase_Error = 2 /**< Command failed due to being invalid in the current phase */
};
/** Enum for the possible status codes for passing to the UpdateStatus() function. */
enum MassStorage_StatusCodes_t
{
Status_USBNotReady = 0, /**< USB is not ready (disconnected from a USB host) */
Status_USBEnumerating = 1, /**< USB interface is enumerating */
Status_USBReady = 2, /**< USB interface is connected and ready */
Status_CommandBlockError = 3, /**< Processing a SCSI command block from the host */
Status_ProcessingCommandBlock = 4, /**< Error during the processing of a SCSI command block from the host */
};
/* Global Variables: */
extern CommandBlockWrapper_t CommandBlock;
extern CommandStatusWrapper_t CommandStatus;
extern volatile bool IsMassStoreReset;
/* Task Definitions: */
TASK(USB_MassStorage);
#define LUN_MEDIA_BLOCKS (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
/* Function Prototypes: */
void SetupHardware(void);
void EVENT_USB_Connect(void);
void EVENT_USB_Disconnect(void);
void EVENT_USB_ConfigurationChanged(void);
void EVENT_USB_UnhandledControlPacket(void);
void UpdateStatus(uint8_t CurrentStatus);
#if defined(INCLUDE_FROM_MASSSTORAGE_C)
static bool ReadInCommandBlock(void);
static void ReturnCommandStatus(void);
#endif
uint8_t StreamCallback_AbortOnMassStoreReset(void);
bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo);
#endif

View file

@ -127,7 +127,6 @@ SRC = $(TARGET).c \
Descriptors.c \
Lib/SCSI.c \
Lib/DataflashManager.c \
$(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
@ -138,7 +137,7 @@ SRC = $(TARGET).c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBInterrupt.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/USBTask.c \
$(LUFA_PATH)/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/HIDParser.c \
$(LUFA_PATH)/LUFA/Drivers/USB/Class/Device/MassStorage.c \
# List C++ source files here. (C dependencies are automatically generated.)
@ -188,7 +187,6 @@ CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD)
CDEFS += -DUSE_NONSTANDARD_DESCRIPTOR_NAMES -DUSB_DEVICE_ONLY
CDEFS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 -DUSE_SINGLE_DEVICE_CONFIGURATION
CDEFS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
CDEFS += -DINTERRUPT_CONTROL_ENDPOINT
# Place -D or -U options here for ASM sources