1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/mtd_emulated/mtd_emulated.c
Gunar Schorcht 609c090ceb 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.
2023-04-11 17:42:10 +02:00

162 lines
4.0 KiB
C

/*
* 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,
};