X-Git-Url: http://git.linex4red.de/pub/lufa.git/blobdiff_plain/e5e7eaee7af719cee00a8c2cb6fb4649dde0aa05..d37d419ffa419911d0488f50f65a77b1f8ecacce:/Demos/Device/MassStorage/MassStorage.c diff --git a/Demos/Device/MassStorage/MassStorage.c b/Demos/Device/MassStorage/MassStorage.c index 8c7db9322..5dbc4a2cc 100644 --- a/Demos/Device/MassStorage/MassStorage.c +++ b/Demos/Device/MassStorage/MassStorage.c @@ -30,34 +30,48 @@ /** \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. + * Main source file for the MassStorage 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 }, -}; +/** LUFA Mass Storage Class driver interface configuration and state information. This structure is + * passed to all Mass Storage Class driver functions, so that multiple instances of the same class + * within a device can be differentiated from one another. + */ +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. +/** Main program entry point. This routine contains the overall program flow, including initial + * setup of all components and the main program loop. */ int main(void) { + SetupHardware(); + + LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); + + for (;;) + { + USB_MS_USBTask(&Disk_MS_Interface); + USB_USBTask(); + } +} + +/** Configures the board hardware and chip peripherals for the demo's functionality. */ +void SetupHardware(void) +{ /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); @@ -68,332 +82,50 @@ 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_Reset event. This fires when the USB interface is reset by the USB host, before the - * enumeration process begins, and enables the control endpoint interrupt so that control requests can be handled - * asynchronously when they arrive rather than when the control endpoint is polled manually. - */ -EVENT_HANDLER(USB_Reset) +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Connect(void) { - /* Select the control endpoint */ - Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP); - - /* Enable the endpoint SETUP interrupt ISR for the control endpoint */ - USB_INT_Enable(ENDPOINT_INT_SETUP); -} - -/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */ -EVENT_HANDLER(USB_Connect) -{ - /* 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. - */ -EVENT_HANDLER(USB_Disconnect) +/** Event handler for the library USB Disconnection event. */ +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. - */ -EVENT_HANDLER(USB_ConfigurationChanged) +/** Event handler for the library USB Configuration Changed event. */ +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. - */ -EVENT_HANDLER(USB_UnhandledControlPacket) +/** Event handler for the library USB Unhandled Control Packet event. */ +void EVENT_USB_UnhandledControlPacket(void) { - /* Process UFI specific control requests */ - switch (bRequest) - { - case REQ_MassStorageReset: - if (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 (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. +/** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed. * - * \param CurrentStatus Current status of the system, from the MassStorage_StatusCodes_t enum + * \param MSInterfaceInfo Pointer to the Mass Storage class interface configuration structure being referenced */ -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); - - /* 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)), - 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, - 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), - 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. - */ -STREAM_CALLBACK(AbortOnMassStoreReset) -{ - /* Abort if a Mass Storage reset command was received */ - if (IsMassStoreReset) - return STREAMCALLBACK_Abort; - - /* Continue with the current stream operation */ - return STREAMCALLBACK_Continue; -} - -/** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when a control request has been issued to the control endpoint, - * so that the request can be processed. As several elements of the Mass Storage implementation require asynchronous control requests - * (such as endpoint stall clearing and Mass Storage Reset requests during data transfers) this is done via interrupts rather than - * polling so that they can be processed regardless of the rest of the application's state. - */ -ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) -{ - /* Check if the control endpoint has received a request */ - if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) - { - /* Clear the endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP); - - /* Process the control request */ - USB_USBTask(); - - /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ - USB_INT_Clear(ENDPOINT_INT_SETUP); - } + return CommandSuccess; }