Merge commit '60b30c0363' as 'lib/lufa'

This commit is contained in:
Jack Humbert 2017-07-07 11:55:23 -04:00
commit 8655d4f494
1455 changed files with 394541 additions and 0 deletions

View file

@ -0,0 +1,50 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 Application Configuration Header File
*
* This is a header file which is be used to configure some of
* the application's compile time options, as an alternative to
* specifying the compile time constants supplied through a
* makefile or build system.
*
* For information on what each token does, refer to the
* \ref Sec_Options section of the application documentation.
*/
#ifndef _APP_CONFIG_H_
#define _APP_CONFIG_H_
#define TOTAL_LUNS 1
#define DISK_READ_ONLY false
#endif

View file

@ -0,0 +1,126 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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
#elif (ARCH == ARCH_XMEGA)
/* 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 USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRIHIGH)
// #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 MAX_ENDPOINT_INDEX 4
// #define NO_DEVICE_REMOTE_WAKEUP
// #define NO_DEVICE_SELF_POWER
#else
#error Unsupported architecture for this LUFA configuration file.
#endif
#endif

View file

@ -0,0 +1,194 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 PROGMEM DeviceDescriptor =
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(1,1,0),
.Class = USB_CSCP_NoDeviceClass,
.SubClass = USB_CSCP_NoDeviceSubclass,
.Protocol = USB_CSCP_NoDeviceProtocol,
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
.VendorID = 0x03EB,
.ProductID = 0x2045,
.ReleaseNumber = VERSION_BCD(0,0,1),
.ManufacturerStrIndex = STRING_ID_Manufacturer,
.ProductStrIndex = STRING_ID_Product,
.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 PROGMEM 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 = INTERFACE_ID_MassStorage,
.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 PROGMEM LanguageString = USB_STRING_DESCRIPTOR_ARRAY(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 PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR(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 PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"LUFA Mass Storage Demo");
/** 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 uint16_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 STRING_ID_Language:
Address = &LanguageString;
Size = pgm_read_byte(&LanguageString.Header.Size);
break;
case STRING_ID_Manufacturer:
Address = &ManufacturerString;
Size = pgm_read_byte(&ManufacturerString.Header.Size);
break;
case STRING_ID_Product:
Address = &ProductString;
Size = pgm_read_byte(&ProductString.Header.Size);
break;
}
break;
}
*DescriptorAddress = Address;
return Size;
}

View file

@ -0,0 +1,98 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 <LUFA/Drivers/USB/USB.h>
#include <avr/pgmspace.h>
#include "Config/AppConfig.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;
/** Enum for the device interface descriptor IDs within the device. Each interface descriptor
* should have a unique ID index associated with it, which can be used to refer to the
* interface from other descriptors.
*/
enum InterfaceDescriptors_t
{
INTERFACE_ID_MassStorage = 0, /**< Mass storage interface descriptor ID */
};
/** Enum for the device string descriptor IDs within the device. Each string descriptor should
* have a unique ID index associated with it, which can be used to refer to the string from
* other descriptors.
*/
enum StringDescriptors_t
{
STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */
STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */
STRING_ID_Product = 2, /**< Product string ID */
};
/* Function Prototypes: */
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const uint16_t wIndex,
const void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
#endif

View file

