210 lines
4.8 KiB
C
210 lines
4.8 KiB
C
/*
|
|
* Copyright (c) 2019 Vestas Wind Systems A/S
|
|
*
|
|
* Heavily based on flash_native_posix.c, which is:
|
|
* Copyright (c) 2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <drivers/eeprom.h>
|
|
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "cmdline.h"
|
|
#include "soc.h"
|
|
|
|
#define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(eeprom_native_posix);
|
|
|
|
static const char default_eeprom_path[] = "eeprom.bin";
|
|
|
|
struct eeprom_native_posix_data {
|
|
const char *path;
|
|
int fd;
|
|
u8_t *eeprom;
|
|
bool init_called;
|
|
};
|
|
|
|
struct eeprom_native_posix_config {
|
|
size_t size;
|
|
bool readonly;
|
|
};
|
|
|
|
#define DEV_NAME(dev) ((dev)->config->name)
|
|
#define DEV_CONFIG(dev) ((dev)->config->config_info)
|
|
#define DEV_DATA(dev) \
|
|
((struct eeprom_native_posix_data *const)(dev)->driver_data)
|
|
|
|
static int eeprom_native_posix_read(struct device *dev, off_t offset,
|
|
void *buf, size_t len)
|
|
{
|
|
struct eeprom_native_posix_data *const data = DEV_DATA(dev);
|
|
const struct eeprom_native_posix_config *config = DEV_CONFIG(dev);
|
|
|
|
if (!len) {
|
|
return 0;
|
|
}
|
|
|
|
if ((offset + len) > config->size) {
|
|
LOG_WRN("attempt to read past device boundary");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (data->eeprom == MAP_FAILED) {
|
|
LOG_ERR("no EEPROM device mapped");
|
|
return -EIO;
|
|
}
|
|
|
|
memcpy(buf, data->eeprom + offset, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int eeprom_native_posix_write(struct device *dev, off_t offset,
|
|
const void *buf, size_t len)
|
|
{
|
|
struct eeprom_native_posix_data *const data = DEV_DATA(dev);
|
|
const struct eeprom_native_posix_config *config = DEV_CONFIG(dev);
|
|
|
|
if (config->readonly) {
|
|
LOG_WRN("attempt to write to read-only device");
|
|
return -EACCES;
|
|
}
|
|
|
|
if (!len) {
|
|
return 0;
|
|
}
|
|
|
|
if ((offset + len) > config->size) {
|
|
LOG_WRN("attempt to write past device boundary");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (data->eeprom == MAP_FAILED) {
|
|
LOG_ERR("no EEPROM device mapped");
|
|
return -EIO;
|
|
}
|
|
|
|
memcpy(data->eeprom + offset, buf, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static size_t eeprom_native_posix_size(struct device *dev)
|
|
{
|
|
const struct eeprom_native_posix_config *config = DEV_CONFIG(dev);
|
|
|
|
return config->size;
|
|
}
|
|
|
|
static int eeprom_native_posix_init(struct device *dev)
|
|
{
|
|
struct eeprom_native_posix_data *const data = DEV_DATA(dev);
|
|
const struct eeprom_native_posix_config *config = DEV_CONFIG(dev);
|
|
|
|
data->init_called = true;
|
|
|
|
if (data->path == NULL) {
|
|
data->path = default_eeprom_path;
|
|
}
|
|
|
|
data->fd = open(data->path, O_RDWR | O_CREAT, (mode_t)0600);
|
|
if (data->fd == -1) {
|
|
posix_print_warning("failed to open EEPROM device file "
|
|
"%s: %s\n",
|
|
data->path, strerror(errno));
|
|
return -EIO;
|
|
}
|
|
|
|
if (ftruncate(data->fd, config->size) == -1) {
|
|
posix_print_warning("failed to resize EEPROM device file "
|
|
"%s: %s\n",
|
|
data->path, strerror(errno));
|
|
return -EIO;
|
|
}
|
|
|
|
data->eeprom = mmap(NULL, config->size, PROT_WRITE | PROT_READ,
|
|
MAP_SHARED, data->fd, 0);
|
|
if (data->eeprom == MAP_FAILED) {
|
|
posix_print_warning("failed to mmap EEPROM device file "
|
|
"%s: %s\n",
|
|
data->path, strerror(errno));
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct eeprom_driver_api eeprom_native_posix_driver_api = {
|
|
.read = eeprom_native_posix_read,
|
|
.write = eeprom_native_posix_write,
|
|
.size = eeprom_native_posix_size,
|
|
};
|
|
|
|
static const struct eeprom_native_posix_config eeprom_native_posix_config_0 = {
|
|
.size = DT_INST_0_ZEPHYR_NATIVE_POSIX_EEPROM_SIZE,
|
|
.readonly = DT_INST_0_ZEPHYR_NATIVE_POSIX_EEPROM_READ_ONLY,
|
|
};
|
|
|
|
static struct eeprom_native_posix_data eeprom_native_posix_data_0;
|
|
|
|
DEVICE_AND_API_INIT(eeprom_native_posix_0,
|
|
DT_INST_0_ZEPHYR_NATIVE_POSIX_EEPROM_LABEL,
|
|
&eeprom_native_posix_init, &eeprom_native_posix_data_0,
|
|
&eeprom_native_posix_config_0, POST_KERNEL,
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
|
&eeprom_native_posix_driver_api);
|
|
|
|
static void eeprom_native_posix_cleanup_0(void)
|
|
{
|
|
struct eeprom_native_posix_data *const data =
|
|
&eeprom_native_posix_data_0;
|
|
const struct eeprom_native_posix_config *config =
|
|
&eeprom_native_posix_config_0;
|
|
|
|
if (!data->init_called) {
|
|
return;
|
|
}
|
|
|
|
if (data->eeprom != MAP_FAILED) {
|
|
munmap(data->eeprom, config->size);
|
|
}
|
|
|
|
if (data->fd != -1) {
|
|
close(data->fd);
|
|
}
|
|
}
|
|
|
|
void eeprom_native_posix_options_0(void)
|
|
{
|
|
static struct args_struct_t eeprom_options[] = {
|
|
{
|
|
.manual = false,
|
|
.is_mandatory = false,
|
|
.is_switch = false,
|
|
.option = "eeprom",
|
|
.name = "path",
|
|
.type = 's',
|
|
.dest = (void *)&eeprom_native_posix_data_0.path,
|
|
.call_when_found = NULL,
|
|
.descript = "Path to binary file to be used as EEPROM",
|
|
},
|
|
ARG_TABLE_ENDMARKER
|
|
};
|
|
|
|
native_add_command_line_opts(eeprom_options);
|
|
}
|
|
|
|
NATIVE_TASK(eeprom_native_posix_options_0, PRE_BOOT_1, 1);
|
|
NATIVE_TASK(eeprom_native_posix_cleanup_0, ON_EXIT, 1);
|