/*
LUFA Library
- Copyright (C) Dean Camera, 2010.
-
+ Copyright (C) Dean Camera, 2011.
+
dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
+ www.lufa-lib.org
*/
/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+ Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
- Permission to use, copy, modify, distribute, and sell this
+ Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
+ without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
- permission notice and warranty disclaimer appear in supporting
- documentation, and that the name of the author not be used in
- advertising or publicity pertaining to distribution of the
+ permission notice and warranty disclaimer appear in supporting
+ documentation, and that the name of the author not be used in
+ advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
#include "MassStorage.h"
/** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */
-CommandBlockWrapper_t CommandBlock;
+MS_CommandBlockWrapper_t CommandBlock;
/** 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 };
+MS_CommandStatusWrapper_t CommandStatus = { .Signature = MS_CSW_SIGNATURE };
/** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */
-volatile bool IsMassStoreReset = false;
+volatile bool IsMassStoreReset = false;
/** Main program entry point. This routine configures the hardware required by the application, then
int main(void)
{
SetupHardware();
-
+
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
sei();
/* Hardware Initialization */
LEDs_Init();
- SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_SCK_LEAD_FALLING | SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);
+ SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_ORDER_MSB_FIRST | SPI_SCK_LEAD_FALLING | SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);
Dataflash_Init();
USB_Init();
{
/* Indicate USB enumerating */
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
-
+
/* Reset the MSReset flag upon connection */
IsMassStoreReset = false;
}
*/
void EVENT_USB_Device_ConfigurationChanged(void)
{
- /* Indicate USB connected and ready */
- LEDs_SetAllLEDs(LEDMASK_USB_READY);
+ bool ConfigSuccess = true;
- /* Setup Mass Storage In and Out Endpoints */
- if (!(Endpoint_ConfigureEndpoint(MASS_STORAGE_IN_EPNUM, EP_TYPE_BULK,
- ENDPOINT_DIR_IN, MASS_STORAGE_IO_EPSIZE,
- ENDPOINT_BANK_SINGLE)))
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- }
-
- if (!(Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPNUM, EP_TYPE_BULK,
- ENDPOINT_DIR_OUT, MASS_STORAGE_IO_EPSIZE,
- ENDPOINT_BANK_SINGLE)))
- {
- LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
- }
+ /* Setup Mass Storage Data Endpoints */
+ ConfigSuccess &= Endpoint_ConfigureEndpoint(MASS_STORAGE_IN_EPNUM, EP_TYPE_BULK, ENDPOINT_DIR_IN,
+ MASS_STORAGE_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
+ ConfigSuccess &= Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPNUM, EP_TYPE_BULK, ENDPOINT_DIR_OUT,
+ MASS_STORAGE_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
+
+ /* Indicate endpoint configuration success or failure */
+ LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : 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.
+/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
+ * the device from the USB host before passing along unhandled control requests to the library for processing
+ * internally.
*/
-void EVENT_USB_Device_UnhandledControlRequest(void)
+void EVENT_USB_Device_ControlRequest(void)
{
/* Process UFI specific control requests */
switch (USB_ControlRequest.bRequest)
{
- case REQ_MassStorageReset:
+ case MS_REQ_MassStorageReset:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
/* Indicate that the current transfer should be aborted */
IsMassStoreReset = true;
-
- Endpoint_ClearStatusStage();
}
break;
- case REQ_GetMaxLUN:
+ case MS_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_Write_8(TOTAL_LUNS - 1);
+
Endpoint_ClearIN();
-
Endpoint_ClearStatusStage();
}
-
+
break;
}
}
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
/* Check direction of command, select Data IN endpoint if data is from the device */
- if (CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN)
+ if (CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN)
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM);
/* Decode the received SCSI command, set returned status code */
- CommandStatus.Status = SCSI_DecodeSCSICommand() ? Command_Pass : Command_Fail;
+ CommandStatus.Status = SCSI_DecodeSCSICommand() ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail;
/* 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))
+ if ((CommandStatus.Status == MS_SCSI_COMMAND_Fail) && (CommandStatus.DataTransferResidue))
Endpoint_StallTransaction();
/* Return command status block to the host */
if (IsMassStoreReset)
{
/* Reset the data endpoint banks */
- Endpoint_ResetFIFO(MASS_STORAGE_OUT_EPNUM);
- Endpoint_ResetFIFO(MASS_STORAGE_IN_EPNUM);
-
+ Endpoint_ResetEndpoint(MASS_STORAGE_OUT_EPNUM);
+ Endpoint_ResetEndpoint(MASS_STORAGE_IN_EPNUM);
+
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
Endpoint_ClearStall();
Endpoint_ResetDataToggle();
*/
static bool ReadInCommandBlock(void)
{
+ uint16_t BytesTransferred;
+
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
-
+
/* Abort if no command has been sent from the host */
if (!(Endpoint_IsOUTReceived()))
return false;
/* 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;
+ BytesTransferred = 0;
+ while (Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)),
+ &BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
+ {
+ /* 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.Flags & 0x1F) ||
- (CommandBlock.SCSICommandLength == 0) ||
- (CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH))
+ if ((CommandBlock.Signature != MS_CBW_SIGNATURE) ||
+ (CommandBlock.LUN >= TOTAL_LUNS) ||
+ (CommandBlock.Flags & 0x1F) ||
+ (CommandBlock.SCSICommandLength == 0) ||
+ (CommandBlock.SCSICommandLength > sizeof(CommandBlock.SCSICommandData)))
{
/* 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;
+ BytesTransferred = 0;
+ while (Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData, CommandBlock.SCSICommandLength,
+ &BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
+ {
+ /* 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;
}
*/
static void ReturnCommandStatus(void)
{
+ uint16_t BytesTransferred;
+
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM);
if (IsMassStoreReset)
return;
}
-
+
/* Write the CSW to the endpoint */
- Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus),
- StreamCallback_AbortOnMassStoreReset);
+ BytesTransferred = 0;
+ while (Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus),
+ &BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
+ {
+ /* Check if the current command is being aborted by the host */
+ if (IsMassStoreReset)
+ return;
+ }
- /* 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;
-}