@ -0,0 +1,530 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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
*
* Functions to manage the physical Dataflash media, including reading and writing of
* blocks of data. These functions are called by the SCSI layer when data must be stored
* or retrieved to/from the physical storage media. If a different media is used (such
* as a SD card or EEPROM), functions similar to these will need to be generated.
*/
#define INCLUDE_FROM_DATAFLASHMANAGER_C
#include "DataflashManager.h"
/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board Dataflash IC(s), from
* the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
* them to the Dataflash in Dataflash page sized blocks.
*
* \param[in] BlockAddress Data block starting address for the write sequence
* \param[in] TotalBlocks Number of blocks of data to write
*/
void DataflashManager_WriteBlocks(const uint32_t BlockAddress,
uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
bool UsingSecondBuffer = false;
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* Copy selected dataflash's current page contents to the Dataflash buffer */
Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
#endif
/* Send the Dataflash buffer write command */
Dataflash_SendByte(DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, CurrDFPageByte);
/* Wait until endpoint is ready before continuing */
if (Endpoint_WaitUntilReady())
return;
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the Dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if the endpoint is currently empty */
if (!(Endpoint_IsReadWriteAllowed()))
{
/* Clear the current endpoint bank */
Endpoint_ClearOUT();
/* Wait until the host has sent another packet */
if (Endpoint_WaitUntilReady())
return;
}
/* Check if end of Dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Write the Dataflash buffer contents back to the Dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0);
/* Reset the Dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Once all the Dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
UsingSecondBuffer = !(UsingSecondBuffer);
/* Select the next Dataflash chip based on the new Dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* If less than one Dataflash page remaining, copy over the existing page to preserve trailing data */
if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
{
/* Copy selected dataflash's current page contents to the Dataflash buffer */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
}
#endif
/* Send the Dataflash buffer write command */
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, 0);
}
/* Write one 16-byte chunk of data to the Dataflash */
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
Dataflash_SendByte(Endpoint_Read_8());
/* Increment the Dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* Write the Dataflash buffer contents back to the Dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0x00);
Dataflash_WaitWhileBusy();
/* If the endpoint is empty, clear it ready for the next packet from the host */
if (!(Endpoint_IsReadWriteAllowed()))
Endpoint_ClearOUT();
/* Deselect all Dataflash chips */
Dataflash_DeselectChip();
}
/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board Dataflash IC(s), into
* the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
* and writes them in OS sized blocks to the endpoint.
*
* \param[in] BlockAddress Data block starting address for the read sequence
* \param[in] TotalBlocks Number of blocks of data to read
*/
void DataflashManager_ReadBlocks(const uint32_t BlockAddress,
uint16_t TotalBlocks)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the Dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
/* Wait until endpoint is ready before continuing */
if (Endpoint_WaitUntilReady())
return;
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Read an endpoint packet sized data block from the Dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if the endpoint is currently full */
if (!(Endpoint_IsReadWriteAllowed()))
{
/* Clear the endpoint bank to send its contents to the host */
Endpoint_ClearIN();
/* Wait until the endpoint is ready for more data */
if (Endpoint_WaitUntilReady())
return;
}
/* Check if end of Dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Reset the Dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Select the next Dataflash chip based on the new Dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the Dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
}
/* Read one 16-byte chunk of data from the Dataflash */
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
Endpoint_Write_8(Dataflash_ReceiveByte());
/* Increment the Dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* If the endpoint is full, send its contents to the host */
if (!(Endpoint_IsReadWriteAllowed()))
Endpoint_ClearIN();
/* Deselect all Dataflash chips */
Dataflash_DeselectChip();
}
/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board Dataflash IC(s), from
* the given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
* Dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
* Dataflash.
*
* \param[in] BlockAddress Data block starting address for the write sequence
* \param[in] TotalBlocks Number of blocks of data to write
* \param[in] BufferPtr Pointer to the data source RAM buffer
*/
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress,
uint16_t TotalBlocks,
uint8_t* BufferPtr)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
bool UsingSecondBuffer = false;
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* Copy selected dataflash's current page contents to the Dataflash buffer */
Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
#endif
/* Send the Dataflash buffer write command */
Dataflash_SendByte(DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, CurrDFPageByte);
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Write an endpoint packet sized data block to the Dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if end of Dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Write the Dataflash buffer contents back to the Dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0);
/* Reset the Dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Once all the Dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
UsingSecondBuffer = !(UsingSecondBuffer);
/* Select the next Dataflash chip based on the new Dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
/* If less than one Dataflash page remaining, copy over the existing page to preserve trailing data */
if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
{
/* Copy selected dataflash's current page contents to the Dataflash buffer */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_WaitWhileBusy();
}
#endif
/* Send the Dataflash buffer write command */
Dataflash_ToggleSelectedChipCS();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
Dataflash_SendAddressBytes(0, 0);
}
/* Write one 16-byte chunk of data to the Dataflash */
for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
Dataflash_SendByte(*(BufferPtr++));
/* Increment the Dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* Write the Dataflash buffer contents back to the Dataflash page */
Dataflash_WaitWhileBusy();
Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
Dataflash_SendAddressBytes(CurrDFPage, 0x00);
Dataflash_WaitWhileBusy();
/* Deselect all Dataflash chips */
Dataflash_DeselectChip();
}
/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board Dataflash IC(s), into
* the preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
* and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
* the files stored on the Dataflash.
*
* \param[in] BlockAddress Data block starting address for the read sequence
* \param[in] TotalBlocks Number of blocks of data to read
* \param[out] BufferPtr Pointer to the data destination RAM buffer
*/
void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress,
uint16_t TotalBlocks,
uint8_t* BufferPtr)
{
uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
/* Select the correct starting Dataflash IC for the block requested */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the Dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
while (TotalBlocks)
{
uint8_t BytesInBlockDiv16 = 0;
/* Read an endpoint packet sized data block from the Dataflash */
while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
{
/* Check if end of Dataflash page reached */
if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
{
/* Reset the Dataflash buffer counter, increment the page counter */
CurrDFPageByteDiv16 = 0;
CurrDFPage++;
/* Select the next Dataflash chip based on the new Dataflash page index */
Dataflash_SelectChipFromPage(CurrDFPage);
/* Send the Dataflash main memory page read command */
Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
Dataflash_SendAddressBytes(CurrDFPage, 0);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
Dataflash_SendByte(0x00);
}
/* Read one 16-byte chunk of data from the Dataflash */
for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
*(BufferPtr++) = Dataflash_ReceiveByte();
/* Increment the Dataflash page 16 byte block counter */
CurrDFPageByteDiv16++;
/* Increment the block 16 byte block counter */
BytesInBlockDiv16++;
}
/* Decrement the blocks remaining counter */
TotalBlocks--;
}
/* Deselect all Dataflash chips */
Dataflash_DeselectChip();
}
/** Disables the Dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
void DataflashManager_ResetDataflashProtections(void)
{
/* Select first Dataflash chip, send the read status register command */
Dataflash_SelectChip(DATAFLASH_CHIP1);
Dataflash_SendByte(DF_CMD_GETSTATUS);
/* Check if sector protection is enabled */
if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
{
Dataflash_ToggleSelectedChipCS();
/* Send the commands to disable sector protection */
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
}
/* Select second Dataflash chip (if present on selected board), send read status register command */
#if (DATAFLASH_TOTALCHIPS == 2)
Dataflash_SelectChip(DATAFLASH_CHIP2);
Dataflash_SendByte(DF_CMD_GETSTATUS);
/* Check if sector protection is enabled */
if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
{
Dataflash_ToggleSelectedChipCS();
/* Send the commands to disable sector protection */
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
}
#endif
/* Deselect current Dataflash chip */
Dataflash_DeselectChip();
}
/** Performs a simple test on the attached Dataflash IC(s) to ensure that they are working.
*
* \return Boolean \c true if all media chips are working, \c false otherwise
*/
bool DataflashManager_CheckDataflashOperation(void)
{
uint8_t ReturnByte;
/* Test first Dataflash IC is present and responding to commands */
Dataflash_SelectChip(DATAFLASH_CHIP1);
Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
ReturnByte = Dataflash_ReceiveByte();
Dataflash_DeselectChip();
/* If returned data is invalid, fail the command */
if (ReturnByte != DF_MANUFACTURER_ATMEL)
return false;
#if (DATAFLASH_TOTALCHIPS == 2)
/* Test second Dataflash IC is present and responding to commands */
Dataflash_SelectChip(DATAFLASH_CHIP2);
Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
ReturnByte = Dataflash_ReceiveByte();
Dataflash_DeselectChip();
/* If returned data is invalid, fail the command */
if (ReturnByte != DF_MANUFACTURER_ATMEL)
return false;
#endif
return true;
}

