Add svn:eol-style property to source files, so that the line endings are correctly converted to the target system's native end of line style.
This commit is contained in:
parent
e331b531c6
commit
071e02c6b6
839 changed files with 274562 additions and 274562 deletions
|
@ -1,492 +1,492 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* 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] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
|
||||
* \param[in] BlockAddress Data block starting address for the write sequence
|
||||
* \param[in] TotalBlocks Number of blocks of data to write
|
||||
*/
|
||||
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
|
||||
/* 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 (MSInterfaceInfo->State.IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decrement the blocks remaining counter and reset the sub block 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] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
|
||||
* \param[in] BlockAddress Data block starting address for the read sequence
|
||||
* \param[in] TotalBlocks Number of blocks of data to read
|
||||
*/
|
||||
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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;
|
||||
|
||||
/* Write an endpoint packet sized data block to 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_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(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 (MSInterfaceInfo->State.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 a 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(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 and reset the sub block 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 a 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;
|
||||
|
||||
/* 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))
|
||||
{
|
||||
/* 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();
|
||||
}
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* 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] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
|
||||
* \param[in] BlockAddress Data block starting address for the write sequence
|
||||
* \param[in] TotalBlocks Number of blocks of data to write
|
||||
*/
|
||||
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
Dataflash_SendByte(Endpoint_Read_Byte());
|
||||
|
||||
/* 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 (MSInterfaceInfo->State.IsMassStoreReset)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decrement the blocks remaining counter and reset the sub block 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] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
|
||||
* \param[in] BlockAddress Data block starting address for the read sequence
|
||||
* \param[in] TotalBlocks Number of blocks of data to read
|
||||
*/
|
||||
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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;
|
||||
|
||||
/* Write an endpoint packet sized data block to 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_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(Dataflash_ReceiveByte());
|
||||
Endpoint_Write_Byte(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 (MSInterfaceInfo->State.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 a 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(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 and reset the sub block 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 a 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;
|
||||
|
||||
/* 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))
|
||||
{
|
||||
/* 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();
|
||||
}
|
||||
|
|
|
@ -1,77 +1,77 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for DataflashManager.c.
|
||||
*/
|
||||
|
||||
#ifndef _DATAFLASH_MANAGER_H_
|
||||
#define _DATAFLASH_MANAGER_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
|
||||
#include "MassStorageKeyboard.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.
|
||||
*/
|
||||
#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. */
|
||||
#define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
|
||||
|
||||
/* Function Prototypes: */
|
||||
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
|
||||
uint16_t TotalBlocks);
|
||||
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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);
|
||||
|
||||
#endif
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for DataflashManager.c.
|
||||
*/
|
||||
|
||||
#ifndef _DATAFLASH_MANAGER_H_
|
||||
#define _DATAFLASH_MANAGER_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
|
||||
#include "MassStorageKeyboard.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.
|
||||
*/
|
||||
#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. */
|
||||
#define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
|
||||
|
||||
/* Function Prototypes: */
|
||||
void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress,
|
||||
uint16_t TotalBlocks);
|
||||
void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, 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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,345 +1,345 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* 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_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* MSInterfaceInfo)
|
||||
{
|
||||
uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 8) |
|
||||
MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]);
|
||||
uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? 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, NO_STREAM_CALLBACK);
|
||||
|
||||
uint8_t PadBytes[AllocationLength - BytesTransferred];
|
||||
|
||||
/* Pad out remaining bytes with 0x00 */
|
||||
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
|
||||
|
||||
/* 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* MSInterfaceInfo)
|
||||
{
|
||||
uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
|
||||
uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
|
||||
|
||||
uint8_t PadBytes[AllocationLength - BytesTransferred];
|
||||
|
||||
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
|
||||
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* MSInterfaceInfo)
|
||||
{
|
||||
uint32_t LastBlockAddressInLUN = (LUN_MEDIA_BLOCKS - 1);
|
||||
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
|
||||
|
||||
Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
|
||||
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* MSInterfaceInfo)
|
||||
{
|
||||
uint8_t ReturnByte;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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* MSInterfaceInfo, const bool IsDataRead)
|
||||
{
|
||||
uint32_t BlockAddress;
|
||||
uint16_t TotalBlocks;
|
||||
|
||||
/* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */
|
||||
((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[2];
|
||||
((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[3];
|
||||
((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
|
||||
((uint8_t*)&BlockAddress)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[5];
|
||||
|
||||
/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */
|
||||
((uint8_t*)&TotalBlocks)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[7];
|
||||
((uint8_t*)&TotalBlocks)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[8];
|
||||
|
||||
/* 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)MSInterfaceInfo->State.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(MSInterfaceInfo, BlockAddress, TotalBlocks);
|
||||
else
|
||||
DataflashManager_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;
|
||||
}
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* 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_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* MSInterfaceInfo)
|
||||
{
|
||||
uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 8) |
|
||||
MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]);
|
||||
uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? 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, NO_STREAM_CALLBACK);
|
||||
|
||||
uint8_t PadBytes[AllocationLength - BytesTransferred];
|
||||
|
||||
/* Pad out remaining bytes with 0x00 */
|
||||
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
|
||||
|
||||
/* 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* MSInterfaceInfo)
|
||||
{
|
||||
uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
|
||||
uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
|
||||
|
||||
uint8_t PadBytes[AllocationLength - BytesTransferred];
|
||||
|
||||
Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK);
|
||||
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* MSInterfaceInfo)
|
||||
{
|
||||
uint32_t LastBlockAddressInLUN = (LUN_MEDIA_BLOCKS - 1);
|
||||
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
|
||||
|
||||
Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NO_STREAM_CALLBACK);
|
||||
Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
|
||||
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* MSInterfaceInfo)
|
||||
{
|
||||
uint8_t ReturnByte;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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* MSInterfaceInfo, const bool IsDataRead)
|
||||
{
|
||||
uint32_t BlockAddress;
|
||||
uint16_t TotalBlocks;
|
||||
|
||||
/* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */
|
||||
((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[2];
|
||||
((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[3];
|
||||
((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
|
||||
((uint8_t*)&BlockAddress)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[5];
|
||||
|
||||
/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */
|
||||
((uint8_t*)&TotalBlocks)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[7];
|
||||
((uint8_t*)&TotalBlocks)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[8];
|
||||
|
||||
/* 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)MSInterfaceInfo->State.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(MSInterfaceInfo, BlockAddress, TotalBlocks);
|
||||
else
|
||||
DataflashManager_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;
|
||||
}
|
||||
|
|
|
@ -1,87 +1,87 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for SCSI.c.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_H_
|
||||
#define _SCSI_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/MassStorage.h>
|
||||
|
||||
#include "MassStorageKeyboard.h"
|
||||
#include "Descriptors.h"
|
||||
#include "DataflashManager.h"
|
||||
#include "SCSI_Codes.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 SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
|
||||
#define DATA_READ true
|
||||
|
||||
/** Macro for the 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
|
||||
|
||||
/* Function Prototypes: */
|
||||
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
|
||||
#if defined(INCLUDE_FROM_SCSI_C)
|
||||
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for SCSI.c.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_H_
|
||||
#define _SCSI_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Drivers/USB/Class/MassStorage.h>
|
||||
|
||||
#include "MassStorageKeyboard.h"
|
||||
#include "Descriptors.h"
|
||||
#include "DataflashManager.h"
|
||||
#include "SCSI_Codes.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 SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
|
||||
#define DATA_READ true
|
||||
|
||||
/** Macro for the 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
|
||||
|
||||
/* Function Prototypes: */
|
||||
bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
|
||||
#if defined(INCLUDE_FROM_SCSI_C)
|
||||
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* MSInterfaceInfo);
|
||||
static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,85 +1,85 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header containing macros for possible SCSI commands and SENSE data. Refer to
|
||||
* the SCSI standard documentation for more information on each SCSI command and
|
||||
* the SENSE data.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_CODES_H_
|
||||
#define _SCSI_CODES_H_
|
||||
|
||||
/* Macros: */
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
||||
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_VERIFY_10 0x2F
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
|
||||
#define SCSI_SENSE_KEY_GOOD 0x00
|
||||
#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
|
||||
#define SCSI_SENSE_KEY_NOT_READY 0x02
|
||||
#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
|
||||
#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
|
||||
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
|
||||
#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
|
||||
#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
|
||||
#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
|
||||
#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
|
||||
#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
|
||||
#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
|
||||
#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
|
||||
#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
|
||||
|
||||
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
|
||||
#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
|
||||
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
|
||||
#define SCSI_ASENSE_WRITE_PROTECTED 0x27
|
||||
#define SCSI_ASENSE_FORMAT_ERROR 0x31
|
||||
#define SCSI_ASENSE_INVALID_COMMAND 0x20
|
||||
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
|
||||
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
|
||||
|
||||
#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
|
||||
#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
|
||||
#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
|
||||
#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
|
||||
|
||||
#endif
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2010.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.fourwalledcubicle.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2010 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 disclaim all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header containing macros for possible SCSI commands and SENSE data. Refer to
|
||||
* the SCSI standard documentation for more information on each SCSI command and
|
||||
* the SENSE data.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_CODES_H_
|
||||
#define _SCSI_CODES_H_
|
||||
|
||||
/* Macros: */
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
||||
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_VERIFY_10 0x2F
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
|
||||
#define SCSI_SENSE_KEY_GOOD 0x00
|
||||
#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
|
||||
#define SCSI_SENSE_KEY_NOT_READY 0x02
|
||||
#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
|
||||
#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
|
||||
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
|
||||
#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
|
||||
#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
|
||||
#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
|
||||
#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
|
||||
#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
|
||||
#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
|
||||
#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
|
||||
#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
|
||||
|
||||
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
|
||||
#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
|
||||
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
|
||||
#define SCSI_ASENSE_WRITE_PROTECTED 0x27
|
||||
#define SCSI_ASENSE_FORMAT_ERROR 0x31
|
||||
#define SCSI_ASENSE_INVALID_COMMAND 0x20
|
||||
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
|
||||
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
|
||||
|
||||
#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
|
||||
#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
|
||||
#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
|
||||
#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue