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

View file

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

View file

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

View file

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

View file

@ -32,8 +32,6 @@ struct bmi160_emul_data {
}; };
/** BMI160 device being emulated */ /** BMI160 device being emulated */
const struct device *dev; const struct device *dev;
/** Configuration information */
const struct bmi160_emul_cfg *cfg;
uint8_t pmu_status; uint8_t pmu_status;
/** Current register to read (address) */ /** Current register to read (address) */
uint32_t cur_reg; uint32_t cur_reg;
@ -43,8 +41,6 @@ struct bmi160_emul_data {
struct bmi160_emul_cfg { struct bmi160_emul_cfg {
/** Label of the SPI bus this emulator connects to */ /** Label of the SPI bus this emulator connects to */
const char *bus_label; const char *bus_label;
/** Pointer to run-time data */
struct bmi160_emul_data *data;
/** Chip registers */ /** Chip registers */
uint8_t *reg; uint8_t *reg;
union { 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)); 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); LOG_INF("write %x = %x", regn, val);
cfg->reg[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; int val;
LOG_INF("read %x =", regn); 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) const struct spi_buf_set *rx_bufs)
{ {
struct bmi160_emul_data *data; struct bmi160_emul_data *data;
const struct bmi160_emul_cfg *cfg;
const struct spi_buf *tx, *txd, *rxd; const struct spi_buf *tx, *txd, *rxd;
unsigned int regn, val; unsigned int regn, val;
int count; int count;
data = CONTAINER_OF(emul, struct bmi160_emul_data, emul_spi); 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);
__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: case 1:
if (regn & BMI160_REG_READ) { if (regn & BMI160_REG_READ) {
regn &= BMI160_REG_MASK; regn &= BMI160_REG_MASK;
val = reg_read(cfg, regn); val = reg_read(emul->parent, regn);
*(uint8_t *)rxd->buf = val; *(uint8_t *)rxd->buf = val;
} else { } else {
val = *(uint8_t *)txd->buf; val = *(uint8_t *)txd->buf;
reg_write(cfg, regn, val); reg_write(emul->parent, regn, val);
} }
break; break;
case BMI160_SAMPLE_SIZE: 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) int num_msgs, int addr)
{ {
struct bmi160_emul_data *data; struct bmi160_emul_data *data;
const struct bmi160_emul_cfg *cfg;
unsigned int val; unsigned int val;
data = CONTAINER_OF(emul, struct bmi160_emul_data, emul_i2c); data = CONTAINER_OF(emul, struct bmi160_emul_data, emul_i2c);
cfg = data->cfg;
__ASSERT_NO_MSG(msgs && num_msgs); __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) { if (msgs->flags & I2C_MSG_READ) {
switch (msgs->len) { switch (msgs->len) {
case 1: case 1:
val = reg_read(cfg, data->cur_reg); val = reg_read(emul->parent, data->cur_reg);
msgs->buf[0] = val; msgs->buf[0] = val;
break; break;
case BMI160_SAMPLE_SIZE: 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) { if (msgs->len != 1) {
LOG_ERR("Unexpected msg1 length %d", msgs->len); 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; break;
default: default:
@ -322,11 +316,10 @@ static void emul_bosch_bmi160_init(const struct emul *emul,
const struct device *parent) const struct device *parent)
{ {
const struct bmi160_emul_cfg *cfg = emul->cfg; 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; uint8_t *reg = cfg->reg;
data->dev = parent; data->dev = parent;
data->cfg = cfg;
data->pmu_status = 0; data->pmu_status = 0;
reg[BMI160_REG_CHIPID] = BMI160_CHIP_ID; 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 device *parent)
{ {
const struct bmi160_emul_cfg *cfg = emul->cfg; 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); emul_bosch_bmi160_init(emul, parent);
data->emul_spi.api = &bmi160_emul_api_spi; data->emul_spi.api = &bmi160_emul_api_spi;
data->emul_spi.chipsel = cfg->chipsel; data->emul_spi.chipsel = cfg->chipsel;
data->emul_spi.parent = emul;
int rc = spi_emul_register(parent, emul->dev_label, &data->emul_spi); 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 device *parent)
{ {
const struct bmi160_emul_cfg *cfg = emul->cfg; 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); emul_bosch_bmi160_init(emul, parent);
data->emul_i2c.api = &bmi160_emul_api_i2c; data->emul_i2c.api = &bmi160_emul_api_i2c;
data->emul_i2c.addr = cfg->addr; data->emul_i2c.addr = cfg->addr;
data->emul_i2c.parent = emul;
int rc = i2c_emul_register(parent, emul->dev_label, &data->emul_i2c); 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) \ #define BMI160_EMUL_DEFINE(n, type) \
EMUL_DEFINE(emul_bosch_bmi160_init_##type, DT_DRV_INST(n), \ 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 */ /* Instantiation macros used when a device is on a SPI bus */
#define BMI160_EMUL_SPI(n) \ #define BMI160_EMUL_SPI(n) \
BMI160_EMUL_DATA(n) \ BMI160_EMUL_DATA(n) \
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
.bus_label = DT_INST_BUS_LABEL(n), \ .bus_label = DT_INST_BUS_LABEL(n), \
.data = &bmi160_emul_data_##n, \
.reg = bmi160_emul_reg_##n, \ .reg = bmi160_emul_reg_##n, \
.chipsel = DT_INST_REG_ADDR(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) \ BMI160_EMUL_DATA(n) \
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
.bus_label = DT_INST_BUS_LABEL(n), \ .bus_label = DT_INST_BUS_LABEL(n), \
.data = &bmi160_emul_data_##n, \
.reg = bmi160_emul_reg_##n, \ .reg = bmi160_emul_reg_##n, \
.addr = DT_INST_REG_ADDR(n) \ .addr = DT_INST_REG_ADDR(n) \
}; \ }; \

View file

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

View file

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