From b7ef7f49c9f6b4de962ae32776866bd1d5d59c3b Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Fri, 22 May 2009 06:17:57 +0000 Subject: Moved out each demos' functionality library files (e.g. Ring Buffer library) to /Lib directories for a better directory structure. --- Demos/Host/MassStorageHost/Lib/MassStoreCommands.c | 685 +++++++++++++++++++++ Demos/Host/MassStorageHost/Lib/MassStoreCommands.h | 175 ++++++ Demos/Host/MassStorageHost/Lib/SCSI_Codes.h | 85 +++ Demos/Host/MassStorageHost/MassStorageHost.h | 3 +- Demos/Host/MassStorageHost/MassStoreCommands.c | 685 --------------------- Demos/Host/MassStorageHost/MassStoreCommands.h | 175 ------ Demos/Host/MassStorageHost/SCSI_Codes.h | 85 --- Demos/Host/MassStorageHost/makefile | 2 +- 8 files changed, 948 insertions(+), 947 deletions(-) create mode 100644 Demos/Host/MassStorageHost/Lib/MassStoreCommands.c create mode 100644 Demos/Host/MassStorageHost/Lib/MassStoreCommands.h create mode 100644 Demos/Host/MassStorageHost/Lib/SCSI_Codes.h delete mode 100644 Demos/Host/MassStorageHost/MassStoreCommands.c delete mode 100644 Demos/Host/MassStorageHost/MassStoreCommands.h delete mode 100644 Demos/Host/MassStorageHost/SCSI_Codes.h (limited to 'Demos/Host/MassStorageHost') diff --git a/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c new file mode 100644 index 000000000..95aafca8c --- /dev/null +++ b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.c @@ -0,0 +1,685 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, 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 + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Mass Storage Device commands, to issue MSD commands to the device for + * reading device status, capacity, and other characteristics. This file + * also contains block read and write functions, so that device blocks + * can be read and written. In general, these functions would be chained + * to a FAT library to give file-level access to an attached device's contents. + * + * \note Many Mass Storage devices on the market are non-compliant to the + * specifications and thus can prove difficult to interface with. It + * may be necessary to retry the functions in the module several times + * after they have returned and error to successfully send the command + * to the device. Some devices may also need to have the stream function + * timeout period extended beyond 100ms (some badly designed devices exceeding + * 1.5 seconds occasionally) by defining USB_STREAM_TIMEOUT_MS to a + * larger value in the project makefile and passing it to the compiler + * via the -D switch. + */ + +#define INCLUDE_FROM_MASSSTORE_COMMANDS_C +#include "MassStoreCommands.h" + +/* Globals: */ +/** Current CBW to send to the device. This is automatically filled by the routines + * in this file and is not externally accessible. + */ +static CommandBlockWrapper_t SCSICommandBlock; + +/** Current CSW received from the device. This is automatically filled by the routines + * in this file and is externally accessible so that the return codes may be checked. + */ +CommandStatusWrapper_t SCSICommandStatus; + +/** Current Tag value used in issued CBWs to the device. This is automatically incremented + * by the routines in this file, and is not externally accessible. + */ +static uint32_t MassStore_Tag = 1; + + +/** Routine to send the current CBW to the device, and increment the Tag value as needed. + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +static uint8_t MassStore_SendCommand(void) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + + /* Each transmission should have a unique tag value, excluding values 0 and 0xFFFFFFFF */ + if (++MassStore_Tag == 0xFFFFFFFF) + MassStore_Tag = 1; + + /* Select the OUT data pipe for CBW transmission */ + Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); + Pipe_Unfreeze(); + + /* Write the CBW command to the OUT pipe */ + if ((ErrorCode = Pipe_Write_Stream_LE(&SCSICommandBlock, sizeof(CommandBlockWrapper_t))) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + /* Send the data in the OUT pipe to the attached device */ + Pipe_ClearOUT(); + + while(!(Pipe_IsOUTReady())); + + /* Freeze pipe after use */ + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +/** Waits until the attached device is ready to accept data following a CBW, checking + * to ensure that the device has not stalled the transaction. + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +static uint8_t MassStore_WaitForDataReceived(void) +{ + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + + /* Unfreeze the OUT pipe so that it can be checked */ + Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); + Pipe_Unfreeze(); + + /* Select the IN data pipe for data reception */ + Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); + Pipe_Unfreeze(); + + /* Wait until data received in the IN pipe */ + while (!(Pipe_IsINReceived())) + { + /* Check to see if a new frame has been issued (1ms elapsed) */ + if (USB_INT_HasOccurred(USB_INT_HSOFI)) + { + /* Clear the flag and decrement the timeout period counter */ + USB_INT_Clear(USB_INT_HSOFI); + TimeoutMSRem--; + + /* Check to see if the timeout period for the command has elapsed */ + if (!(TimeoutMSRem)) + return PIPE_RWSTREAM_Timeout; + } + + Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); + + /* Check if pipe stalled (command failed by device) */ + if (Pipe_IsStalled()) + { + /* Clear the stall condition on the OUT pipe */ + MassStore_ClearPipeStall(MASS_STORE_DATA_OUT_PIPE); + + return PIPE_RWSTREAM_PipeStalled; + } + + Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); + + /* Check if pipe stalled (command failed by device) */ + if (Pipe_IsStalled()) + { + /* Clear the stall condition on the IN pipe */ + MassStore_ClearPipeStall(MASS_STORE_DATA_IN_PIPE); + + return PIPE_RWSTREAM_PipeStalled; + } + + /* Check to see if the device was disconnected, if so exit function */ + if (!(USB_IsConnected)) + return PIPE_RWSTREAM_DeviceDisconnected; + }; + + return PIPE_RWSTREAM_NoError; +} + +/** Sends or receives the transaction's data stage to or from the attached device, reading or + * writing to the nominated buffer. + * + * \param BufferPtr Pointer to the data buffer to read from or write to + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +static uint8_t MassStore_SendReceiveData(void* BufferPtr) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + uint16_t BytesRem = SCSICommandBlock.Header.DataTransferLength; + + /* Check the direction of the SCSI command data stage */ + if (SCSICommandBlock.Header.Flags & COMMAND_DIRECTION_DATA_IN) + { + /* Select the IN data pipe for data reception */ + Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); + Pipe_Unfreeze(); + + /* Read in the block data from the pipe */ + if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + /* Acknowledge the packet */ + Pipe_ClearIN(); + } + else + { + /* Select the OUT data pipe for data transmission */ + Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); + Pipe_Unfreeze(); + + /* Write the block data to the pipe */ + if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + /* Acknowledge the packet */ + Pipe_ClearOUT(); + + while (!(Pipe_IsOUTReady())); + } + + /* Freeze used pipe after use */ + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +/** Routine to receive the current CSW from the device. + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +static uint8_t MassStore_GetReturnedStatus(void) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + + /* If an error in the command ocurred, abort */ + if ((ErrorCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + /* Select the IN data pipe for data reception */ + Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); + Pipe_Unfreeze(); + + /* Load in the CSW from the attached device */ + if ((ErrorCode = Pipe_Read_Stream_LE(&SCSICommandStatus, sizeof(CommandStatusWrapper_t))) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + /* Clear the data ready for next reception */ + Pipe_ClearIN(); + + /* Freeze the IN pipe after use */ + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +/** Clears the stall condition in the attached device on the nominated endpoint number. + * + * \param EndpointNum Endpoint number in the attached device whose stall condition is to be cleared + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum + */ +uint8_t MassStore_ClearPipeStall(const uint8_t EndpointNum) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT), + .bRequest = REQ_ClearFeature, + .wValue = FEATURE_ENDPOINT_HALT, + .wIndex = EndpointNum, + .wLength = 0, + }; + + /* Select the control pipe for the request transfer */ + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +/** Issues a Mass Storage class specific request to reset the attached device's Mass Storage interface, + * readying the device for the next CBW. + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum + */ +uint8_t MassStore_MassStorageReset(void) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_MassStorageReset, + .wValue = 0, + .wIndex = 0, + .wLength = 0, + }; + + /* Select the control pipe for the request transfer */ + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +/** Issues a Mass Storage class specific request to determine the index of the highest numbered Logical + * Unit in the attached device. + * + * \param MaxLUNIndex Pointer to the location that the maximum LUN index value should be stored + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum + */ +uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex) +{ + uint8_t ErrorCode; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_GetMaxLUN, + .wValue = 0, + .wIndex = 0, + .wLength = 1, + }; + + /* Select the control pipe for the request transfer */ + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled) + { + /* Clear the pipe stall */ + Pipe_ClearStall(); + + /* Some faulty Mass Storage devices don't implement the GET_MAX_LUN request, so assume a single LUN */ + *MaxLUNIndex = 0; + } + + return ErrorCode; +} + +/** Issues a SCSI Request Sense command to the attached device, to determine the current SCSI sense information. This + * gives error codes for the last issued SCSI command to the device. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * \param SensePtr Pointer to the sense data structure where the sense data from the device is to be stored + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to issue REQUEST SENSE command */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 6 + }, + + .SCSICommandData = + { + SCSI_CMD_REQUEST_SENSE, + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + sizeof(SCSI_Request_Sense_Response_t), // Allocation Length + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Wait until data received from the device */ + if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read the returned sense data into the buffer */ + if ((ReturnCode = MassStore_SendReceiveData((uint8_t*)SensePtr)) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} + +/** Issues a SCSI Device Block Read command to the attached device, to read in one or more data blocks from the + * storage medium into a buffer. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * \param BlockAddress Start block address to read from + * \param Blocks Number of blocks to read from the device + * \param BlockSize Size in bytes of each block to read + * \param BufferPtr Pointer to the buffer where the read data is to be written to + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to read in the given blocks from the device */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = ((uint32_t)Blocks * BlockSize), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 10 + }, + + .SCSICommandData = + { + SCSI_CMD_READ_10, + 0x00, // Unused (control bits, all off) + (BlockAddress >> 24), // MSB of Block Address + (BlockAddress >> 16), + (BlockAddress >> 8), + (BlockAddress & 0xFF), // LSB of Block Address + 0x00, // Unused (reserved) + 0x00, // MSB of Total Blocks to Read + Blocks, // LSB of Total Blocks to Read + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Wait until data received from the device */ + if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read the returned block data into the buffer */ + if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} + +/** Issues a SCSI Device Block Write command to the attached device, to write one or more data blocks to the + * storage medium from a buffer. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * \param BlockAddress Start block address to write to + * \param Blocks Number of blocks to write to in the device + * \param BlockSize Size in bytes of each block to write + * \param BufferPtr Pointer to the buffer where the write data is to be sourced from + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to write the given blocks to the device */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = ((uint32_t)Blocks * BlockSize), + .Flags = COMMAND_DIRECTION_DATA_OUT, + .LUN = LUNIndex, + .SCSICommandLength = 10 + }, + + .SCSICommandData = + { + SCSI_CMD_WRITE_10, + 0x00, // Unused (control bits, all off) + (BlockAddress >> 24), // MSB of Block Address + (BlockAddress >> 16), + (BlockAddress >> 8), + (BlockAddress & 0xFF), // LSB of Block Address + 0x00, // Unused (reserved) + 0x00, // MSB of Total Blocks to Write + Blocks, // LSB of Total Blocks to Write + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Write the data to the device from the buffer */ + if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} + +/** Issues a SCSI Device Test Unit Ready command to the attached device, to determine if the device is ready to accept + * other commands. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to issue TEST UNIT READY command */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = 0, + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 6 + }, + + .SCSICommandData = + { + SCSI_CMD_TEST_UNIT_READY, + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} + +/** Issues a SCSI Device Read Capacity command to the attached device, to determine the capacity of the + * given Logical Unit within the device. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * \param CapacityPtr Device capacity structure where the capacity data is to be stored + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const CapacityPtr) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to issue READ CAPACITY command */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = sizeof(SCSI_Capacity_t), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 10 + }, + + .SCSICommandData = + { + SCSI_CMD_READ_CAPACITY_10, + 0x00, // Reserved + 0x00, // MSB of Logical block address + 0x00, + 0x00, + 0x00, // LSB of Logical block address + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Partial Medium Indicator + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Wait until data received from the device */ + if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Read the returned capacity data into the buffer */ + if ((ReturnCode = MassStore_SendReceiveData(CapacityPtr)) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + /* Endian-correct the read data */ + CapacityPtr->Blocks = SwapEndian_32(CapacityPtr->Blocks); + CapacityPtr->BlockSize = SwapEndian_32(CapacityPtr->BlockSize); + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} + +/** Issues a SCSI Device Prevent/Allow Medium Removal command to the attached device, to lock the physical media from + * being removed. This is a legacy command for SCSI disks with removable storage (such as ZIP disks), but should still + * be issued before the first read or write command is sent. + * + * \param LUNIndex Index of the LUN inside the device the command is being addressed to + * \param PreventRemoval Whether or not the LUN media should be locked to prevent removal or not + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ +uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool PreventRemoval) +{ + uint8_t ReturnCode = PIPE_RWSTREAM_NoError; + + /* Create a CBW with a SCSI command to issue PREVENT ALLOW MEDIUM REMOVAL command */ + SCSICommandBlock = (CommandBlockWrapper_t) + { + .Header = + { + .Signature = CBW_SIGNATURE, + .Tag = MassStore_Tag, + .DataTransferLength = 0, + .Flags = COMMAND_DIRECTION_DATA_OUT, + .LUN = LUNIndex, + .SCSICommandLength = 6 + }, + + .SCSICommandData = + { + SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL, + 0x00, // Reserved + 0x00, // Reserved + PreventRemoval, // Prevent flag + 0x00, // Reserved + 0x00 // Unused (control) + } + }; + + /* Send SCSI command to the attached device */ + MassStore_SendCommand(); + + /* Read in the returned CSW from the device */ + if ((ReturnCode = MassStore_GetReturnedStatus())) + { + Pipe_Freeze(); + return ReturnCode; + } + + return PIPE_RWSTREAM_NoError; +} diff --git a/Demos/Host/MassStorageHost/Lib/MassStoreCommands.h b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.h new file mode 100644 index 000000000..28f6a1561 --- /dev/null +++ b/Demos/Host/MassStorageHost/Lib/MassStoreCommands.h @@ -0,0 +1,175 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, 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 + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for MassStoreCommands.c. + */ + +#ifndef _MASS_STORE_COMMANDS_H_ +#define _MASS_STORE_COMMANDS_H_ + + /* Includes: */ + #include + + #include "MassStorageHost.h" + #include "SCSI_Codes.h" + + #include // USB Functionality + + /* Macros: */ + /** Class specific request to reset the Mass Storage interface of the attached device */ + #define REQ_MassStorageReset 0xFF + + /** Class specific request to retrieve the maximum Logical Unit Number (LUN) index of the attached device */ + #define REQ_GetMaxLUN 0xFE + + /** Command Block Wrapper signature byte, for verification of valid CBW blocks */ + #define CBW_SIGNATURE 0x43425355UL + + /** Command Static Wrapper signature byte, for verification of valid CSW blocks */ + #define CSW_SIGNATURE 0x53425355UL + + /** Data direction mask for the Flags field of a CBW, indicating Host-to-Device transfer direction */ + #define COMMAND_DIRECTION_DATA_OUT (0 << 7) + + /** Data direction mask for the Flags field of a CBW, indicating Device-to-Host transfer direction */ + #define COMMAND_DIRECTION_DATA_IN (1 << 7) + + /** Timeout period between the issuing of a CBW to a device, and the reception of the first packet */ + #define COMMAND_DATA_TIMEOUT_MS 500 + + /** Pipe number of the Mass Storage data IN pipe */ + #define MASS_STORE_DATA_IN_PIPE 1 + + /** Pipe number of the Mass Storage data OUT pipe */ + #define MASS_STORE_DATA_OUT_PIPE 2 + + /* Type defines: */ + /** Type define for a Mass Storage class Command Block Wrapper, used to wrap SCSI + * commands for transport over the USB bulk endpoints to the device. + */ + typedef struct + { + struct + { + uint32_t Signature; /**< Command block signature, always equal to CBW_SIGNATURE */ + uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW */ + uint32_t DataTransferLength; /**< Length of data to transfer, following the CBW */ + uint8_t Flags; /**< Block flags, equal to one of the COMMAND_DIRECTION_DATA_* macros */ + uint8_t LUN; /**< Logical Unit Number the CBW is addressed to in the device */ + uint8_t SCSICommandLength; /**< Length of the SCSI command in the CBW */ + } Header; + + uint8_t SCSICommandData[16]; /**< SCSI command to issue to the device */ + } CommandBlockWrapper_t; + + /** Type define for a Mass Storage class Command Status Wrapper, used to wrap SCSI + * responses for transport over the USB bulk endpoints from the device. + */ + typedef struct + { + uint32_t Signature; /**< Command status signature, always equal to CSW_SIGNATURE */ + uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW */ + uint32_t DataTransferResidue; /**< Length of data not transferred */ + uint8_t Status; /**< Command status, a value from the MassStorageHost_CommandStatusCodes_t enum */ + } CommandStatusWrapper_t; + + /** Type define for a SCSI Sense structure. Structures of this type are filled out by the + * device via the MassStore_RequestSense() function, indicating the current sense data of the + * device (giving explicit error codes for the last issued command). For details of the + * structure contents, refer to the SCSI specifications. + */ + typedef struct + { + uint8_t ReponseCode; + + uint8_t SegmentNumber; + + unsigned char SenseKey : 4; + unsigned char _RESERVED1 : 1; + unsigned char ILI : 1; + unsigned char EOM : 1; + unsigned char FileMark : 1; + + uint8_t Information[4]; + uint8_t AdditionalLength; + uint8_t CmdSpecificInformation[4]; + uint8_t AdditionalSenseCode; + uint8_t AdditionalSenseQualifier; + uint8_t FieldReplaceableUnitCode; + uint8_t SenseKeySpecific[3]; + } SCSI_Request_Sense_Response_t; + + /** SCSI capacity structure, to hold the total capacity of the device in both the number + * of blocks in the current LUN, and the size of each block. This structure is filled by + * the device when the MassStore_ReadCapacity() function is called. + */ + typedef struct + { + uint32_t Blocks; /**< Number of blocks in the addressed LUN of the device */ + uint32_t BlockSize; /**< Number of bytes in each block in the addressed LUN */ + } SCSI_Capacity_t; + + /* Enums: */ + /** CSW status return codes, indicating the overall status of the issued CBW */ + enum MassStorageHost_CommandStatusCodes_t + { + Command_Pass = 0, /**< Command completed successfully */ + Command_Fail = 1, /**< Command failed to complete successfully */ + Phase_Error = 2 /**< Phase error while processing the issued command */ + }; + + /* External Variables: */ + extern CommandStatusWrapper_t SCSICommandStatus; + + /* Function Prototypes: */ + #if defined(INCLUDE_FROM_MASSSTORE_COMMANDS_C) + static uint8_t MassStore_SendCommand(void); + static uint8_t MassStore_WaitForDataReceived(void); + static uint8_t MassStore_SendReceiveData(void* BufferPtr) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t MassStore_GetReturnedStatus(void); + #endif + + uint8_t MassStore_ClearPipeStall(const uint8_t EndpointNum); + uint8_t MassStore_MassStorageReset(void); + uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex); + uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr) + ATTR_NON_NULL_PTR_ARG(2); + uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(5); + uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(5); + uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const CapacityPtr) + ATTR_NON_NULL_PTR_ARG(2); + uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex); + uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool PreventRemoval); + +#endif diff --git a/Demos/Host/MassStorageHost/Lib/SCSI_Codes.h b/Demos/Host/MassStorageHost/Lib/SCSI_Codes.h new file mode 100644 index 000000000..2b2213de2 --- /dev/null +++ b/Demos/Host/MassStorageHost/Lib/SCSI_Codes.h @@ -0,0 +1,85 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, 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 + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header containing macros for possible SCSI commands and SENSE data. Refer to + * the SCSI standard documentation for more information on each SCSI command and + * the SENSE data. + */ + +#ifndef _SCSI_CODES_H_ +#define _SCSI_CODES_H_ + + /* Macros: */ + #define SCSI_CMD_INQUIRY 0x12 + #define SCSI_CMD_REQUEST_SENSE 0x03 + #define SCSI_CMD_TEST_UNIT_READY 0x00 + #define SCSI_CMD_READ_CAPACITY_10 0x25 + #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D + #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E + #define SCSI_CMD_WRITE_10 0x2A + #define SCSI_CMD_READ_10 0x28 + #define SCSI_CMD_WRITE_6 0x0A + #define SCSI_CMD_READ_6 0x08 + #define SCSI_CMD_VERIFY_10 0x2F + #define SCSI_CMD_MODE_SENSE_6 0x1A + #define SCSI_CMD_MODE_SENSE_10 0x5A + + #define SCSI_SENSE_KEY_GOOD 0x00 + #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 + #define SCSI_SENSE_KEY_NOT_READY 0x02 + #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 + #define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 + #define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 + #define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 + #define SCSI_SENSE_KEY_DATA_PROTECT 0x07 + #define SCSI_SENSE_KEY_BLANK_CHECK 0x08 + #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 + #define SCSI_SENSE_KEY_COPY_ABORTED 0x0A + #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B + #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D + #define SCSI_SENSE_KEY_MISCOMPARE 0x0E + + #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 + #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 + #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 + #define SCSI_ASENSE_WRITE_PROTECTED 0x27 + #define SCSI_ASENSE_FORMAT_ERROR 0x31 + #define SCSI_ASENSE_INVALID_COMMAND 0x20 + #define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 + #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A + + #define SCSI_ASENSEQ_NO_QUALIFIER 0x00 + #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 + #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 + #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 + +#endif diff --git a/Demos/Host/MassStorageHost/MassStorageHost.h b/Demos/Host/MassStorageHost/MassStorageHost.h index 1646ad75e..6e1e5cd9e 100644 --- a/Demos/Host/MassStorageHost/MassStorageHost.h +++ b/Demos/Host/MassStorageHost/MassStorageHost.h @@ -45,7 +45,8 @@ #include #include "ConfigDescriptor.h" - #include "MassStoreCommands.h" + + #include "Lib/MassStoreCommands.h" #include // Library Version Information #include // ANSI Terminal Escape Codes diff --git a/Demos/Host/MassStorageHost/MassStoreCommands.c b/Demos/Host/MassStorageHost/MassStoreCommands.c deleted file mode 100644 index 95aafca8c..000000000 --- a/Demos/Host/MassStorageHost/MassStoreCommands.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, 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 - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Mass Storage Device commands, to issue MSD commands to the device for - * reading device status, capacity, and other characteristics. This file - * also contains block read and write functions, so that device blocks - * can be read and written. In general, these functions would be chained - * to a FAT library to give file-level access to an attached device's contents. - * - * \note Many Mass Storage devices on the market are non-compliant to the - * specifications and thus can prove difficult to interface with. It - * may be necessary to retry the functions in the module several times - * after they have returned and error to successfully send the command - * to the device. Some devices may also need to have the stream function - * timeout period extended beyond 100ms (some badly designed devices exceeding - * 1.5 seconds occasionally) by defining USB_STREAM_TIMEOUT_MS to a - * larger value in the project makefile and passing it to the compiler - * via the -D switch. - */ - -#define INCLUDE_FROM_MASSSTORE_COMMANDS_C -#include "MassStoreCommands.h" - -/* Globals: */ -/** Current CBW to send to the device. This is automatically filled by the routines - * in this file and is not externally accessible. - */ -static CommandBlockWrapper_t SCSICommandBlock; - -/** Current CSW received from the device. This is automatically filled by the routines - * in this file and is externally accessible so that the return codes may be checked. - */ -CommandStatusWrapper_t SCSICommandStatus; - -/** Current Tag value used in issued CBWs to the device. This is automatically incremented - * by the routines in this file, and is not externally accessible. - */ -static uint32_t MassStore_Tag = 1; - - -/** Routine to send the current CBW to the device, and increment the Tag value as needed. - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -static uint8_t MassStore_SendCommand(void) -{ - uint8_t ErrorCode = PIPE_RWSTREAM_NoError; - - /* Each transmission should have a unique tag value, excluding values 0 and 0xFFFFFFFF */ - if (++MassStore_Tag == 0xFFFFFFFF) - MassStore_Tag = 1; - - /* Select the OUT data pipe for CBW transmission */ - Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); - Pipe_Unfreeze(); - - /* Write the CBW command to the OUT pipe */ - if ((ErrorCode = Pipe_Write_Stream_LE(&SCSICommandBlock, sizeof(CommandBlockWrapper_t))) != PIPE_RWSTREAM_NoError) - return ErrorCode; - - /* Send the data in the OUT pipe to the attached device */ - Pipe_ClearOUT(); - - while(!(Pipe_IsOUTReady())); - - /* Freeze pipe after use */ - Pipe_Freeze(); - - return PIPE_RWSTREAM_NoError; -} - -/** Waits until the attached device is ready to accept data following a CBW, checking - * to ensure that the device has not stalled the transaction. - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -static uint8_t MassStore_WaitForDataReceived(void) -{ - uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; - - /* Unfreeze the OUT pipe so that it can be checked */ - Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); - Pipe_Unfreeze(); - - /* Select the IN data pipe for data reception */ - Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); - Pipe_Unfreeze(); - - /* Wait until data received in the IN pipe */ - while (!(Pipe_IsINReceived())) - { - /* Check to see if a new frame has been issued (1ms elapsed) */ - if (USB_INT_HasOccurred(USB_INT_HSOFI)) - { - /* Clear the flag and decrement the timeout period counter */ - USB_INT_Clear(USB_INT_HSOFI); - TimeoutMSRem--; - - /* Check to see if the timeout period for the command has elapsed */ - if (!(TimeoutMSRem)) - return PIPE_RWSTREAM_Timeout; - } - - Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); - - /* Check if pipe stalled (command failed by device) */ - if (Pipe_IsStalled()) - { - /* Clear the stall condition on the OUT pipe */ - MassStore_ClearPipeStall(MASS_STORE_DATA_OUT_PIPE); - - return PIPE_RWSTREAM_PipeStalled; - } - - Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); - - /* Check if pipe stalled (command failed by device) */ - if (Pipe_IsStalled()) - { - /* Clear the stall condition on the IN pipe */ - MassStore_ClearPipeStall(MASS_STORE_DATA_IN_PIPE); - - return PIPE_RWSTREAM_PipeStalled; - } - - /* Check to see if the device was disconnected, if so exit function */ - if (!(USB_IsConnected)) - return PIPE_RWSTREAM_DeviceDisconnected; - }; - - return PIPE_RWSTREAM_NoError; -} - -/** Sends or receives the transaction's data stage to or from the attached device, reading or - * writing to the nominated buffer. - * - * \param BufferPtr Pointer to the data buffer to read from or write to - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -static uint8_t MassStore_SendReceiveData(void* BufferPtr) -{ - uint8_t ErrorCode = PIPE_RWSTREAM_NoError; - uint16_t BytesRem = SCSICommandBlock.Header.DataTransferLength; - - /* Check the direction of the SCSI command data stage */ - if (SCSICommandBlock.Header.Flags & COMMAND_DIRECTION_DATA_IN) - { - /* Select the IN data pipe for data reception */ - Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); - Pipe_Unfreeze(); - - /* Read in the block data from the pipe */ - if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError) - return ErrorCode; - - /* Acknowledge the packet */ - Pipe_ClearIN(); - } - else - { - /* Select the OUT data pipe for data transmission */ - Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE); - Pipe_Unfreeze(); - - /* Write the block data to the pipe */ - if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError) - return ErrorCode; - - /* Acknowledge the packet */ - Pipe_ClearOUT(); - - while (!(Pipe_IsOUTReady())); - } - - /* Freeze used pipe after use */ - Pipe_Freeze(); - - return PIPE_RWSTREAM_NoError; -} - -/** Routine to receive the current CSW from the device. - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -static uint8_t MassStore_GetReturnedStatus(void) -{ - uint8_t ErrorCode = PIPE_RWSTREAM_NoError; - - /* If an error in the command ocurred, abort */ - if ((ErrorCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) - return ErrorCode; - - /* Select the IN data pipe for data reception */ - Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); - Pipe_Unfreeze(); - - /* Load in the CSW from the attached device */ - if ((ErrorCode = Pipe_Read_Stream_LE(&SCSICommandStatus, sizeof(CommandStatusWrapper_t))) != PIPE_RWSTREAM_NoError) - return ErrorCode; - - /* Clear the data ready for next reception */ - Pipe_ClearIN(); - - /* Freeze the IN pipe after use */ - Pipe_Freeze(); - - return PIPE_RWSTREAM_NoError; -} - -/** Clears the stall condition in the attached device on the nominated endpoint number. - * - * \param EndpointNum Endpoint number in the attached device whose stall condition is to be cleared - * - * \return A value from the USB_Host_SendControlErrorCodes_t enum - */ -uint8_t MassStore_ClearPipeStall(const uint8_t EndpointNum) -{ - USB_ControlRequest = (USB_Request_Header_t) - { - .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT), - .bRequest = REQ_ClearFeature, - .wValue = FEATURE_ENDPOINT_HALT, - .wIndex = EndpointNum, - .wLength = 0, - }; - - /* Select the control pipe for the request transfer */ - Pipe_SelectPipe(PIPE_CONTROLPIPE); - - return USB_Host_SendControlRequest(NULL); -} - -/** Issues a Mass Storage class specific request to reset the attached device's Mass Storage interface, - * readying the device for the next CBW. - * - * \return A value from the USB_Host_SendControlErrorCodes_t enum - */ -uint8_t MassStore_MassStorageReset(void) -{ - USB_ControlRequest = (USB_Request_Header_t) - { - .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), - .bRequest = REQ_MassStorageReset, - .wValue = 0, - .wIndex = 0, - .wLength = 0, - }; - - /* Select the control pipe for the request transfer */ - Pipe_SelectPipe(PIPE_CONTROLPIPE); - - return USB_Host_SendControlRequest(NULL); -} - -/** Issues a Mass Storage class specific request to determine the index of the highest numbered Logical - * Unit in the attached device. - * - * \param MaxLUNIndex Pointer to the location that the maximum LUN index value should be stored - * - * \return A value from the USB_Host_SendControlErrorCodes_t enum - */ -uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex) -{ - uint8_t ErrorCode; - - USB_ControlRequest = (USB_Request_Header_t) - { - .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), - .bRequest = REQ_GetMaxLUN, - .wValue = 0, - .wIndex = 0, - .wLength = 1, - }; - - /* Select the control pipe for the request transfer */ - Pipe_SelectPipe(PIPE_CONTROLPIPE); - - if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled) - { - /* Clear the pipe stall */ - Pipe_ClearStall(); - - /* Some faulty Mass Storage devices don't implement the GET_MAX_LUN request, so assume a single LUN */ - *MaxLUNIndex = 0; - } - - return ErrorCode; -} - -/** Issues a SCSI Request Sense command to the attached device, to determine the current SCSI sense information. This - * gives error codes for the last issued SCSI command to the device. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * \param SensePtr Pointer to the sense data structure where the sense data from the device is to be stored - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to issue REQUEST SENSE command */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t), - .Flags = COMMAND_DIRECTION_DATA_IN, - .LUN = LUNIndex, - .SCSICommandLength = 6 - }, - - .SCSICommandData = - { - SCSI_CMD_REQUEST_SENSE, - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - sizeof(SCSI_Request_Sense_Response_t), // Allocation Length - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Wait until data received from the device */ - if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read the returned sense data into the buffer */ - if ((ReturnCode = MassStore_SendReceiveData((uint8_t*)SensePtr)) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} - -/** Issues a SCSI Device Block Read command to the attached device, to read in one or more data blocks from the - * storage medium into a buffer. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * \param BlockAddress Start block address to read from - * \param Blocks Number of blocks to read from the device - * \param BlockSize Size in bytes of each block to read - * \param BufferPtr Pointer to the buffer where the read data is to be written to - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, - const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to read in the given blocks from the device */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = ((uint32_t)Blocks * BlockSize), - .Flags = COMMAND_DIRECTION_DATA_IN, - .LUN = LUNIndex, - .SCSICommandLength = 10 - }, - - .SCSICommandData = - { - SCSI_CMD_READ_10, - 0x00, // Unused (control bits, all off) - (BlockAddress >> 24), // MSB of Block Address - (BlockAddress >> 16), - (BlockAddress >> 8), - (BlockAddress & 0xFF), // LSB of Block Address - 0x00, // Unused (reserved) - 0x00, // MSB of Total Blocks to Read - Blocks, // LSB of Total Blocks to Read - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Wait until data received from the device */ - if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read the returned block data into the buffer */ - if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} - -/** Issues a SCSI Device Block Write command to the attached device, to write one or more data blocks to the - * storage medium from a buffer. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * \param BlockAddress Start block address to write to - * \param Blocks Number of blocks to write to in the device - * \param BlockSize Size in bytes of each block to write - * \param BufferPtr Pointer to the buffer where the write data is to be sourced from - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, - const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to write the given blocks to the device */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = ((uint32_t)Blocks * BlockSize), - .Flags = COMMAND_DIRECTION_DATA_OUT, - .LUN = LUNIndex, - .SCSICommandLength = 10 - }, - - .SCSICommandData = - { - SCSI_CMD_WRITE_10, - 0x00, // Unused (control bits, all off) - (BlockAddress >> 24), // MSB of Block Address - (BlockAddress >> 16), - (BlockAddress >> 8), - (BlockAddress & 0xFF), // LSB of Block Address - 0x00, // Unused (reserved) - 0x00, // MSB of Total Blocks to Write - Blocks, // LSB of Total Blocks to Write - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Write the data to the device from the buffer */ - if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} - -/** Issues a SCSI Device Test Unit Ready command to the attached device, to determine if the device is ready to accept - * other commands. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to issue TEST UNIT READY command */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = 0, - .Flags = COMMAND_DIRECTION_DATA_IN, - .LUN = LUNIndex, - .SCSICommandLength = 6 - }, - - .SCSICommandData = - { - SCSI_CMD_TEST_UNIT_READY, - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} - -/** Issues a SCSI Device Read Capacity command to the attached device, to determine the capacity of the - * given Logical Unit within the device. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * \param CapacityPtr Device capacity structure where the capacity data is to be stored - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const CapacityPtr) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to issue READ CAPACITY command */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = sizeof(SCSI_Capacity_t), - .Flags = COMMAND_DIRECTION_DATA_IN, - .LUN = LUNIndex, - .SCSICommandLength = 10 - }, - - .SCSICommandData = - { - SCSI_CMD_READ_CAPACITY_10, - 0x00, // Reserved - 0x00, // MSB of Logical block address - 0x00, - 0x00, - 0x00, // LSB of Logical block address - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Partial Medium Indicator - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Wait until data received from the device */ - if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Read the returned capacity data into the buffer */ - if ((ReturnCode = MassStore_SendReceiveData(CapacityPtr)) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - /* Endian-correct the read data */ - CapacityPtr->Blocks = SwapEndian_32(CapacityPtr->Blocks); - CapacityPtr->BlockSize = SwapEndian_32(CapacityPtr->BlockSize); - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} - -/** Issues a SCSI Device Prevent/Allow Medium Removal command to the attached device, to lock the physical media from - * being removed. This is a legacy command for SCSI disks with removable storage (such as ZIP disks), but should still - * be issued before the first read or write command is sent. - * - * \param LUNIndex Index of the LUN inside the device the command is being addressed to - * \param PreventRemoval Whether or not the LUN media should be locked to prevent removal or not - * - * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum - */ -uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool PreventRemoval) -{ - uint8_t ReturnCode = PIPE_RWSTREAM_NoError; - - /* Create a CBW with a SCSI command to issue PREVENT ALLOW MEDIUM REMOVAL command */ - SCSICommandBlock = (CommandBlockWrapper_t) - { - .Header = - { - .Signature = CBW_SIGNATURE, - .Tag = MassStore_Tag, - .DataTransferLength = 0, - .Flags = COMMAND_DIRECTION_DATA_OUT, - .LUN = LUNIndex, - .SCSICommandLength = 6 - }, - - .SCSICommandData = - { - SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL, - 0x00, // Reserved - 0x00, // Reserved - PreventRemoval, // Prevent flag - 0x00, // Reserved - 0x00 // Unused (control) - } - }; - - /* Send SCSI command to the attached device */ - MassStore_SendCommand(); - - /* Read in the returned CSW from the device */ - if ((ReturnCode = MassStore_GetReturnedStatus())) - { - Pipe_Freeze(); - return ReturnCode; - } - - return PIPE_RWSTREAM_NoError; -} diff --git a/Demos/Host/MassStorageHost/MassStoreCommands.h b/Demos/Host/MassStorageHost/MassStoreCommands.h deleted file mode 100644 index 28f6a1561..000000000 --- a/Demos/Host/MassStorageHost/MassStoreCommands.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, 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 - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Header file for MassStoreCommands.c. - */ - -#ifndef _MASS_STORE_COMMANDS_H_ -#define _MASS_STORE_COMMANDS_H_ - - /* Includes: */ - #include - - #include "MassStorageHost.h" - #include "SCSI_Codes.h" - - #include // USB Functionality - - /* Macros: */ - /** Class specific request to reset the Mass Storage interface of the attached device */ - #define REQ_MassStorageReset 0xFF - - /** Class specific request to retrieve the maximum Logical Unit Number (LUN) index of the attached device */ - #define REQ_GetMaxLUN 0xFE - - /** Command Block Wrapper signature byte, for verification of valid CBW blocks */ - #define CBW_SIGNATURE 0x43425355UL - - /** Command Static Wrapper signature byte, for verification of valid CSW blocks */ - #define CSW_SIGNATURE 0x53425355UL - - /** Data direction mask for the Flags field of a CBW, indicating Host-to-Device transfer direction */ - #define COMMAND_DIRECTION_DATA_OUT (0 << 7) - - /** Data direction mask for the Flags field of a CBW, indicating Device-to-Host transfer direction */ - #define COMMAND_DIRECTION_DATA_IN (1 << 7) - - /** Timeout period between the issuing of a CBW to a device, and the reception of the first packet */ - #define COMMAND_DATA_TIMEOUT_MS 500 - - /** Pipe number of the Mass Storage data IN pipe */ - #define MASS_STORE_DATA_IN_PIPE 1 - - /** Pipe number of the Mass Storage data OUT pipe */ - #define MASS_STORE_DATA_OUT_PIPE 2 - - /* Type defines: */ - /** Type define for a Mass Storage class Command Block Wrapper, used to wrap SCSI - * commands for transport over the USB bulk endpoints to the device. - */ - typedef struct - { - struct - { - uint32_t Signature; /**< Command block signature, always equal to CBW_SIGNATURE */ - uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW */ - uint32_t DataTransferLength; /**< Length of data to transfer, following the CBW */ - uint8_t Flags; /**< Block flags, equal to one of the COMMAND_DIRECTION_DATA_* macros */ - uint8_t LUN; /**< Logical Unit Number the CBW is addressed to in the device */ - uint8_t SCSICommandLength; /**< Length of the SCSI command in the CBW */ - } Header; - - uint8_t SCSICommandData[16]; /**< SCSI command to issue to the device */ - } CommandBlockWrapper_t; - - /** Type define for a Mass Storage class Command Status Wrapper, used to wrap SCSI - * responses for transport over the USB bulk endpoints from the device. - */ - typedef struct - { - uint32_t Signature; /**< Command status signature, always equal to CSW_SIGNATURE */ - uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW */ - uint32_t DataTransferResidue; /**< Length of data not transferred */ - uint8_t Status; /**< Command status, a value from the MassStorageHost_CommandStatusCodes_t enum */ - } CommandStatusWrapper_t; - - /** Type define for a SCSI Sense structure. Structures of this type are filled out by the - * device via the MassStore_RequestSense() function, indicating the current sense data of the - * device (giving explicit error codes for the last issued command). For details of the - * structure contents, refer to the SCSI specifications. - */ - typedef struct - { - uint8_t ReponseCode; - - uint8_t SegmentNumber; - - unsigned char SenseKey : 4; - unsigned char _RESERVED1 : 1; - unsigned char ILI : 1; - unsigned char EOM : 1; - unsigned char FileMark : 1; - - uint8_t Information[4]; - uint8_t AdditionalLength; - uint8_t CmdSpecificInformation[4]; - uint8_t AdditionalSenseCode; - uint8_t AdditionalSenseQualifier; - uint8_t FieldReplaceableUnitCode; - uint8_t SenseKeySpecific[3]; - } SCSI_Request_Sense_Response_t; - - /** SCSI capacity structure, to hold the total capacity of the device in both the number - * of blocks in the current LUN, and the size of each block. This structure is filled by - * the device when the MassStore_ReadCapacity() function is called. - */ - typedef struct - { - uint32_t Blocks; /**< Number of blocks in the addressed LUN of the device */ - uint32_t BlockSize; /**< Number of bytes in each block in the addressed LUN */ - } SCSI_Capacity_t; - - /* Enums: */ - /** CSW status return codes, indicating the overall status of the issued CBW */ - enum MassStorageHost_CommandStatusCodes_t - { - Command_Pass = 0, /**< Command completed successfully */ - Command_Fail = 1, /**< Command failed to complete successfully */ - Phase_Error = 2 /**< Phase error while processing the issued command */ - }; - - /* External Variables: */ - extern CommandStatusWrapper_t SCSICommandStatus; - - /* Function Prototypes: */ - #if defined(INCLUDE_FROM_MASSSTORE_COMMANDS_C) - static uint8_t MassStore_SendCommand(void); - static uint8_t MassStore_WaitForDataReceived(void); - static uint8_t MassStore_SendReceiveData(void* BufferPtr) ATTR_NON_NULL_PTR_ARG(1); - static uint8_t MassStore_GetReturnedStatus(void); - #endif - - uint8_t MassStore_ClearPipeStall(const uint8_t EndpointNum); - uint8_t MassStore_MassStorageReset(void); - uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex); - uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr) - ATTR_NON_NULL_PTR_ARG(2); - uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, - const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(5); - uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress, - const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(5); - uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const CapacityPtr) - ATTR_NON_NULL_PTR_ARG(2); - uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex); - uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool PreventRemoval); - -#endif diff --git a/Demos/Host/MassStorageHost/SCSI_Codes.h b/Demos/Host/MassStorageHost/SCSI_Codes.h deleted file mode 100644 index 2b2213de2..000000000 --- a/Demos/Host/MassStorageHost/SCSI_Codes.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, 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 - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Header containing macros for possible SCSI commands and SENSE data. Refer to - * the SCSI standard documentation for more information on each SCSI command and - * the SENSE data. - */ - -#ifndef _SCSI_CODES_H_ -#define _SCSI_CODES_H_ - - /* Macros: */ - #define SCSI_CMD_INQUIRY 0x12 - #define SCSI_CMD_REQUEST_SENSE 0x03 - #define SCSI_CMD_TEST_UNIT_READY 0x00 - #define SCSI_CMD_READ_CAPACITY_10 0x25 - #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D - #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E - #define SCSI_CMD_WRITE_10 0x2A - #define SCSI_CMD_READ_10 0x28 - #define SCSI_CMD_WRITE_6 0x0A - #define SCSI_CMD_READ_6 0x08 - #define SCSI_CMD_VERIFY_10 0x2F - #define SCSI_CMD_MODE_SENSE_6 0x1A - #define SCSI_CMD_MODE_SENSE_10 0x5A - - #define SCSI_SENSE_KEY_GOOD 0x00 - #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 - #define SCSI_SENSE_KEY_NOT_READY 0x02 - #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 - #define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 - #define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 - #define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 - #define SCSI_SENSE_KEY_DATA_PROTECT 0x07 - #define SCSI_SENSE_KEY_BLANK_CHECK 0x08 - #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 - #define SCSI_SENSE_KEY_COPY_ABORTED 0x0A - #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B - #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D - #define SCSI_SENSE_KEY_MISCOMPARE 0x0E - - #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 - #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 - #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 - #define SCSI_ASENSE_WRITE_PROTECTED 0x27 - #define SCSI_ASENSE_FORMAT_ERROR 0x31 - #define SCSI_ASENSE_INVALID_COMMAND 0x20 - #define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 - #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A - - #define SCSI_ASENSEQ_NO_QUALIFIER 0x00 - #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 - #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 - #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 - -#endif diff --git a/Demos/Host/MassStorageHost/makefile b/Demos/Host/MassStorageHost/makefile index d4792ae40..f50f59887 100644 --- a/Demos/Host/MassStorageHost/makefile +++ b/Demos/Host/MassStorageHost/makefile @@ -125,7 +125,7 @@ LUFA_PATH = ../../.. # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c \ ConfigDescriptor.c \ - MassStoreCommands.c \ + Lib/MassStoreCommands.c \ $(LUFA_PATH)/LUFA/Scheduler/Scheduler.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/SerialStream.c \ $(LUFA_PATH)/LUFA/Drivers/Peripheral/Serial.c \ -- cgit v1.2.3