mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 00:29:46 +01:00
drivers/mtd_emulatd: MTD emulated in RAM for testing
This driver provides support for MTDs emulated in RAM to test MTD-based applications on boards that do not provide MTDs in hardware.
This commit is contained in:
parent
756197316d
commit
609c090ceb
102
drivers/include/mtd_emulated.h
Normal file
102
drivers/include/mtd_emulated.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mtd
|
||||
* @{
|
||||
* @brief MTD device that is emulated in RAM for test purposes
|
||||
*
|
||||
* Helpers for using emulated MTDs.
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
*/
|
||||
#ifndef MTD_EMULATED_H
|
||||
#define MTD_EMULATED_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "macros/utils.h"
|
||||
#include "mtd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro to define an emulated MTD
|
||||
*
|
||||
* This macro creates a MTD device that is emulated in RAM. For example, using
|
||||
* ```
|
||||
* MTD_EMULATED_DEV(0, 16, 4, 64)
|
||||
* ```
|
||||
* creates the emulated MTD device `mtd_emulated_dev0` with 16 sectors, 4 pages
|
||||
* per sector and a page size of 64 bytes. The write size is always 1 byte.
|
||||
*
|
||||
* @param n index of the emulated MTD (results into symbol `mtd_emulated_devn`)
|
||||
* @param sc sectors of the emulated MTD
|
||||
* @param pps pages per sector of the emulated MTD
|
||||
* @param ps page size in bytes
|
||||
*/
|
||||
#define MTD_EMULATED_DEV(n, sc, pps, ps) \
|
||||
uint8_t _mtd_emulated_memory ## n[sc * pps * ps]; \
|
||||
\
|
||||
mtd_emulated_t mtd_emulated_dev ## n = { \
|
||||
.base = { \
|
||||
.driver = &_mtd_emulated_driver, \
|
||||
.sector_count = sc, \
|
||||
.pages_per_sector = pps, \
|
||||
.page_size = ps, \
|
||||
.write_size = 1, \
|
||||
}, \
|
||||
.size = sc * pps * ps, \
|
||||
.memory = _mtd_emulated_memory ## n, \
|
||||
.init_done = false, \
|
||||
} \
|
||||
|
||||
#if MODULE_VFS_AUTO_MOUNT || DOXYGEN
|
||||
/**
|
||||
* @brief Macro to define an automatic VFS mount point for an emulated MTD.
|
||||
*
|
||||
* For example, using
|
||||
* ```
|
||||
* MTD_EMULATED_DEV_FS(0, 2, fatfs);
|
||||
* ```
|
||||
* automatically mounts the emulated MTD `mtd_emulated_dev0` with FAT file
|
||||
* system under mount point `/mtde0` with unique index 2.
|
||||
*
|
||||
* @param n index of the emulated MTD (symbol `mtd_emulated_devn`, mount point `/mtde0`)
|
||||
* @param m unique overall index of VFS mount point
|
||||
* @param fs filesystem type used
|
||||
*/
|
||||
#define MTD_EMULATED_DEV_FS(n, m, fs) \
|
||||
VFS_AUTO_MOUNT(fs, VFS_MTD(mtd_emulated_dev ## n), "/mtde" # n, m)
|
||||
|
||||
#endif /* MODULE_VFS || DOXYGEN */
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for a MTD device that is emulated in RAM
|
||||
*/
|
||||
typedef struct {
|
||||
mtd_dev_t base; /**< inherit from mtd_dev_t object */
|
||||
size_t size; /**< total size of the MTD device in bytes */
|
||||
uint8_t *memory; /**< RAM that is used for the emulated MTD device */
|
||||
bool init_done; /**< indicates whether initialization is already done */
|
||||
} mtd_emulated_t;
|
||||
|
||||
/**
|
||||
* @brief Emulated MTD device operations table for mtd
|
||||
*/
|
||||
extern const mtd_desc_t _mtd_emulated_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MTD_EMULATED_H */
|
||||
/** @} */
|
@ -105,6 +105,9 @@ config MODULE_MTD_SDCARD
|
||||
bool "MTD interface for SPI SD-Card"
|
||||
depends on MODULE_SDCARD_SPI
|
||||
|
||||
config MODULE_MTD_EMULATED
|
||||
bool "MTD interface for MTD emulated in RAM"
|
||||
|
||||
config MODULE_SAM0_SDHC
|
||||
bool "MTD interface for SAM0 SD Host Controller"
|
||||
depends on CPU_COMMON_SAM0
|
||||
|
1
drivers/mtd_emulated/Makefile
Normal file
1
drivers/mtd_emulated/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
161
drivers/mtd_emulated/mtd_emulated.c
Normal file
161
drivers/mtd_emulated/mtd_emulated.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "macros/utils.h"
|
||||
#include "mtd_emulated.h"
|
||||
|
||||
static int _init(mtd_dev_t *dev)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
assert(mtd);
|
||||
|
||||
if (!mtd->init_done) {
|
||||
memset(mtd->memory, 0xff, mtd->size);
|
||||
mtd->init_done = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read(mtd_dev_t *dev, void *dest, uint32_t addr, uint32_t count)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
assert(mtd);
|
||||
assert(dest);
|
||||
|
||||
if ((addr + count) > mtd->size) {
|
||||
/* addr + count must not exceed the size of memory */
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
memcpy(dest, mtd->memory + addr, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read_page(mtd_dev_t *dev, void *dest,
|
||||
uint32_t page, uint32_t offset, uint32_t size)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
(void)mtd;
|
||||
|
||||
assert(mtd);
|
||||
assert(dest);
|
||||
|
||||
if (((page * mtd->base.page_size) + offset + size) > mtd->size) {
|
||||
/* page addr + offset + size must not exceed the size of memory */
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
memcpy(dest, mtd->memory + (page * mtd->base.page_size) + offset, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int _write(mtd_dev_t *dev, const void *src, uint32_t addr, uint32_t count)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
(void)mtd;
|
||||
|
||||
assert(mtd);
|
||||
assert(src);
|
||||
|
||||
if (/* addr + count must be inside a page boundary. */
|
||||
(((addr % mtd->base.page_size) + count) > mtd->base.page_size) ||
|
||||
/* addr + count must not exceed the size of memory */
|
||||
((addr + count) > mtd->size)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
memcpy(mtd->memory + addr, src, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _write_page(mtd_dev_t *dev, const void *src,
|
||||
uint32_t page, uint32_t offset, uint32_t size)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
(void)mtd;
|
||||
|
||||
assert(mtd);
|
||||
assert(src);
|
||||
|
||||
if (/* offset must be smaller than the page size */
|
||||
(offset >= mtd->base.page_size) ||
|
||||
/* page addr + offset + size must not exceed the size of memory */
|
||||
((page * mtd->base.page_size) + offset + size) > mtd->size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
memcpy(mtd->memory + (page * mtd->base.page_size) + offset, src, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t count)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
(void)mtd;
|
||||
assert(mtd);
|
||||
|
||||
if (/* addr must be aligned on a sector boundary */
|
||||
(addr % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) ||
|
||||
/* count must be a multiple of a sector size. */
|
||||
(count % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) ||
|
||||
/* addr + count must not exceed the size of memory */
|
||||
((addr + count) > mtd->size)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
memset(mtd->memory + addr, 0xff, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t num)
|
||||
{
|
||||
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
||||
|
||||
(void)mtd;
|
||||
assert(mtd);
|
||||
|
||||
if (/* sector must not exceed the number of sectors */
|
||||
(sector >= mtd->base.sector_count) ||
|
||||
/* sector + num must not exceed the number of sectors */
|
||||
((sector + num) > mtd->base.sector_count)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
memset(mtd->memory + (sector * (mtd->base.pages_per_sector * mtd->base.page_size)),
|
||||
0xff, num * (mtd->base.pages_per_sector * mtd->base.page_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
|
||||
{
|
||||
(void)dev;
|
||||
(void)power;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const mtd_desc_t _mtd_emulated_driver = {
|
||||
.init = _init,
|
||||
.read = _read,
|
||||
.read_page = _read_page,
|
||||
.write = _write,
|
||||
.write_page = _write_page,
|
||||
.erase = _erase,
|
||||
.erase_sector = _erase_sector,
|
||||
.power = _power,
|
||||
};
|
Loading…
Reference in New Issue
Block a user