1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/mtd_mapper/mtd_mapper.c

131 lines
3.1 KiB
C

/*
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
*
* 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_mapper
* @{
*
* @file
* @brief Driver for flash memory remap support
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#include <stdint.h>
#include <errno.h>
#include "kernel_defines.h"
#include "mtd.h"
#include "mtd_mapper.h"
#include "mutex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static void _unlock(mtd_mapper_region_t *region)
{
mutex_unlock(&region->parent->lock);
}
static void _lock(mtd_mapper_region_t *region)
{
mutex_lock(&region->parent->lock);
}
static uint32_t _region_size(mtd_mapper_region_t *region)
{
return region->mtd.page_size * region->mtd.pages_per_sector *
region->mtd.sector_count;
}
static int _init_target(mtd_mapper_region_t *region)
{
mtd_mapper_parent_t *parent = region->parent;
if (!parent->init) {
parent->init = true;
return mtd_init(parent->mtd);
}
return 0;
}
static int _init(mtd_dev_t *mtd)
{
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
mtd_dev_t *backing_mtd = region->parent->mtd;
/* Configuration sanity checks */
assert(backing_mtd->page_size == region->mtd.page_size);
assert(backing_mtd->pages_per_sector == region->mtd.pages_per_sector);
assert(backing_mtd->sector_count >= region->mtd.sector_count);
/* offset + region size must not exceed the backing device */
assert(region->offset + _region_size(
region) <=
backing_mtd->pages_per_sector * backing_mtd->sector_count *
backing_mtd->page_size);
_lock(region);
int res = _init_target(region);
_unlock(region);
return res;
}
static int _write(mtd_dev_t *mtd, const void *src, uint32_t addr,
uint32_t count)
{
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
if (addr + count > _region_size(region)) {
return -EOVERFLOW;
}
_lock(region);
int res = mtd_write(region->parent->mtd, src, addr + region->offset, count);
_unlock(region);
return res;
}
static int _read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count)
{
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
if (addr + count > _region_size(region)) {
return -EOVERFLOW;
}
_lock(region);
int res = mtd_read(region->parent->mtd, dest, addr + region->offset, count);
_unlock(region);
return res;
}
static int _erase(mtd_dev_t *mtd, uint32_t addr, uint32_t count)
{
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
if (addr + count > _region_size(region)) {
return -EOVERFLOW;
}
_lock(region);
int res = mtd_erase(region->parent->mtd, addr + region->offset, count);
_unlock(region);
return res;
}
const mtd_desc_t mtd_mapper_driver = {
.init = _init,
.read = _read,
.write = _write,
.erase = _erase,
};