View file

@ -0,0 +1,86 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 DataflashManager.c.
*/
#ifndef _DATAFLASH_MANAGER_H_
#define _DATAFLASH_MANAGER_H_
/* Includes: */
#include <avr/io.h>
#include "../MassStorage.h"
#include "../Descriptors.h"
#include <LUFA/Common/Common.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/Dataflash.h>
/* Preprocessor Checks: */
#if (DATAFLASH_PAGE_SIZE % 16)
#error Dataflash page size must be a multiple of 16 bytes.
#endif
/* Defines: */
/** Total number of bytes of the storage medium, comprised of one or more Dataflash ICs. */
#define VIRTUAL_MEMORY_BYTES ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
/** Block size of the device. This is kept at 512 to remain compatible with the OS despite the underlying
* storage media (Dataflash) using a different native block size. Do not change this value.
*/
#define VIRTUAL_MEMORY_BLOCK_SIZE 512
/** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. Do not
* change this value; change VIRTUAL_MEMORY_BYTES instead to alter the media size.
*/
#define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
/** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
#define LUN_MEDIA_BLOCKS (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
/* Function Prototypes: */
void DataflashManager_WriteBlocks(const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_ReadBlocks(const uint32_t BlockAddress,
uint16_t TotalBlocks);
void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress,
uint16_t TotalBlocks,
uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress,
uint16_t TotalBlocks,
uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
void DataflashManager_ResetDataflashProtections(void);
bool DataflashManager_CheckDataflashOperation(void);
#endif

View file

@ -0,0 +1,344 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 = "Dataflash Disk",
.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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise
*/
bool SCSI_DecodeSCSICommand(void)
{
bool CommandSuccess = false;
/* Run the appropriate SCSI command hander function based on the passed command */
switch (CommandBlock.SCSICommandData[0])
{
case SCSI_CMD_INQUIRY:
CommandSuccess = SCSI_Command_Inquiry();
break;
case SCSI_CMD_REQUEST_SENSE:
CommandSuccess = SCSI_Command_Request_Sense();
break;
case SCSI_CMD_READ_CAPACITY_10:
CommandSuccess = SCSI_Command_Read_Capacity_10();
break;
case SCSI_CMD_SEND_DIAGNOSTIC:
CommandSuccess = SCSI_Command_Send_Diagnostic();
break;
case SCSI_CMD_WRITE_10:
CommandSuccess = SCSI_Command_ReadWrite_10(DATA_WRITE);
break;
case SCSI_CMD_READ_10:
CommandSuccess = SCSI_Command_ReadWrite_10(DATA_READ);
break;
case SCSI_CMD_MODE_SENSE_6:
CommandSuccess = SCSI_Command_ModeSense_6();
break;
case SCSI_CMD_START_STOP_UNIT:
case SCSI_CMD_TEST_UNIT_READY:
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
case SCSI_CMD_VERIFY_10:
/* These commands should just succeed, no handling required */
CommandSuccess = true;
CommandBlock.DataTransferLength = 0;
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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Inquiry(void)
{
uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&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 ((CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
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;
}
/* Write the INQUIRY data to the endpoint */
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 */
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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Request_Sense(void)
{
uint8_t AllocationLength = CommandBlock.SCSICommandData[4];
uint8_t BytesTransferred = MIN(AllocationLength, sizeof(SenseData));
/* Send the SENSE data - this indicates to the host the status of the last command */
Endpoint_Write_Stream_LE(&SenseData, 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 */
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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Read_Capacity_10(void)
{
/* Send the total number of logical blocks in the current LUN */
Endpoint_Write_32_BE(LUN_MEDIA_BLOCKS - 1);
/* Send the logical block size of the device (must be 512 bytes) */
Endpoint_Write_32_BE(VIRTUAL_MEMORY_BLOCK_SIZE);
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
/* Send the endpoint data packet to the host */
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_Send_Diagnostic(void)
{
/* Check to see if the SELF TEST bit is not set */
if (!(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;
}
/* Check to see if all attached Dataflash ICs are functional */
if (!(DataflashManager_CheckDataflashOperation()))
{
/* Update SENSE key with a hardware error condition and return command fail */
SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR,
SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
SCSI_ASENSEQ_NO_QUALIFIER);
return false;
}
/* Succeed the command and update the bytes transferred counter */
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] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_ReadWrite_10(const bool IsDataRead)
{
uint32_t BlockAddress;
uint16_t TotalBlocks;
/* Check if the disk is write protected or not */
if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
{
/* Block address is invalid, update SENSE key and return command fail */
SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
SCSI_ASENSE_WRITE_PROTECTED,
SCSI_ASENSEQ_NO_QUALIFIER);
return false;
}
BlockAddress = SwapEndian_32(*(uint32_t*)&CommandBlock.SCSICommandData[2]);
TotalBlocks = SwapEndian_16(*(uint16_t*)&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;
}
#if (TOTAL_LUNS > 1)
/* Adjust the given block address to the real media address based on the selected LUN */
BlockAddress += ((uint32_t)CommandBlock.LUN * LUN_MEDIA_BLOCKS);
#endif
/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
if (IsDataRead == DATA_READ)
DataflashManager_ReadBlocks(BlockAddress, TotalBlocks);
else
DataflashManager_WriteBlocks(BlockAddress, TotalBlocks);
/* Update the bytes transferred counter and succeed the command */
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.
*
* \return Boolean \c true if the command completed successfully, \c false otherwise.
*/
static bool SCSI_Command_ModeSense_6(void)
{
/* Send an empty header response with the Write Protect flag status */
Endpoint_Write_8(0x00);
Endpoint_Write_8(0x00);
Endpoint_Write_8(DISK_READ_ONLY ? 0x80 : 0x00);
Endpoint_Write_8(0x00);
Endpoint_ClearIN();
/* Update the bytes transferred counter and succeed the command */
CommandBlock.DataTransferLength -= 4;
return true;
}

View file

@ -0,0 +1,150 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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/Common/Common.h>
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include "../MassStorage.h"
#include "../Descriptors.h"
#include "DataflashManager.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) do { SenseData.SenseKey = (Key); \
SenseData.AdditionalSenseCode = (Acode); \
SenseData.AdditionalSenseQualifier = (Aqual); } while (0)
/** 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
/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
#define DEVICE_TYPE_CDROM 0x05
/* Type Defines: */
/** Type define for a SCSI response structure to a SCSI INQUIRY command. For details of the
* structure contents, refer to the SCSI specifications.
*/
typedef struct
{
unsigned DeviceType : 5;
unsigned PeripheralQualifier : 3;
unsigned Reserved : 7;
unsigned Removable : 1;
uint8_t Version;
unsigned ResponseDataFormat : 4;
unsigned Reserved2 : 1;
unsigned NormACA : 1;
unsigned TrmTsk : 1;
unsigned AERC : 1;
uint8_t AdditionalLength;
uint8_t Reserved3[2];
unsigned SoftReset : 1;
unsigned CmdQue : 1;
unsigned Reserved4 : 1;
unsigned Linked : 1;
unsigned Sync : 1;
unsigned WideBus16Bit : 1;
unsigned WideBus32Bit : 1;
unsigned RelAddr : 1;
uint8_t VendorID[8];
uint8_t ProductID[16];
uint8_t RevisionID[4];
} MS_SCSI_Inquiry_Response_t;
/** Type define for a SCSI sense structure to a SCSI REQUEST SENSE command. For details of the
* structure contents, refer to the SCSI specifications.
*/
typedef struct
{
uint8_t ResponseCode;
uint8_t SegmentNumber;
unsigned SenseKey : 4;
unsigned Reserved : 1;
unsigned ILI : 1;
unsigned EOM : 1;
unsigned 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];
} MS_SCSI_Request_Sense_Response_t;
/* Function Prototypes: */
bool SCSI_DecodeSCSICommand(void);
#if defined(INCLUDE_FROM_SCSI_C)
static bool SCSI_Command_Inquiry(void);
static bool SCSI_Command_Request_Sense(void);
static bool SCSI_Command_Read_Capacity_10(void);
static bool SCSI_Command_Send_Diagnostic(void);
static bool SCSI_Command_ReadWrite_10(const bool IsDataRead);
static bool SCSI_Command_ModeSense_6(void);
#endif
#endif

View file

@ -0,0 +1,332 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 Mass Storage demo. This file contains the main tasks of the demo and
* is responsible for the initial application hardware configuration.
*/
#define INCLUDE_FROM_MASSSTORAGE_C
#include "MassStorage.h"
/** Structure to hold the latest Command Block Wrapper issued by the host, containing a SCSI command to execute. */
MS_CommandBlockWrapper_t CommandBlock;
/** Structure to hold the latest Command Status Wrapper to return to the host, containing the status of the last issued command. */
MS_CommandStatusWrapper_t CommandStatus = { .Signature = MS_CSW_SIGNATURE };
/** Flag to asynchronously abort any in-progress data transfers upon the reception of a mass storage reset command. */
volatile bool IsMassStoreReset = false;
/** Main program entry point. This routine configures the hardware required by the application, then
* enters a loop to run the application tasks in sequence.
*/
int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
GlobalInterruptEnable();
for (;;)
{
MassStorage_Task();
USB_USBTask();
}
}
/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
#if (ARCH == ARCH_AVR8)
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF);
wdt_disable();
/* Disable clock division */
clock_prescale_set(clock_div_1);
#elif (ARCH == ARCH_XMEGA)
/* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */
XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU);
XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL);
/* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */
XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ);
XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB);
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
#endif
/* Hardware Initialization */
LEDs_Init();
Dataflash_Init();
USB_Init();
/* Check if the Dataflash is working, abort if not */
if (!(DataflashManager_CheckDataflashOperation()))
{
LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
for(;;);
}
/* Clear Dataflash sector protections, if enabled */
DataflashManager_ResetDataflashProtections();
}
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */
void EVENT_USB_Device_Connect(void)
{
/* Indicate USB enumerating */
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
/* Reset the MSReset flag upon connection */
IsMassStoreReset = false;
}
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
* the status LEDs and stops the Mass Storage management task.
*/
void EVENT_USB_Device_Disconnect(void)
{
/* Indicate USB not ready */
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
* of the USB device after enumeration - the device endpoints are configured and the Mass Storage management task started.
*/
void EVENT_USB_Device_ConfigurationChanged(void)
{
bool ConfigSuccess = true;
/* Setup Mass Storage Data Endpoints */
ConfigSuccess &= Endpoint_ConfigureEndpoint(MASS_STORAGE_IN_EPADDR, EP_TYPE_BULK, MASS_STORAGE_IO_EPSIZE, 1);
ConfigSuccess &= Endpoint_ConfigureEndpoint(MASS_STORAGE_OUT_EPADDR, EP_TYPE_BULK, MASS_STORAGE_IO_EPSIZE, 1);
/* Indicate endpoint configuration success or failure */
LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}
/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
* the device from the USB host before passing along unhandled control requests to the library for processing
* internally.
*/
void EVENT_USB_Device_ControlRequest(void)
{
/* Process UFI specific control requests */
switch (USB_ControlRequest.bRequest)
{
case MS_REQ_MassStorageReset:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
/* Indicate that the current transfer should be aborted */
IsMassStoreReset = true;
}
break;
case MS_REQ_GetMaxLUN:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
/* Indicate to the host the number of supported LUNs (virtual disks) on the device */
Endpoint_Write_8(TOTAL_LUNS - 1);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
}
break;
}
}
/** Task to manage the Mass Storage interface, reading in Command Block Wrappers from the host, processing the SCSI commands they
* contain, and returning Command Status Wrappers back to the host to indicate the success or failure of the last issued command.
*/
void MassStorage_Task(void)
{
/* Device must be connected and configured for the task to run */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
/* Process sent command block from the host if one has been sent */
if (ReadInCommandBlock())
{
/* Indicate busy */
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
/* Check direction of command, select Data IN endpoint if data is from the device */
if (CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN)
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPADDR);
/* Decode the received SCSI command, set returned status code */
CommandStatus.Status = SCSI_DecodeSCSICommand() ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail;
/* Load in the CBW tag into the CSW to link them together */
CommandStatus.Tag = CommandBlock.Tag;
/* Load in the data residue counter into the CSW */
CommandStatus.DataTransferResidue = CommandBlock.DataTransferLength;
/* Stall the selected data pipe if command failed (if data is still to be transferred) */
if ((CommandStatus.Status == MS_SCSI_COMMAND_Fail) && (CommandStatus.DataTransferResidue))
Endpoint_StallTransaction();
/* Return command status block to the host */
ReturnCommandStatus();
/* Indicate ready */
LEDs_SetAllLEDs(LEDMASK_USB_READY);
}
/* Check if a Mass Storage Reset occurred */
if (IsMassStoreReset)
{
/* Reset the data endpoint banks */
Endpoint_ResetEndpoint(MASS_STORAGE_OUT_EPADDR);
Endpoint_ResetEndpoint(MASS_STORAGE_IN_EPADDR);
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPADDR);
Endpoint_ClearStall();
Endpoint_ResetDataToggle();
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPADDR);
Endpoint_ClearStall();
Endpoint_ResetDataToggle();
/* Clear the abort transfer flag */
IsMassStoreReset = false;
}
}
/** Function to read in a command block from the host, via the bulk data OUT endpoint. This function reads in the next command block
* if one has been issued, and performs validation to ensure that the block command is valid.
*
* \return Boolean \c true if a valid command block has been read in from the endpoint, \c false otherwise
*/
static bool ReadInCommandBlock(void)
{
uint16_t BytesTransferred;
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPADDR);
/* Abort if no command has been sent from the host */
if (!(Endpoint_IsOUTReceived()))
return false;
/* Read in command block header */
BytesTransferred = 0;
while (Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)),
&BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
}
/* Verify the command block - abort if invalid */
if ((CommandBlock.Signature != MS_CBW_SIGNATURE) ||
(CommandBlock.LUN >= TOTAL_LUNS) ||
(CommandBlock.Flags & 0x1F) ||
(CommandBlock.SCSICommandLength == 0) ||
(CommandBlock.SCSICommandLength > sizeof(CommandBlock.SCSICommandData)))
{
/* Stall both data pipes until reset by host */
Endpoint_StallTransaction();
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPADDR);
Endpoint_StallTransaction();
return false;
}
/* Read in command block command data */
BytesTransferred = 0;
while (Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData, CommandBlock.SCSICommandLength,
&BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return false;
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
return true;
}
/** Returns the filled Command Status Wrapper back to the host via the bulk data IN endpoint, waiting for the host to clear any
* stalled data endpoints as needed.
*/
static void ReturnCommandStatus(void)
{
uint16_t BytesTransferred;
/* Select the Data Out endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPADDR);
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
while (Endpoint_IsStalled())
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Select the Data In endpoint */
Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPADDR);
/* While data pipe is stalled, wait until the host issues a control request to clear the stall */
while (Endpoint_IsStalled())
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Write the CSW to the endpoint */
BytesTransferred = 0;
while (Endpoint_Write_Stream_LE(&CommandStatus, sizeof(CommandStatus),
&BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer)
{
/* Check if the current command is being aborted by the host */
if (IsMassStoreReset)
return;
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
}

View file

@ -0,0 +1,92 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 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 "Descriptors.h"
#include "Lib/SCSI.h"
#include "Lib/DataflashManager.h"
#include "Config/AppConfig.h"
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Dataflash.h>
#include <LUFA/Platform/Platform.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
/* Global Variables: */
extern MS_CommandBlockWrapper_t CommandBlock;
extern MS_CommandStatusWrapper_t CommandStatus;
extern volatile bool IsMassStoreReset;
/* Function Prototypes: */
void SetupHardware(void);
void MassStorage_Task(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);
#if defined(INCLUDE_FROM_MASSSTORAGE_C)
static bool ReadInCommandBlock(void);
static void ReturnCommandStatus(void);
#endif
#endif

View file

@ -0,0 +1,100 @@
/** \file
*
* This file contains special DoxyGen information for the generation of the main page and other special
* documentation pages. It is not a project source file.
*/
/** \mainpage Mass Storage Device Demo
*
* \section Sec_Compat Demo Compatibility:
*
* The following list indicates what microcontrollers are compatible with this demo.
*
* \li Series 7 USB AVRs (AT90USBxxx7)
* \li Series 6 USB AVRs (AT90USBxxx6)
* \li Series 4 USB AVRs (ATMEGAxxU4)
* \li Series 2 USB AVRs (AT90USBxx2, ATMEGAxxU2)
* \li Series AU XMEGA AVRs (ATXMEGAxxxAxU)
* \li Series B XMEGA AVRs (ATXMEGAxxxBx)
* \li Series C XMEGA AVRs (ATXMEGAxxxCx)
*
* \section Sec_Info USB Information:
*
* The following table gives a rundown of the USB utilization of this demo.
*
* <table>
* <tr>
* <td><b>USB Mode:</b></td>
* <td>Device</td>
* </tr>
* <tr>
* <td><b>USB Class:</b></td>
* <td>Mass Storage Device</td>
* </tr>
* <tr>
* <td><b>USB Subclass:</b></td>
* <td>Bulk-Only Transport</td>
* </tr>
* <tr>
* <td><b>Relevant Standards:</b></td>
* <td>USBIF Mass Storage Standard \n
* USB Bulk-Only Transport Standard \n
* SCSI Primary Commands Specification \n
* SCSI Block Commands Specification</td>
* </tr>
* <tr>
* <td><b>Supported USB Speeds:</b></td>
* <td>Full Speed Mode</td>
* </tr>
* </table>
*
* \section Sec_Description Project Description:
*
* Mass Storage device demonstration application. This gives a simple
* reference application for implementing a USB Mass Storage device using
* the basic USB UFI drivers in all modern OSes (i.e. no special drivers
* required).
*
* On start-up the system will automatically enumerate and function as an
* external mass storage device which may be formatted and used in the same
* manner as commercial USB Mass Storage devices.
*
* You will need to format the mass storage drive upon first run of this
* demonstration - as the device acts only as a data block transport between
* the host and the storage media, it does not matter what file system is used,
* as the data interpretation is performed by the host and not the USB device.
*
* This demo is not restricted to only a single LUN (logical disk); by changing
* the TOTAL_LUNS value in DataflashManager.h, any number of LUNs can be used
* (from 1 to 255), with each LUN being allocated an equal portion of the available
* Dataflash memory.
*
* The USB control endpoint is managed entirely by the library using endpoint
* interrupts, as the INTERRUPT_CONTROL_ENDPOINT option is enabled. This allows for
* the host to reset the Mass Storage device state during long transfers without
* the need for complicated polling logic.
*
* \section Sec_Options Project Options
*
* The following defines can be found in this demo, which can control the demo behaviour when defined, or changed in value.
*
* <table>
* <tr>
* <th><b>Define Name:</b></th>
* <th><b>Location:</b></th>
* <th><b>Description:</b></th>
* </tr>
* <tr>
* <td>TOTAL_LUNS</td>
* <td>AppConfig.h</td>
* <td>Total number of Logical Units (drives) in the device. The total device capacity is shared equally between each drive
* - this can be set to any positive non-zero amount.</td>
* </tr>
* <tr>
* <td>DISK_READ_ONLY</td>
* <td>AppConfig.h</td>
* <td>Indicates if the disk should be write protected or not.</td>
* </tr>
* </table>
*/

View file

@ -0,0 +1,67 @@
<asf xmlversion="1.0">
<project caption="Mass Storage Device Demo (Low Level APIs)" id="lufa.demos.device.lowlevel.mass_storage.example.avr8">
<require idref="lufa.demos.device.lowlevel.mass_storage"/>
<require idref="lufa.boards.dummy.avr8"/>
<generator value="as5_8"/>
<device-support value="at90usb1287"/>
<config name="lufa.drivers.board.name" value="none"/>
<build type="define" name="F_CPU" value="16000000UL"/>
<build type="define" name="F_USB" value="16000000UL"/>
</project>
<project caption="Mass Storage Device Demo (Low Level APIs)" id="lufa.demos.device.lowlevel.mass_storage.example.xmega">
<require idref="lufa.demos.device.lowlevel.mass_storage"/>
<require idref="lufa.boards.dummy.xmega"/>
<generator value="as5_8"/>
<device-support value="atxmega128a1u"/>
<config name="lufa.drivers.board.name" value="none"/>
<build type="define" name="F_CPU" value="32000000UL"/>
<build type="define" name="F_USB" value="48000000UL"/>
</project>
<module type="application" id="lufa.demos.device.lowlevel.mass_storage" caption="Mass Storage Device Demo (Low Level APIs)">
<info type="description" value="summary">
Mass Storage device demo, implementing a basic USB storage disk using a Dataflash memory IC. This demo uses the Low Level LUFA APIs to manually implement a USB Class for demonstration purposes without using the simpler in-built LUFA Class Driver APIs.
</info>
<info type="gui-flag" value="move-to-root"/>
<info type="keyword" value="Technology">
<keyword value="Low Level APIs"/>
<keyword value="USB Device"/>
<keyword value="Mass Storage Class"/>
</info>
<device-support-alias value="lufa_avr8"/>
<device-support-alias value="lufa_xmega"/>
<device-support-alias value="lufa_uc3"/>
<build type="distribute" subtype="user-file" value="doxyfile"/>
<build type="distribute" subtype="user-file" value="MassStorage.txt"/>
<build type="c-source" value="MassStorage.c"/>
<build type="c-source" value="Descriptors.c"/>
<build type="c-source" value="Lib/DataflashManager.c"/>
<build type="c-source" value="Lib/SCSI.c"/>
<build type="header-file" value="MassStorage.h"/>
<build type="header-file" value="Descriptors.h"/>
<build type="header-file" value="Lib/DataflashManager.h"/>
<build type="header-file" value="Lib/SCSI.h"/>
<build type="module-config" subtype="path" value="Config"/>
<build type="module-config" subtype="required-header-file" value="AppConfig.h"/>
<build type="header-file" value="Config/AppConfig.h"/>
<build type="header-file" value="Config/LUFAConfig.h"/>
<require idref="lufa.common"/>
<require idref="lufa.platform"/>
<require idref="lufa.drivers.usb"/>
<require idref="lufa.drivers.board"/>
<require idref="lufa.drivers.board.leds"/>
<require idref="lufa.drivers.board.dataflash"/>
</module>
</asf>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
#
# LUFA Library
# Copyright (C) Dean Camera, 2017.
#
# dean [at] fourwalledcubicle [dot] com
# www.lufa-lib.org
#
# --------------------------------------
# LUFA Project Makefile.
# --------------------------------------
# Run "make help" for target help.
MCU = at90usb1287
ARCH = AVR8
BOARD = USBKEY
F_CPU = 8000000
F_USB = $(F_CPU)
OPTIMIZATION = s
TARGET = MassStorage
SRC = $(TARGET).c Descriptors.c Lib/DataflashManager.c Lib/SCSI.c $(LUFA_SRC_USB)
LUFA_PATH = ../../../../LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
LD_FLAGS =
# Default target
all:
# Include LUFA-specific DMBS extension modules
DMBS_LUFA_PATH ?= $(LUFA_PATH)/Build/LUFA
include $(DMBS_LUFA_PATH)/lufa-sources.mk
include $(DMBS_LUFA_PATH)/lufa-gcc.mk
# Include common DMBS build system modules
DMBS_PATH ?= $(LUFA_PATH)/Build/DMBS/DMBS
include $(DMBS_PATH)/core.mk
include $(DMBS_PATH)/cppcheck.mk
include $(DMBS_PATH)/doxygen.mk
include $(DMBS_PATH)/dfu.mk
include $(DMBS_PATH)/gcc.mk
include $(DMBS_PATH)/hid.mk
include $(DMBS_PATH)/avrdude.mk
include $(DMBS_PATH)/atprogram.mk