diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 62035aef83..a94cc44437 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -116,6 +116,23 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name, return ncl->clock; } +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) +{ + const struct ClockPortInitElem *elem; + + for (elem = &clocks[0]; elem->name != NULL; elem++) { + Clock **clkp; + /* offset cannot be inside the DeviceState part */ + assert(elem->offset > sizeof(DeviceState)); + clkp = (Clock **)(((void *) dev) + elem->offset); + if (elem->is_output) { + *clkp = qdev_init_clock_out(dev, elem->name); + } else { + *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev); + } + } +} + static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) { NamedClockList *ncl; diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h index b3b3a3e021..a340f65ff9 100644 --- a/include/hw/qdev-clock.h +++ b/include/hw/qdev-clock.h @@ -101,4 +101,59 @@ Clock *qdev_alias_clock(DeviceState *dev, const char *name, */ void qdev_finalize_clocklist(DeviceState *dev); +/** + * ClockPortInitElem: + * @name: name of the clock (can't be NULL) + * @output: indicates whether the clock is input or output + * @callback: for inputs, optional callback to be called on clock's update + * with device as opaque + * @offset: optional offset to store the ClockIn or ClockOut pointer in device + * state structure (0 means unused) + */ +struct ClockPortInitElem { + const char *name; + bool is_output; + ClockCallback *callback; + size_t offset; +}; + +#define clock_offset_value(devstate, field) \ + (offsetof(devstate, field) + \ + type_check(Clock *, typeof_field(devstate, field))) + +#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \ + .name = (stringify(field)), \ + .is_output = out_not_in, \ + .callback = cb, \ + .offset = clock_offset_value(devstate, field), \ +} + +/** + * QDEV_CLOCK_(IN|OUT): + * @devstate: structure type. @dev argument of qdev_init_clocks below must be + * a pointer to that same type. + * @field: a field in @_devstate (must be Clock*) + * @callback: (for input only) callback (or NULL) to be called with the device + * state as argument + * + * The name of the clock will be derived from @field + */ +#define QDEV_CLOCK_IN(devstate, field, callback) \ + QDEV_CLOCK(false, devstate, field, callback) + +#define QDEV_CLOCK_OUT(devstate, field) \ + QDEV_CLOCK(true, devstate, field, NULL) + +#define QDEV_CLOCK_END { .name = NULL } + +typedef struct ClockPortInitElem ClockPortInitArray[]; + +/** + * qdev_init_clocks: + * @dev: the device to add clocks to + * @clocks: a QDEV_CLOCK_END-terminated array which contains the + * clocks information. + */ +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks); + #endif /* QDEV_CLOCK_H */