Add the start of a new Mass Storage class bootloader.
authorDean Camera <dean@fourwalledcubicle.com>
Fri, 8 Mar 2013 15:50:12 +0000 (15:50 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Fri, 8 Mar 2013 15:50:12 +0000 (15:50 +0000)
Bootloaders/Incomplete/MassStorage/Config/LUFAConfig.h [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Descriptors.c [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Descriptors.h [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Lib/SCSI.c [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Lib/SCSI.h [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.c [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.h [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/MassStorage.c [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/MassStorage.h [new file with mode: 0644]
Bootloaders/Incomplete/MassStorage/makefile [new file with mode: 0644]

diff --git a/Bootloaders/Incomplete/MassStorage/Config/LUFAConfig.h b/Bootloaders/Incomplete/MassStorage/Config/LUFAConfig.h
new file mode 100644 (file)
index 0000000..b1ae7b5
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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
+ *  \brief LUFA Library Configuration Header File
+ *
+ *  This header file is used to configure LUFA's compile time options,
+ *  as an alternative to the compile time constants supplied through
+ *  a makefile.
+ *
+ *  For information on what each token does, refer to the LUFA
+ *  manual section "Summary of Compile Tokens".
+ */
+
+#ifndef _LUFA_CONFIG_H_
+#define _LUFA_CONFIG_H_
+
+       #if (ARCH == ARCH_AVR8)
+
+               /* Non-USB Related Configuration Tokens: */
+//             #define DISABLE_TERMINAL_CODES
+
+               /* USB Class Driver Related Tokens: */
+//             #define HID_HOST_BOOT_PROTOCOL_ONLY
+//             #define HID_STATETABLE_STACK_DEPTH       {Insert Value Here}
+//             #define HID_USAGE_STACK_DEPTH            {Insert Value Here}
+//             #define HID_MAX_COLLECTIONS              {Insert Value Here}
+//             #define HID_MAX_REPORTITEMS              {Insert Value Here}
+//             #define HID_MAX_REPORT_IDS               {Insert Value Here}
+//             #define NO_CLASS_DRIVER_AUTOFLUSH
+
+               /* General USB Driver Related Tokens: */
+//             #define ORDERED_EP_CONFIG
+               #define USE_STATIC_OPTIONS               (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
+               #define USB_DEVICE_ONLY
+//             #define USB_HOST_ONLY
+//             #define USB_STREAM_TIMEOUT_MS            {Insert Value Here}
+//             #define NO_LIMITED_CONTROLLER_CONNECT
+//             #define NO_SOF_EVENTS
+
+               /* USB Device Mode Driver Related Tokens: */
+               #define USE_RAM_DESCRIPTORS
+//             #define USE_FLASH_DESCRIPTORS
+//             #define USE_EEPROM_DESCRIPTORS
+//             #define NO_INTERNAL_SERIAL
+               #define FIXED_CONTROL_ENDPOINT_SIZE      8
+//             #define DEVICE_STATE_AS_GPIOR            {Insert Value Here}
+               #define FIXED_NUM_CONFIGURATIONS         1
+//             #define CONTROL_ONLY_DEVICE
+               #define INTERRUPT_CONTROL_ENDPOINT
+//             #define NO_DEVICE_REMOTE_WAKEUP
+//             #define NO_DEVICE_SELF_POWER
+
+               /* USB Host Mode Driver Related Tokens: */
+//             #define HOST_STATE_AS_GPIOR              {Insert Value Here}
+//             #define USB_HOST_TIMEOUT_MS              {Insert Value Here}
+//             #define HOST_DEVICE_SETTLE_DELAY_MS          {Insert Value Here}
+//             #define NO_AUTO_VBUS_MANAGEMENT
+//             #define INVERTED_VBUS_ENABLE_LINE
+
+       #else
+
+               #error Unsupported architecture for this LUFA configuration file.
+
+       #endif
+#endif
diff --git a/Bootloaders/Incomplete/MassStorage/Descriptors.c b/Bootloaders/Incomplete/MassStorage/Descriptors.c
new file mode 100644 (file)
index 0000000..0dda34a
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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
+ *
+ *  USB Device Descriptors, for library use when in USB device mode. Descriptors are special
+ *  computer-readable structures which the host requests upon device enumeration, to determine
+ *  the device's capabilities and functions.
+ */
+
+#include "Descriptors.h"
+
+
+/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
+ *  device characteristics, including the supported USB version, control endpoint size and the
+ *  number of device configurations. The descriptor is read out by the USB host when the enumeration
+ *  process begins.
+ */
+const USB_Descriptor_Device_t DeviceDescriptor =
+{
+       .Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
+
+       .USBSpecification       = VERSION_BCD(01.10),
+       .Class                  = USB_CSCP_NoDeviceClass,
+       .SubClass               = USB_CSCP_NoDeviceSubclass,
+       .Protocol               = USB_CSCP_NoDeviceProtocol,
+
+       .Endpoint0Size          = FIXED_CONTROL_ENDPOINT_SIZE,
+
+       .VendorID               = 0x03EB,
+       .ProductID              = 0x2045,
+       .ReleaseNumber          = VERSION_BCD(00.01),
+
+       .ManufacturerStrIndex   = 0x01,
+       .ProductStrIndex        = 0x02,
+       .SerialNumStrIndex      = USE_INTERNAL_SERIAL,
+
+       .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
+};
+
+/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
+ *  of the device in one of its supported configurations, including information about any device interfaces
+ *  and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
+ *  a configuration so that the host may correctly communicate with the USB device.
+ */
+const USB_Descriptor_Configuration_t ConfigurationDescriptor =
+{
+       .Config =
+               {
+                       .Header                 = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
+
+                       .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
+                       .TotalInterfaces        = 1,
+
+                       .ConfigurationNumber    = 1,
+                       .ConfigurationStrIndex  = NO_DESCRIPTOR,
+
+                       .ConfigAttributes       = USB_CONFIG_ATTR_RESERVED,
+
+                       .MaxPowerConsumption    = USB_CONFIG_POWER_MA(100)
+               },
+
+       .MS_Interface =
+               {
+                       .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
+
+                       .InterfaceNumber        = 0,
+                       .AlternateSetting       = 0,
+
+                       .TotalEndpoints         = 2,
+
+                       .Class                  = MS_CSCP_MassStorageClass,
+                       .SubClass               = MS_CSCP_SCSITransparentSubclass,
+                       .Protocol               = MS_CSCP_BulkOnlyTransportProtocol,
+
+                       .InterfaceStrIndex      = NO_DESCRIPTOR
+               },
+
+       .MS_DataInEndpoint =
+               {
+                       .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+                       .EndpointAddress        = MASS_STORAGE_IN_EPADDR,
+                       .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+                       .EndpointSize           = MASS_STORAGE_IO_EPSIZE,
+                       .PollingIntervalMS      = 0x05
+               },
+
+       .MS_DataOutEndpoint =
+               {
+                       .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+                       .EndpointAddress        = MASS_STORAGE_OUT_EPADDR,
+                       .Attributes             = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+                       .EndpointSize           = MASS_STORAGE_IO_EPSIZE,
+                       .PollingIntervalMS      = 0x05
+               }
+};
+
+/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
+ *  the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
+ *  via the language ID table available at USB.org what languages the device supports for its string descriptors.
+ */
+const USB_Descriptor_String_t LanguageString =
+{
+       .Header                 = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
+
+       .UnicodeString          = {LANGUAGE_ID_ENG}
+};
+
+/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
+ *  form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
+ *  Descriptor.
+ */
+const USB_Descriptor_String_t ManufacturerString =
+{
+       .Header                 = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String},
+
+       .UnicodeString          = L"Dean Camera"
+};
+
+/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
+ *  and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
+ *  Descriptor.
+ */
+const USB_Descriptor_String_t ProductString =
+{
+       .Header                 = {.Size = USB_STRING_LEN(15), .Type = DTYPE_String},
+
+       .UnicodeString          = L"LUFA Bootloader"
+};
+
+/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
+ *  documentation) by the application code so that the address and size of a requested descriptor can be given
+ *  to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
+ *  is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
+ *  USB host.
+ */
+uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
+                                    const uint8_t wIndex,
+                                    const void** const DescriptorAddress)
+{
+       const uint8_t  DescriptorType   = (wValue >> 8);
+       const uint8_t  DescriptorNumber = (wValue & 0xFF);
+
+       const void* Address = NULL;
+       uint16_t    Size    = NO_DESCRIPTOR;
+
+       switch (DescriptorType)
+       {
+               case DTYPE_Device:
+                       Address = &DeviceDescriptor;
+                       Size    = sizeof(USB_Descriptor_Device_t);
+                       break;
+               case DTYPE_Configuration:
+                       Address = &ConfigurationDescriptor;
+                       Size    = sizeof(USB_Descriptor_Configuration_t);
+                       break;
+               case DTYPE_String:
+                       switch (DescriptorNumber)
+                       {
+                               case 0x00:
+                                       Address = &LanguageString;
+                                       Size    = pgm_read_byte(&LanguageString.Header.Size);
+                                       break;
+                               case 0x01:
+                                       Address = &ManufacturerString;
+                                       Size    = pgm_read_byte(&ManufacturerString.Header.Size);
+                                       break;
+                               case 0x02:
+                                       Address = &ProductString;
+                                       Size    = pgm_read_byte(&ProductString.Header.Size);
+                                       break;
+                       }
+
+                       break;
+       }
+
+       *DescriptorAddress = Address;
+       return Size;
+}
+
diff --git a/Bootloaders/Incomplete/MassStorage/Descriptors.h b/Bootloaders/Incomplete/MassStorage/Descriptors.h
new file mode 100644 (file)
index 0000000..7261fab
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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 Descriptors.c.
+ */
+
+#ifndef _DESCRIPTORS_H_
+#define _DESCRIPTORS_H_
+
+       /* Includes: */
+               #include <avr/pgmspace.h>
+
+               #include <LUFA/Drivers/USB/USB.h>
+
+       /* Macros: */
+               /** Endpoint address of the Mass Storage device-to-host data IN endpoint. */
+               #define MASS_STORAGE_IN_EPADDR         (ENDPOINT_DIR_IN  | 3)
+
+               /** Endpoint address of the Mass Storage host-to-device data OUT endpoint. */
+               #define MASS_STORAGE_OUT_EPADDR        (ENDPOINT_DIR_OUT | 4)
+
+               /** Size in bytes of the Mass Storage data endpoints. */
+               #define MASS_STORAGE_IO_EPSIZE         64
+
+       /* Type Defines: */
+               /** Type define for the device configuration descriptor structure. This must be defined in the
+                *  application code, as the configuration descriptor contains several sub-descriptors which
+                *  vary between devices, and which describe the device's usage to the host.
+                */
+               typedef struct
+               {
+                       USB_Descriptor_Configuration_Header_t Config;
+
+                       // Mass Storage Interface
+                       USB_Descriptor_Interface_t            MS_Interface;
+                       USB_Descriptor_Endpoint_t             MS_DataInEndpoint;
+                       USB_Descriptor_Endpoint_t             MS_DataOutEndpoint;
+               } USB_Descriptor_Configuration_t;
+
+       /* Function Prototypes: */
+               uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
+                                                   const uint8_t wIndex,
+                                                   const void** const DescriptorAddress)
+                                                   ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
+
+#endif
+
diff --git a/Bootloaders/Incomplete/MassStorage/Lib/SCSI.c b/Bootloaders/Incomplete/MassStorage/Lib/SCSI.c
new file mode 100644 (file)
index 0000000..c6596d4
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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
+ *
+ *  SCSI command processing routines, for SCSI commands issued by the host. Mass Storage
+ *  devices use a thin "Bulk-Only Transport" protocol for issuing commands and status information,
+ *  which wrap around standard SCSI device commands for controlling the actual storage medium.
+ */
+
+#define  INCLUDE_FROM_SCSI_C
+#include "SCSI.h"
+
+/** Structure to hold the SCSI response data to a SCSI INQUIRY command. This gives information about the device's
+ *  features and capabilities.
+ */
+static const SCSI_Inquiry_Response_t InquiryData =
+       {
+               .DeviceType          = DEVICE_TYPE_BLOCK,
+               .PeripheralQualifier = 0,
+
+               .Removable           = true,
+
+               .Version             = 0,
+
+               .ResponseDataFormat  = 2,
+               .NormACA             = false,
+               .TrmTsk              = false,
+               .AERC                = false,
+
+               .AdditionalLength    = 0x1F,
+
+               .SoftReset           = false,
+               .CmdQue              = false,
+               .Linked              = false,
+               .Sync                = false,
+               .WideBus16Bit        = false,
+               .WideBus32Bit        = false,
+               .RelAddr             = false,
+
+               .VendorID            = "LUFA",
+               .ProductID           = "Bootloader",
+               .RevisionID          = {'0','.','0','0'},
+       };
+
+/** Structure to hold the sense data for the last issued SCSI command, which is returned to the host after a SCSI REQUEST SENSE
+ *  command is issued. This gives information on exactly why the last command failed to complete.
+ */
+static SCSI_Request_Sense_Response_t SenseData =
+       {
+               .ResponseCode        = 0x70,
+               .AdditionalLength    = 0x0A,
+       };
+
+
+/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches
+ *  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.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise
+ */
+bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       bool CommandSuccess = false;
+
+       /* Run the appropriate SCSI command hander function based on the passed command */
+       switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0])
+       {
+               case SCSI_CMD_INQUIRY:
+                       CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo);
+                       break;
+               case SCSI_CMD_REQUEST_SENSE:
+                       CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo);
+                       break;
+               case SCSI_CMD_READ_CAPACITY_10:
+                       CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
+                       break;
+               case SCSI_CMD_SEND_DIAGNOSTIC:
+                       CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
+                       break;
+               case SCSI_CMD_WRITE_10:
+                       CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
+                       break;
+               case SCSI_CMD_READ_10:
+                       CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
+                       break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       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;
+                       MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
+                       break;
+               default:
+                       /* Update the SENSE key to reflect the invalid command */
+                       SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+                                  SCSI_ASENSE_INVALID_COMMAND,
+                                  SCSI_ASENSEQ_NO_QUALIFIER);
+                       break;
+       }
+
+       /* Check if command was successfully processed */
+       if (CommandSuccess)
+       {
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
+                              SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
+                              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
+ *  and capabilities to the host.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       uint16_t AllocationLength  = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]);
+       uint16_t BytesTransferred  = MIN(AllocationLength, sizeof(InquiryData));
+
+       /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
+       if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
+            MSInterfaceInfo->State.CommandBlock.SCSICommandData[2])
+       {
+               /* Optional but unsupported bits set - update the SENSE key and fail the request */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+                              SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;
+       }
+
+       Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NULL);
+
+       /* Pad out remaining bytes with 0x00 */
+       Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
+
+       /* Finalize the stream transfer to send the last packet */
+       Endpoint_ClearIN();
+
+       /* Succeed the command and update the bytes transferred counter */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
+
+       return true;
+}
+
+/** Command processing for an issued SCSI REQUEST SENSE command. This command returns information about the last issued command,
+ *  including the error code and additional error information so that the host can determine why a command failed to complete.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
+       uint8_t BytesTransferred = MIN(AllocationLength, sizeof(SenseData));
+
+       Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NULL);
+       Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
+       Endpoint_ClearIN();
+
+       /* Succeed the command and update the bytes transferred counter */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
+
+       return true;
+}
+
+/** Command processing for an issued SCSI READ CAPACITY (10) command. This command returns information about the device's capacity
+ *  on the selected Logical Unit (drive), as a number of OS-sized blocks.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       uint32_t LastBlockAddressInLUN = (LUN_MEDIA_BLOCKS - 1);
+       uint32_t MediaBlockSize        = VIRTUAL_MEMORY_BLOCK_SIZE;
+
+       Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NULL);
+       Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NULL);
+       Endpoint_ClearIN();
+
+       /* Succeed the command and update the bytes transferred counter */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 8;
+
+       return true;
+}
+
+/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the
+ *  board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is
+ *  supported.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Check to see if the SELF TEST bit is not set */
+       if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2)))
+       {
+               /* Only self-test supported - update SENSE key and fail the command */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+                              SCSI_ASENSE_INVALID_FIELD_IN_CDB,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;
+       }
+
+       /* Succeed the command and update the bytes transferred counter */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
+
+       return true;
+}
+
+/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
+ *  and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual
+ *  reading and writing of the data.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *  \param[in] IsDataRead  Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                                      const bool IsDataRead)
+{
+       uint32_t BlockAddress;
+       uint16_t TotalBlocks;
+
+       /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
+       BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
+
+       /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */
+       TotalBlocks  = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]);
+
+       /* Check if the block address is outside the maximum allowable value for the LUN */
+       if (BlockAddress >= LUN_MEDIA_BLOCKS)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
+                              SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;
+       }
+
+       /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
+       if (IsDataRead == DATA_READ)
+         VirtualFAT_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
+       else
+         VirtualFAT_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
+
+       return true;
+}
+
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_8(0x00);
+       Endpoint_Write_8(0x00);
+       Endpoint_Write_8(0x00);
+       Endpoint_Write_8(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
+
diff --git a/Bootloaders/Incomplete/MassStorage/Lib/SCSI.h b/Bootloaders/Incomplete/MassStorage/Lib/SCSI.h
new file mode 100644 (file)
index 0000000..bec1c96
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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 SCSI.c.
+ */
+
+#ifndef _SCSI_H_
+#define _SCSI_H_
+
+       /* Includes: */
+               #include <avr/io.h>
+               #include <avr/pgmspace.h>
+
+               #include <LUFA/Drivers/USB/USB.h>
+
+               #include "../MassStorage.h"
+               #include "../Descriptors.h"
+               #include "VirtualFAT.h"
+
+       /* Macros: */
+               /** Macro to set the current SCSI sense data to the given key, additional sense code and additional sense qualifier. This
+                *  is for convenience, as it allows for all three sense values (returned upon request to the host to give information about
+                *  the last command failure) in a quick and easy manner.
+                *
+                *  \param[in] Key    New SCSI sense key to set the sense code to
+                *  \param[in] Acode  New SCSI additional sense key to set the additional sense code to
+                *  \param[in] Aqual  New SCSI additional sense key qualifier to set the additional sense qualifier code to
+                */
+               #define SCSI_SET_SENSE(Key, Acode, Aqual)  MACROS{ SenseData.SenseKey                 = (Key);   \
+                                                                  SenseData.AdditionalSenseCode      = (Acode); \
+                                                                  SenseData.AdditionalSenseQualifier = (Aqual); }MACROE
+
+               /** Macro for the \ref SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
+               #define DATA_READ           true
+
+               /** Macro for the \ref SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
+               #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
+
+       /* Function Prototypes: */
+               bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+
+               #if defined(INCLUDE_FROM_SCSI_C)
+                       static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                       static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                       static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                       static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+                       static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                                                             const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+               #endif
+
+#endif
+
diff --git a/Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.c b/Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.c
new file mode 100644 (file)
index 0000000..7b0c5dd
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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.
+*/
+
+#include "VirtualFAT.h"
+
+static const FATBootBlock_t BootBlock =
+       {
+               .Bootstrap               = {0xEB, 0x3C, 0x90},
+               .Description             = "mkdosfs",
+               .BlockSize               = VIRTUAL_MEMORY_BLOCK_SIZE,
+               .BlocksPerAllocationUnit = ALLOCATION_UNIT_BLOCKS,
+               .ReservedBlocks          = 1,
+               .FATCopies               = 2,
+               .RootDirectoryEntries    = 512,
+               .TotalBlocks16           = LUN_MEDIA_BLOCKS,
+               .MediaDescriptor         = 0xF8,
+               .BlocksPerFAT            = 1,
+               .BlocksPerTrack          = 32,
+               .Heads                   = 64,
+               .HiddenBlocks            = 0,
+               .TotalBlocks32           = 0,
+               .PhysicalDriveNum        = 0,
+               .ExtendedBootRecordSig   = 0x29,
+               .VolumeSerialNumber      = 0x12345678,
+               .VolumeLabel             = "LUFA BOOT  ",
+               .FilesystemIdentifier    = "FAT16   ",
+               .BootstrapProgram        = {0},
+               .MagicSignature          = 0xAA55,
+       };
+
+static FATDirectoryEntry_t FirmwareFileEntry =
+       {
+               .Filename        = "Firmware",
+               .Extension       = "bin",
+               .Attributes      = 0,
+               .Reserved        = {0},
+               .CreationTime    = (1 << 11) | (1 << 5),
+               .CreationDate    = (9 << 9)  | (2 << 5) | (14 << 0),
+               .StartingCluster = 4,
+               .FileSize        = (FLASHEND + 1UL),
+       };
+
+static void WriteBlock(uint16_t BlockNumber)
+{
+       uint8_t BlockBuffer[512];
+
+       /* Wait until endpoint is ready before continuing */
+       if (Endpoint_WaitUntilReady())
+         return;
+
+       Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
+       Endpoint_ClearOUT();
+
+       // TODO: Write to FLASH
+}
+
+static void ReadBlock(uint16_t BlockNumber)
+{
+       uint8_t BlockBuffer[512];
+       memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
+
+       switch (BlockNumber)
+       {
+               case 0:
+                       memcpy(BlockBuffer, &BootBlock, sizeof(FATBootBlock_t));
+                       break;
+
+               case 1:
+               case 2:
+                       /* Cluster 0: Media type/Reserved */
+                       ((uint16_t*)&BlockBuffer)[0] = 0xFF00 | BootBlock.MediaDescriptor;
+
+                       /* Cluster 1: Reserved */
+                       ((uint16_t*)&BlockBuffer)[1] = 0xFFFF;
+
+                       /* Cluster 2: Reserved */
+                       ((uint16_t*)&BlockBuffer)[2] = 0xFFFF;
+
+                       /* Cluster 3: FIRMWARE.BIN File Entry */
+                       ((uint16_t*)&BlockBuffer)[3] = 0xFFFF;
+
+                       /* Cluster 4 onwards: Cluster chain of FIRMWARE.BIN */
+                       for (uint16_t i = 0; i < ((FLASHEND + 1) / (VIRTUAL_MEMORY_BLOCK_SIZE * ALLOCATION_UNIT_BLOCKS)); i++)
+                       {
+                               ((uint16_t*)&BlockBuffer)[i + 4] = i + 5;
+                       }
+
+                       /* Mark last cluster as end of file */
+                       ((uint16_t*)&BlockBuffer)[((FLASHEND + 1) / (VIRTUAL_MEMORY_BLOCK_SIZE * ALLOCATION_UNIT_BLOCKS)) + 4] = 0xFFFF;
+                       break;
+
+               case 3:
+                       memcpy(BlockBuffer, &FirmwareFileEntry, sizeof(FATDirectoryEntry_t));
+                       break;
+
+               default:
+                       break;
+       }
+
+       /* Wait until endpoint is ready before continuing */
+       if (Endpoint_WaitUntilReady())
+         return;
+
+       Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
+       Endpoint_ClearIN();
+}
+
+void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                            const uint32_t BlockAddress,
+                            uint16_t TotalBlocks)
+{
+       uint16_t CurrentBlock = (uint16_t)BlockAddress;
+
+       while (TotalBlocks--)
+         WriteBlock(CurrentBlock++);
+}
+
+void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                           const uint32_t BlockAddress,
+                           uint16_t TotalBlocks)
+{
+       uint16_t CurrentBlock = (uint16_t)BlockAddress;
+
+       while (TotalBlocks--)
+         ReadBlock(CurrentBlock++);
+}
+
diff --git a/Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.h b/Bootloaders/Incomplete/MassStorage/Lib/VirtualFAT.h
new file mode 100644 (file)
index 0000000..2009b68
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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.
+*/
+
+#ifndef _VIRTUALFAT_H_
+#define _VIRTUALFAT_H_
+
+       /* Includes: */
+               #include <avr/io.h>
+               #include <avr/pgmspace.h>
+
+               #include <LUFA/Drivers/USB/USB.h>
+
+       /* Macros: */
+               #define VIRTUAL_MEMORY_BLOCK_SIZE 512
+               #define ALLOCATION_UNIT_BLOCKS    4
+               #define LUN_MEDIA_BLOCKS          ((FLASHEND + 1) / VIRTUAL_MEMORY_BLOCK_SIZE) + 16
+
+       /* Type Definitions: */
+               typedef struct
+               {
+                       uint8_t  Bootstrap[3];
+                       uint8_t  Description[8];
+                       uint16_t BlockSize;
+                       uint8_t  BlocksPerAllocationUnit;
+                       uint16_t ReservedBlocks;
+                       uint8_t  FATCopies;
+                       uint16_t RootDirectoryEntries;
+                       uint16_t TotalBlocks16;
+                       uint8_t  MediaDescriptor;
+                       uint16_t BlocksPerFAT;
+                       uint16_t BlocksPerTrack;
+                       uint16_t Heads;
+                       uint32_t HiddenBlocks;
+                       uint32_t TotalBlocks32;
+                       uint16_t PhysicalDriveNum;
+                       uint8_t  ExtendedBootRecordSig;
+                       uint32_t VolumeSerialNumber;
+                       uint8_t  VolumeLabel[11];
+                       uint8_t  FilesystemIdentifier[8];
+                       uint8_t  BootstrapProgram[448];
+                       uint16_t MagicSignature;
+               } FATBootBlock_t;
+
+               typedef struct
+               {
+                       uint8_t Filename[8];
+                       uint8_t Extension[3];
+                       uint8_t Attributes;
+                       uint8_t Reserved[10];
+                       uint16_t CreationTime;
+                       uint16_t CreationDate;
+                       uint16_t StartingCluster;
+                       uint32_t FileSize;
+               } FATDirectoryEntry_t;
+
+       /* Function Prototypes: */
+               void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                                           const uint32_t BlockAddress,
+                                           uint16_t TotalBlocks);
+
+               void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
+                                          const uint32_t BlockAddress,
+                                          uint16_t TotalBlocks);
+#endif
diff --git a/Bootloaders/Incomplete/MassStorage/MassStorage.c b/Bootloaders/Incomplete/MassStorage/MassStorage.c
new file mode 100644 (file)
index 0000000..2d4d973
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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
+ *
+ *  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.
+ */
+
+#include "MassStorage.h"
+
+/** 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_Device_t Disk_MS_Interface =
+       {
+               .Config =
+                       {
+                               .InterfaceNumber           = 0,
+                               .DataINEndpoint            =
+                                       {
+                                               .Address           = MASS_STORAGE_IN_EPADDR,
+                                               .Size              = MASS_STORAGE_IO_EPSIZE,
+                                               .Banks             = 1,
+                                       },
+                               .DataOUTEndpoint           =
+                                       {
+                                               .Address           = MASS_STORAGE_OUT_EPADDR,
+                                               .Size              = MASS_STORAGE_IO_EPSIZE,
+                                               .Banks             = 1,
+                                       },
+                               .TotalLUNs                 = 1,
+                       },
+       };
+
+
+/** 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);
+       GlobalInterruptEnable();
+
+       for (;;)
+       {
+               MS_Device_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();
+
+       /* Disable clock division */
+       clock_prescale_set(clock_div_1);
+
+       /* Relocate the interrupt vector table to the bootloader section */
+       MCUCR = (1 << IVCE);
+       MCUCR = (1 << IVSEL);
+
+       /* Hardware Initialization */
+       LEDs_Init();
+       USB_Init();
+}
+
+/** Event handler for the library USB Connection event. */
+void EVENT_USB_Device_Connect(void)
+{
+       LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
+}
+
+/** Event handler for the library USB Disconnection event. */
+void EVENT_USB_Device_Disconnect(void)
+{
+       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+}
+
+/** Event handler for the library USB Configuration Changed event. */
+void EVENT_USB_Device_ConfigurationChanged(void)
+{
+       bool ConfigSuccess = true;
+
+       ConfigSuccess &= MS_Device_ConfigureEndpoints(&Disk_MS_Interface);
+
+       LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
+}
+
+/** Event handler for the library USB Control Request reception event. */
+void EVENT_USB_Device_ControlRequest(void)
+{
+       MS_Device_ProcessControlRequest(&Disk_MS_Interface);
+}
+
+/** Mass Storage class driver callback function the reception of SCSI commands from the host, which must be processed.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface configuration structure being referenced
+ */
+bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       bool CommandSuccess;
+
+       LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
+       CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
+       LEDs_SetAllLEDs(LEDMASK_USB_READY);
+
+       return CommandSuccess;
+}
+
diff --git a/Bootloaders/Incomplete/MassStorage/MassStorage.h b/Bootloaders/Incomplete/MassStorage/MassStorage.h
new file mode 100644 (file)
index 0000000..a6ad9b2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  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
+  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 disclaims 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 MassStorage.c.
+ */
+
+#ifndef _MASS_STORAGE_H_
+#define _MASS_STORAGE_H_
+
+       /* Includes: */
+               #include <avr/io.h>
+               #include <avr/wdt.h>
+               #include <avr/power.h>
+               #include <avr/interrupt.h>
+               #include <string.h>
+
+               #include "Descriptors.h"
+
+               #include "Lib/SCSI.h"
+
+               #include <LUFA/Drivers/Board/LEDs.h>
+               #include <LUFA/Drivers/USB/USB.h>
+
+       /* Macros: */
+               /** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
+               #define LEDMASK_USB_NOTREADY      LEDS_LED1
+
+               /** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
+               #define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3)
+
+               /** LED mask for the library LED driver, to indicate that the USB interface is ready. */
+               #define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4)
+
+               /** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
+               #define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3)
+
+               /** LED mask for the library LED driver, to indicate that the USB interface is busy. */
+               #define LEDMASK_USB_BUSY          LEDS_LED2
+
+       /* Function Prototypes: */
+               void SetupHardware(void);
+
+               void EVENT_USB_Device_Connect(void);
+               void EVENT_USB_Device_Disconnect(void);
+               void EVENT_USB_Device_ConfigurationChanged(void);
+               void EVENT_USB_Device_ControlRequest(void);
+
+               bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
+
+#endif
+
diff --git a/Bootloaders/Incomplete/MassStorage/makefile b/Bootloaders/Incomplete/MassStorage/makefile
new file mode 100644 (file)
index 0000000..566c47d
--- /dev/null
@@ -0,0 +1,48 @@
+#\r
+#             LUFA Library\r
+#     Copyright (C) Dean Camera, 2013.\r
+#\r
+#  dean [at] fourwalledcubicle [dot] com\r
+#           www.lufa-lib.org\r
+#\r
+# --------------------------------------\r
+#         LUFA Project Makefile.\r
+# --------------------------------------\r
+\r
+# Run "make help" for target help.\r
+\r
+MCU          = at90usb1287\r
+ARCH         = AVR8\r
+BOARD        = USBKEY\r
+F_CPU        = 8000000\r
+F_USB        = $(F_CPU)\r
+OPTIMIZATION = s\r
+TARGET       = MassStorage\r
+SRC          = $(TARGET).c Descriptors.c Lib/SCSI.c Lib/VirtualFAT.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)\r
+LUFA_PATH    = ../../../LUFA\r
+CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/\r
+LD_FLAGS     = -Wl,--section-start=.text=$(BOOT_START_OFFSET)\r
+\r
+# Flash size and bootloader section sizes of the target, in KB. These must\r
+# match the target's total FLASH size and the bootloader size set in the\r
+# device's fuses.\r
+FLASH_SIZE_KB        := 128\r
+BOOT_SECTION_SIZE_KB := 8\r
+\r
+# Bootloader address calculation formulas\r
+# Do not modify these macros, but rather modify the dependent values above.\r
+CALC_ADDRESS_IN_HEX   = $(shell printf "0x%X" $$(( $(1) )) )\r
+BOOT_START_OFFSET     = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) - $(BOOT_SECTION_SIZE_KB)) * 1024 )\r
+BOOT_SEC_OFFSET       = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) * 1024) - $(strip $(1)) )\r
+\r
+# Default target\r
+all:\r
+\r
+# Include LUFA build script makefiles\r
+include $(LUFA_PATH)/Build/lufa_core.mk\r
+include $(LUFA_PATH)/Build/lufa_sources.mk\r
+include $(LUFA_PATH)/Build/lufa_build.mk\r
+include $(LUFA_PATH)/Build/lufa_cppcheck.mk\r
+include $(LUFA_PATH)/Build/lufa_doxygen.mk\r
+include $(LUFA_PATH)/Build/lufa_avrdude.mk\r
+include $(LUFA_PATH)/Build/lufa_atprogram.mk\r