648 lines
13 KiB
C
648 lines
13 KiB
C
/*****************************************************************************
|
|
*
|
|
* \file
|
|
*
|
|
* \brief Abstraction layer for memory interfaces.
|
|
*
|
|
* This module contains the interfaces:
|
|
* - MEM <-> USB;
|
|
* - MEM <-> RAM;
|
|
* - MEM <-> MEM.
|
|
*
|
|
* This module may be configured and expanded to support the following features:
|
|
* - write-protected globals;
|
|
* - password-protected data;
|
|
* - specific features;
|
|
* - etc.
|
|
*
|
|
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. The name of Atmel may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* 4. This software may only be redistributed and used in connection with an
|
|
* Atmel microcontroller product.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
******************************************************************************/
|
|
/*
|
|
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
|
|
*/
|
|
|
|
#ifdef ARDUINO_ARCH_SAM
|
|
|
|
//_____ I N C L U D E S ____________________________________________________
|
|
|
|
#include "compiler.h"
|
|
#include "preprocessor.h"
|
|
#ifdef FREERTOS_USED
|
|
#include "FreeRTOS.h"
|
|
#include "semphr.h"
|
|
#endif
|
|
#include "ctrl_access.h"
|
|
|
|
|
|
//_____ D E F I N I T I O N S ______________________________________________
|
|
|
|
#ifdef FREERTOS_USED
|
|
|
|
/*! \name LUN Access Protection Macros
|
|
*/
|
|
//! @{
|
|
|
|
/*! \brief Locks accesses to LUNs.
|
|
*
|
|
* \return \c true if the access was successfully locked, else \c false.
|
|
*/
|
|
#define Ctrl_access_lock() ctrl_access_lock()
|
|
|
|
/*! \brief Unlocks accesses to LUNs.
|
|
*/
|
|
#define Ctrl_access_unlock() xSemaphoreGive(ctrl_access_semphr)
|
|
|
|
//! @}
|
|
|
|
//! Handle to the semaphore protecting accesses to LUNs.
|
|
static xSemaphoreHandle ctrl_access_semphr = NULL;
|
|
|
|
#else
|
|
|
|
/*! \name LUN Access Protection Macros
|
|
*/
|
|
//! @{
|
|
|
|
/*! \brief Locks accesses to LUNs.
|
|
*
|
|
* \return \c true if the access was successfully locked, else \c false.
|
|
*/
|
|
#define Ctrl_access_lock() true
|
|
|
|
/*! \brief Unlocks accesses to LUNs.
|
|
*/
|
|
#define Ctrl_access_unlock()
|
|
|
|
//! @}
|
|
|
|
#endif // FREERTOS_USED
|
|
|
|
|
|
#if MAX_LUN
|
|
|
|
/*! \brief Initializes an entry of the LUN descriptor table.
|
|
*
|
|
* \param lun Logical Unit Number.
|
|
*
|
|
* \return LUN descriptor table entry initializer.
|
|
*/
|
|
#if ACCESS_USB == true && ACCESS_MEM_TO_RAM == true
|
|
#define Lun_desc_entry(lun) \
|
|
{\
|
|
TPASTE3(Lun_, lun, _test_unit_ready),\
|
|
TPASTE3(Lun_, lun, _read_capacity),\
|
|
TPASTE3(Lun_, lun, _unload),\
|
|
TPASTE3(Lun_, lun, _wr_protect),\
|
|
TPASTE3(Lun_, lun, _removal),\
|
|
TPASTE3(Lun_, lun, _usb_read_10),\
|
|
TPASTE3(Lun_, lun, _usb_write_10),\
|
|
TPASTE3(Lun_, lun, _mem_2_ram),\
|
|
TPASTE3(Lun_, lun, _ram_2_mem),\
|
|
TPASTE3(LUN_, lun, _NAME)\
|
|
}
|
|
#elif ACCESS_USB == true
|
|
#define Lun_desc_entry(lun) \
|
|
{\
|
|
TPASTE3(Lun_, lun, _test_unit_ready),\
|
|
TPASTE3(Lun_, lun, _read_capacity),\
|
|
TPASTE3(Lun_, lun, _unload),\
|
|
TPASTE3(Lun_, lun, _wr_protect),\
|
|
TPASTE3(Lun_, lun, _removal),\
|
|
TPASTE3(Lun_, lun, _usb_read_10),\
|
|
TPASTE3(Lun_, lun, _usb_write_10),\
|
|
TPASTE3(LUN_, lun, _NAME)\
|
|
}
|
|
#elif ACCESS_MEM_TO_RAM == true
|
|
#define Lun_desc_entry(lun) \
|
|
{\
|
|
TPASTE3(Lun_, lun, _test_unit_ready),\
|
|
TPASTE3(Lun_, lun, _read_capacity),\
|
|
TPASTE3(Lun_, lun, _unload),\
|
|
TPASTE3(Lun_, lun, _wr_protect),\
|
|
TPASTE3(Lun_, lun, _removal),\
|
|
TPASTE3(Lun_, lun, _mem_2_ram),\
|
|
TPASTE3(Lun_, lun, _ram_2_mem),\
|
|
TPASTE3(LUN_, lun, _NAME)\
|
|
}
|
|
#else
|
|
#define Lun_desc_entry(lun) \
|
|
{\
|
|
TPASTE3(Lun_, lun, _test_unit_ready),\
|
|
TPASTE3(Lun_, lun, _read_capacity),\
|
|
TPASTE3(Lun_, lun, _unload),\
|
|
TPASTE3(Lun_, lun, _wr_protect),\
|
|
TPASTE3(Lun_, lun, _removal),\
|
|
TPASTE3(LUN_, lun, _NAME)\
|
|
}
|
|
#endif
|
|
|
|
//! LUN descriptor table.
|
|
static const struct
|
|
{
|
|
Ctrl_status (*test_unit_ready)(void);
|
|
Ctrl_status (*read_capacity)(U32 *);
|
|
bool (*unload)(bool);
|
|
bool (*wr_protect)(void);
|
|
bool (*removal)(void);
|
|
#if ACCESS_USB == true
|
|
Ctrl_status (*usb_read_10)(U32, U16);
|
|
Ctrl_status (*usb_write_10)(U32, U16);
|
|
#endif
|
|
#if ACCESS_MEM_TO_RAM == true
|
|
Ctrl_status (*mem_2_ram)(U32, void *);
|
|
Ctrl_status (*ram_2_mem)(U32, const void *);
|
|
#endif
|
|
const char *name;
|
|
} lun_desc[MAX_LUN] =
|
|
{
|
|
#if LUN_0 == ENABLE
|
|
# ifndef Lun_0_unload
|
|
# define Lun_0_unload NULL
|
|
# endif
|
|
Lun_desc_entry(0),
|
|
#endif
|
|
#if LUN_1 == ENABLE
|
|
# ifndef Lun_1_unload
|
|
# define Lun_1_unload NULL
|
|
# endif
|
|
Lun_desc_entry(1),
|
|
#endif
|
|
#if LUN_2 == ENABLE
|
|
# ifndef Lun_2_unload
|
|
# define Lun_2_unload NULL
|
|
# endif
|
|
Lun_desc_entry(2),
|
|
#endif
|
|
#if LUN_3 == ENABLE
|
|
# ifndef Lun_3_unload
|
|
# define Lun_3_unload NULL
|
|
# endif
|
|
Lun_desc_entry(3),
|
|
#endif
|
|
#if LUN_4 == ENABLE
|
|
# ifndef Lun_4_unload
|
|
# define Lun_4_unload NULL
|
|
# endif
|
|
Lun_desc_entry(4),
|
|
#endif
|
|
#if LUN_5 == ENABLE
|
|
# ifndef Lun_5_unload
|
|
# define Lun_5_unload NULL
|
|
# endif
|
|
Lun_desc_entry(5),
|
|
#endif
|
|
#if LUN_6 == ENABLE
|
|
# ifndef Lun_6_unload
|
|
# define Lun_6_unload NULL
|
|
# endif
|
|
Lun_desc_entry(6),
|
|
#endif
|
|
#if LUN_7 == ENABLE
|
|
# ifndef Lun_7_unload
|
|
# define Lun_7_unload NULL
|
|
# endif
|
|
Lun_desc_entry(7)
|
|
#endif
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
#if GLOBAL_WR_PROTECT == true
|
|
bool g_wr_protect;
|
|
#endif
|
|
|
|
|
|
/*! \name Control Interface
|
|
*/
|
|
//! @{
|
|
|
|
|
|
#ifdef FREERTOS_USED
|
|
|
|
bool ctrl_access_init(void)
|
|
{
|
|
// If the handle to the protecting semaphore is not valid,
|
|
if (!ctrl_access_semphr)
|
|
{
|
|
// try to create the semaphore.
|
|
vSemaphoreCreateBinary(ctrl_access_semphr);
|
|
|
|
// If the semaphore could not be created, there is no backup solution.
|
|
if (!ctrl_access_semphr) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*! \brief Locks accesses to LUNs.
|
|
*
|
|
* \return \c true if the access was successfully locked, else \c false.
|
|
*/
|
|
static bool ctrl_access_lock(void)
|
|
{
|
|
// If the semaphore could not be created, there is no backup solution.
|
|
if (!ctrl_access_semphr) return false;
|
|
|
|
// Wait for the semaphore.
|
|
while (!xSemaphoreTake(ctrl_access_semphr, portMAX_DELAY));
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // FREERTOS_USED
|
|
|
|
|
|
U8 get_nb_lun(void)
|
|
{
|
|
#if MEM_USB == ENABLE
|
|
# ifndef Lun_usb_get_lun
|
|
# define Lun_usb_get_lun() host_get_lun()
|
|
# endif
|
|
U8 nb_lun;
|
|
|
|
if (!Ctrl_access_lock()) return MAX_LUN;
|
|
|
|
nb_lun = MAX_LUN + Lun_usb_get_lun();
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return nb_lun;
|
|
#else
|
|
return MAX_LUN;
|
|
#endif
|
|
}
|
|
|
|
|
|
U8 get_cur_lun(void)
|
|
{
|
|
return LUN_ID_0;
|
|
}
|
|
|
|
|
|
Ctrl_status mem_test_unit_ready(U8 lun)
|
|
{
|
|
Ctrl_status status;
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].test_unit_ready() :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_test_unit_ready(lun - LUN_ID_USB);
|
|
#else
|
|
CTRL_FAIL;
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
Ctrl_status mem_read_capacity(U8 lun, U32 *u32_nb_sector)
|
|
{
|
|
Ctrl_status status;
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].read_capacity(u32_nb_sector) :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_read_capacity(lun - LUN_ID_USB, u32_nb_sector);
|
|
#else
|
|
CTRL_FAIL;
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
U8 mem_sector_size(U8 lun)
|
|
{
|
|
U8 sector_size;
|
|
|
|
if (!Ctrl_access_lock()) return 0;
|
|
|
|
sector_size =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? 1 :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_read_sector_size(lun - LUN_ID_USB);
|
|
#else
|
|
0;
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return sector_size;
|
|
}
|
|
|
|
|
|
bool mem_unload(U8 lun, bool unload)
|
|
{
|
|
bool unloaded;
|
|
#if !MAX_LUN || !defined(Lun_usb_unload)
|
|
UNUSED(lun);
|
|
#endif
|
|
|
|
if (!Ctrl_access_lock()) return false;
|
|
|
|
unloaded =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ?
|
|
(lun_desc[lun].unload ?
|
|
lun_desc[lun].unload(unload) : !unload) :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
# if defined(Lun_usb_unload)
|
|
Lun_usb_unload(lun - LUN_ID_USB, unload);
|
|
# else
|
|
!unload; /* Can not unload: load success, unload fail */
|
|
# endif
|
|
#else
|
|
false; /* No mem, unload/load fail */
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return unloaded;
|
|
}
|
|
|
|
bool mem_wr_protect(U8 lun)
|
|
{
|
|
bool wr_protect;
|
|
|
|
if (!Ctrl_access_lock()) return true;
|
|
|
|
wr_protect =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].wr_protect() :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_wr_protect(lun - LUN_ID_USB);
|
|
#else
|
|
true;
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return wr_protect;
|
|
}
|
|
|
|
|
|
bool mem_removal(U8 lun)
|
|
{
|
|
bool removal;
|
|
#if MAX_LUN==0
|
|
UNUSED(lun);
|
|
#endif
|
|
|
|
if (!Ctrl_access_lock()) return true;
|
|
|
|
removal =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].removal() :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_removal();
|
|
#else
|
|
true;
|
|
#endif
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return removal;
|
|
}
|
|
|
|
|
|
const char *mem_name(U8 lun)
|
|
{
|
|
#if MAX_LUN==0
|
|
UNUSED(lun);
|
|
#endif
|
|
return
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].name :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
LUN_USB_NAME;
|
|
#else
|
|
NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
//! @}
|
|
|
|
|
|
#if ACCESS_USB == true
|
|
|
|
/*! \name MEM <-> USB Interface
|
|
*/
|
|
//! @{
|
|
|
|
|
|
Ctrl_status memory_2_usb(U8 lun, U32 addr, U16 nb_sector)
|
|
{
|
|
Ctrl_status status;
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
memory_start_read_action(nb_sector);
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].usb_read_10(addr, nb_sector) :
|
|
#endif
|
|
CTRL_FAIL;
|
|
memory_stop_read_action();
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector)
|
|
{
|
|
Ctrl_status status;
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
memory_start_write_action(nb_sector);
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].usb_write_10(addr, nb_sector) :
|
|
#endif
|
|
CTRL_FAIL;
|
|
memory_stop_write_action();
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//! @}
|
|
|
|
#endif // ACCESS_USB == true
|
|
|
|
|
|
#if ACCESS_MEM_TO_RAM == true
|
|
|
|
/*! \name MEM <-> RAM Interface
|
|
*/
|
|
//! @{
|
|
|
|
|
|
Ctrl_status memory_2_ram(U8 lun, U32 addr, void *ram)
|
|
{
|
|
Ctrl_status status;
|
|
#if MAX_LUN==0
|
|
UNUSED(lun);
|
|
#endif
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
memory_start_read_action(1);
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].mem_2_ram(addr, ram) :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_mem_2_ram(addr, ram);
|
|
#else
|
|
CTRL_FAIL;
|
|
#endif
|
|
memory_stop_read_action();
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram)
|
|
{
|
|
Ctrl_status status;
|
|
#if MAX_LUN==0
|
|
UNUSED(lun);
|
|
#endif
|
|
|
|
if (!Ctrl_access_lock()) return CTRL_FAIL;
|
|
|
|
memory_start_write_action(1);
|
|
status =
|
|
#if MAX_LUN
|
|
(lun < MAX_LUN) ? lun_desc[lun].ram_2_mem(addr, ram) :
|
|
#endif
|
|
#if LUN_USB == ENABLE
|
|
Lun_usb_ram_2_mem(addr, ram);
|
|
#else
|
|
CTRL_FAIL;
|
|
#endif
|
|
memory_stop_write_action();
|
|
|
|
Ctrl_access_unlock();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//! @}
|
|
|
|
#endif // ACCESS_MEM_TO_RAM == true
|
|
|
|
|
|
#if ACCESS_STREAM == true
|
|
|
|
/*! \name Streaming MEM <-> MEM Interface
|
|
*/
|
|
//! @{
|
|
|
|
|
|
#if ACCESS_MEM_TO_MEM == true
|
|
|
|
#include "fat.h"
|
|
|
|
Ctrl_status stream_mem_to_mem(U8 src_lun, U32 src_addr, U8 dest_lun, U32 dest_addr, U16 nb_sector)
|
|
{
|
|
COMPILER_ALIGNED(4)
|
|
static U8 sector_buf[FS_512B];
|
|
Ctrl_status status = CTRL_GOOD;
|
|
|
|
while (nb_sector--)
|
|
{
|
|
if ((status = memory_2_ram(src_lun, src_addr++, sector_buf)) != CTRL_GOOD) break;
|
|
if ((status = ram_2_memory(dest_lun, dest_addr++, sector_buf)) != CTRL_GOOD) break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif // ACCESS_MEM_TO_MEM == true
|
|
|
|
|
|
Ctrl_status stream_state(U8 id)
|
|
{
|
|
UNUSED(id);
|
|
return CTRL_GOOD;
|
|
}
|
|
|
|
|
|
U16 stream_stop(U8 id)
|
|
{
|
|
UNUSED(id);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//! @}
|
|
|
|
#endif // ACCESS_STREAM
|
|
|
|
#endif // ARDUINO_ARCH_SAM
|