/***************************************************************************** * * \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-2018 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * Subject to your compliance with these terms, you may use Microchip * software and any derivatives exclusively with Microchip products. * It is your responsibility to comply with third party license terms applicable * to your use of third party software (including open source software) that * may accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * \asf_license_stop * ******************************************************************************/ /* * Support and FAQ: visit Microchip Support */ //_____ 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 == true