emul: Add data and parent pointers to emulators

Emulators are difficult to work with, they generally require maintaining
some state in a mutable data struct. Since the emulator struct doesn't
support a data field like devices do, the pattern seems to be to add it
to the configuration. This makes following the logic of where things are
difficult.

1. Add a `struct emul *parent` structure to the espi/i2c/spi emulator
   structs to make it easier when casting up.
2. Add a `void *data` field to `struct emul` to hold the data for
   emulators.

Signed-off-by: Yuval Peress <peress@chromium.org>
This commit is contained in:
Yuval Peress 2021-09-09 12:06:08 -06:00 committed by Christopher Friedt
parent 512dab526c
commit 2629fc566d
7 changed files with 63 additions and 64 deletions

View file

@ -56,6 +56,8 @@ struct emul {
const char *dev_label;
/** Emulator-specific configuration data */
const void *cfg;
/** Emulator-specific data */
void *data;
};
/**
@ -78,13 +80,15 @@ extern const struct emul __emul_list_end[];
* typedef)
* @param node_id Node ID of the driver to emulate (e.g. DT_DRV_INST(n))
* @param cfg_ptr emulator-specific configuration data
* @param data_ptr emulator-specific data
*/
#define EMUL_DEFINE(init_ptr, node_id, cfg_ptr) \
static struct emul EMUL_REG_NAME(node_id) \
__attribute__((__section__(".emulators"))) __used = { \
.init = (init_ptr), \
.dev_label = DT_LABEL(node_id), \
.cfg = (cfg_ptr), \
#define EMUL_DEFINE(init_ptr, node_id, cfg_ptr, data_ptr) \
static struct emul EMUL_REG_NAME(node_id) __attribute__((__section__(".emulators"))) \
__used = { \
.init = (init_ptr), \
.dev_label = DT_LABEL(node_id), \
.cfg = (cfg_ptr), \
.data = (data_ptr), \
};
/**

View file

@ -15,6 +15,7 @@
#include <zephyr/types.h>
#include <device.h>
#include <drivers/emul.h>
/**
* @brief eSPI Emulation Interface
@ -111,9 +112,11 @@ struct emul_espi_device_api {
/** Node in a linked list of emulators for eSPI devices */
struct espi_emul {
sys_snode_t node;
/* API provided for this device */
/** Parent emulator */
const struct emul *parent;
/** API provided for this device */
const struct emul_espi_device_api *api;
/* eSPI chip-select of the emulated device */
/** eSPI chip-select of the emulated device */
uint16_t chipsel;
};

View file

@ -22,6 +22,7 @@
#include <zephyr/types.h>
#include <device.h>
#include <drivers/emul.h>
#ifdef __cplusplus
extern "C" {
@ -34,6 +35,9 @@ struct i2c_emul_api;
struct i2c_emul {
sys_snode_t node;
/** Parent emulator */
const struct emul *parent;
/* API provided for this device */
const struct i2c_emul_api *api;

View file

@ -15,6 +15,7 @@
#include <zephyr/types.h>
#include <device.h>
#include <drivers/emul.h>
/**
* @brief SPI Emulation Interface
@ -34,6 +35,9 @@ struct spi_emul_api;
struct spi_emul {
sys_snode_t node;
/** Parent emulator */
const struct emul *parent;
/* API provided for this device */
const struct spi_emul_api *api;

View file

@ -32,8 +32,6 @@ struct bmi160_emul_data {
};
/** BMI160 device being emulated */
const struct device *dev;
/** Configuration information */
const struct bmi160_emul_cfg *cfg;
uint8_t pmu_status;
/** Current register to read (address) */
uint32_t cur_reg;
@ -43,8 +41,6 @@ struct bmi160_emul_data {
struct bmi160_emul_cfg {
/** Label of the SPI bus this emulator connects to */
const char *bus_label;
/** Pointer to run-time data */
struct bmi160_emul_data *data;
/** Chip registers */
uint8_t *reg;
union {
@ -77,9 +73,10 @@ static void sample_read(struct bmi160_emul_data *data, union bmi160_sample *buf)
memcpy(buf->raw, raw_data, ARRAY_SIZE(raw_data));
}
static void reg_write(const struct bmi160_emul_cfg *cfg, int regn, int val)
static void reg_write(const struct emul *emulator, int regn, int val)
{
struct bmi160_emul_data *data = cfg->data;
struct bmi160_emul_data *data = emulator->data;
const struct bmi160_emul_cfg *cfg = emulator->cfg;
LOG_INF("write %x = %x", regn, val);
cfg->reg[regn] = val;
@ -136,9 +133,10 @@ static void reg_write(const struct bmi160_emul_cfg *cfg, int regn, int val)
}
}
static int reg_read(const struct bmi160_emul_cfg *cfg, int regn)
static int reg_read(const struct emul *emulator, int regn)
{
struct bmi160_emul_data *data = cfg->data;
struct bmi160_emul_data *data = emulator->data;
const struct bmi160_emul_cfg *cfg = emulator->cfg;
int val;
LOG_INF("read %x =", regn);
@ -185,13 +183,11 @@ static int bmi160_emul_io_spi(struct spi_emul *emul,
const struct spi_buf_set *rx_bufs)
{
struct bmi160_emul_data *data;
const struct bmi160_emul_cfg *cfg;
const struct spi_buf *tx, *txd, *rxd;
unsigned int regn, val;
int count;
data = CONTAINER_OF(emul, struct bmi160_emul_data, emul_spi);
cfg = data->cfg;
__ASSERT_NO_MSG(tx_bufs || rx_bufs);
__ASSERT_NO_MSG(!tx_bufs || !rx_bufs ||
@ -214,11 +210,11 @@ static int bmi160_emul_io_spi(struct spi_emul *emul,
case 1:
if (regn & BMI160_REG_READ) {
regn &= BMI160_REG_MASK;
val = reg_read(cfg, regn);
val = reg_read(emul->parent, regn);
*(uint8_t *)rxd->buf = val;
} else {
val = *(uint8_t *)txd->buf;
reg_write(cfg, regn, val);
reg_write(emul->parent, regn, val);
}
break;
case BMI160_SAMPLE_SIZE:
@ -252,11 +248,9 @@ static int bmi160_emul_transfer_i2c(struct i2c_emul *emul, struct i2c_msg *msgs,
int num_msgs, int addr)
{
struct bmi160_emul_data *data;
const struct bmi160_emul_cfg *cfg;
unsigned int val;
data = CONTAINER_OF(emul, struct bmi160_emul_data, emul_i2c);
cfg = data->cfg;
__ASSERT_NO_MSG(msgs && num_msgs);
@ -278,7 +272,7 @@ static int bmi160_emul_transfer_i2c(struct i2c_emul *emul, struct i2c_msg *msgs,
if (msgs->flags & I2C_MSG_READ) {
switch (msgs->len) {
case 1:
val = reg_read(cfg, data->cur_reg);
val = reg_read(emul->parent, data->cur_reg);
msgs->buf[0] = val;
break;
case BMI160_SAMPLE_SIZE:
@ -292,7 +286,7 @@ static int bmi160_emul_transfer_i2c(struct i2c_emul *emul, struct i2c_msg *msgs,
if (msgs->len != 1) {
LOG_ERR("Unexpected msg1 length %d", msgs->len);
}
reg_write(cfg, data->cur_reg, msgs->buf[0]);
reg_write(emul->parent, data->cur_reg, msgs->buf[0]);
}
break;
default:
@ -322,11 +316,10 @@ static void emul_bosch_bmi160_init(const struct emul *emul,
const struct device *parent)
{
const struct bmi160_emul_cfg *cfg = emul->cfg;
struct bmi160_emul_data *data = cfg->data;
struct bmi160_emul_data *data = emul->data;
uint8_t *reg = cfg->reg;
data->dev = parent;
data->cfg = cfg;
data->pmu_status = 0;
reg[BMI160_REG_CHIPID] = BMI160_CHIP_ID;
@ -347,11 +340,12 @@ static int emul_bosch_bmi160_init_spi(const struct emul *emul,
const struct device *parent)
{
const struct bmi160_emul_cfg *cfg = emul->cfg;
struct bmi160_emul_data *data = cfg->data;
struct bmi160_emul_data *data = emul->data;
emul_bosch_bmi160_init(emul, parent);
data->emul_spi.api = &bmi160_emul_api_spi;
data->emul_spi.chipsel = cfg->chipsel;
data->emul_spi.parent = emul;
int rc = spi_emul_register(parent, emul->dev_label, &data->emul_spi);
@ -374,11 +368,12 @@ static int emul_bosch_bmi160_init_i2c(const struct emul *emul,
const struct device *parent)
{
const struct bmi160_emul_cfg *cfg = emul->cfg;
struct bmi160_emul_data *data = cfg->data;
struct bmi160_emul_data *data = emul->data;
emul_bosch_bmi160_init(emul, parent);
data->emul_i2c.api = &bmi160_emul_api_i2c;
data->emul_i2c.addr = cfg->addr;
data->emul_i2c.parent = emul;
int rc = i2c_emul_register(parent, emul->dev_label, &data->emul_i2c);
@ -392,14 +387,13 @@ static int emul_bosch_bmi160_init_i2c(const struct emul *emul,
#define BMI160_EMUL_DEFINE(n, type) \
EMUL_DEFINE(emul_bosch_bmi160_init_##type, DT_DRV_INST(n), \
&bmi160_emul_cfg_##n)
&bmi160_emul_cfg_##n, &bmi160_emul_data_##n)
/* Instantiation macros used when a device is on a SPI bus */
#define BMI160_EMUL_SPI(n) \
BMI160_EMUL_DATA(n) \
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
.bus_label = DT_INST_BUS_LABEL(n), \
.data = &bmi160_emul_data_##n, \
.reg = bmi160_emul_reg_##n, \
.chipsel = DT_INST_REG_ADDR(n) \
}; \
@ -409,7 +403,6 @@ static int emul_bosch_bmi160_init_i2c(const struct emul *emul,
BMI160_EMUL_DATA(n) \
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
.bus_label = DT_INST_BUS_LABEL(n), \
.data = &bmi160_emul_data_##n, \
.reg = bmi160_emul_reg_##n, \
.addr = DT_INST_REG_ADDR(n) \
}; \

View file

@ -68,8 +68,6 @@ struct espi_host_emul_data {
struct espi_emul emul;
/** eSPI controller device */
const struct device *espi;
/** Configuration information */
const struct espi_host_emul_cfg *cfg;
/** Virtual Wires states, for one slave only.
* With multi-slaves config, the states should be saved per slave */
struct vw_data vw_state[NUMBER_OF_VWIRES];
@ -85,8 +83,6 @@ struct espi_host_emul_cfg {
const char *espi_label;
/** Label of the emulated AP*/
const char *label;
/** Pointer to run-time data */
struct espi_host_emul_data *data;
/* eSPI chip-select of the emulated device */
uint16_t chipsel;
};
@ -258,24 +254,24 @@ static struct emul_espi_device_api ap_emul_api = {
static int emul_host_init(const struct emul *emul, const struct device *bus)
{
const struct espi_host_emul_cfg *cfg = emul->cfg;
struct espi_host_emul_data *data = cfg->data;
struct espi_host_emul_data *data = emul->data;
data->emul.api = &ap_emul_api;
data->emul.chipsel = cfg->chipsel;
data->emul.parent = emul;
data->espi = bus;
data->cfg = cfg;
emul_host_init_vw_state(data);
return espi_emul_register(bus, emul->dev_label, &data->emul);
}
#define HOST_EMUL(n) \
static struct espi_host_emul_data espi_host_emul_data_##n; \
static const struct espi_host_emul_cfg espi_host_emul_cfg_##n = { \
.espi_label = DT_INST_BUS_LABEL(n), \
.data = &espi_host_emul_data_##n, \
.chipsel = DT_INST_REG_ADDR(n), \
}; \
EMUL_DEFINE(emul_host_init, DT_DRV_INST(n), &espi_host_emul_cfg_##n)
#define HOST_EMUL(n) \
static struct espi_host_emul_data espi_host_emul_data_##n; \
static const struct espi_host_emul_cfg espi_host_emul_cfg_##n = { \
.espi_label = DT_INST_BUS_LABEL(n), \
.chipsel = DT_INST_REG_ADDR(n), \
}; \
EMUL_DEFINE(emul_host_init, DT_DRV_INST(n), &espi_host_emul_cfg_##n, \
&espi_host_emul_data_##n)
DT_INST_FOREACH_STATUS_OKAY(HOST_EMUL)

View file

@ -22,8 +22,6 @@ struct at24_emul_data {
struct i2c_emul emul;
/** AT24 device being emulated */
const struct device *i2c;
/** Configuration information */
const struct at24_emul_cfg *cfg;
/** Current register to read (address) */
uint32_t cur_reg;
};
@ -32,8 +30,6 @@ struct at24_emul_data {
struct at24_emul_cfg {
/** Label of the I2C bus this emulator connects to */
const char *i2c_label;
/** Pointer to run-time data */
struct at24_emul_data *data;
/** EEPROM data contents */
uint8_t *buf;
/** Size of EEPROM in bytes */
@ -67,7 +63,7 @@ static int at24_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs,
bool too_fast;
data = CONTAINER_OF(emul, struct at24_emul_data, emul);
cfg = data->cfg;
cfg = emul->parent->cfg;
if (cfg->addr != addr) {
LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr,
@ -141,12 +137,12 @@ static int emul_atmel_at24_init(const struct emul *emul,
const struct device *parent)
{
const struct at24_emul_cfg *cfg = emul->cfg;
struct at24_emul_data *data = cfg->data;
struct at24_emul_data *data = emul->data;
data->emul.api = &at24_emul_api;
data->emul.addr = cfg->addr;
data->emul.parent = emul;
data->i2c = parent;
data->cfg = cfg;
data->cur_reg = 0;
/* Start with an erased EEPROM, assuming all 0xff */
@ -157,17 +153,16 @@ static int emul_atmel_at24_init(const struct emul *emul,
return rc;
}
#define EEPROM_AT24_EMUL(n) \
static uint8_t at24_emul_buf_##n[DT_INST_PROP(n, size)]; \
static struct at24_emul_data at24_emul_data_##n; \
static const struct at24_emul_cfg at24_emul_cfg_##n = { \
.i2c_label = DT_INST_BUS_LABEL(n), \
.data = &at24_emul_data_##n, \
.buf = at24_emul_buf_##n, \
.size = DT_INST_PROP(n, size), \
.addr = DT_INST_REG_ADDR(n), \
.addr_width = 8, \
}; \
EMUL_DEFINE(emul_atmel_at24_init, DT_DRV_INST(n), &at24_emul_cfg_##n)
#define EEPROM_AT24_EMUL(n) \
static uint8_t at24_emul_buf_##n[DT_INST_PROP(n, size)]; \
static struct at24_emul_data at24_emul_data_##n; \
static const struct at24_emul_cfg at24_emul_cfg_##n = { \
.i2c_label = DT_INST_BUS_LABEL(n), \
.buf = at24_emul_buf_##n, \
.size = DT_INST_PROP(n, size), \
.addr = DT_INST_REG_ADDR(n), \
.addr_width = 8, \
}; \
EMUL_DEFINE(emul_atmel_at24_init, DT_DRV_INST(n), &at24_emul_cfg_##n, &at24_emul_data_##n)
DT_INST_FOREACH_STATUS_OKAY(EEPROM_AT24_EMUL)