@@ -153,3 +153,29 @@ void qdev_connect_clock_out(DeviceState *dev, const char *name, ClockIn *clk,
clock_connect(clk, clkout);
}
+
+void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
+{
+ const struct ClockPortInitElem *elem;
+
+ assert(dev);
+ assert(clocks);
+
+ for (elem = &clocks[0]; elem->name != NULL; elem++) {
+ /* offset cannot be inside the DeviceState part */
+ assert(elem->offset == 0 || elem->offset > sizeof(DeviceState));
+ if (elem->is_output) {
+ ClockOut *clk;
+ clk = qdev_init_clock_out(dev, elem->name);
+ if (elem->offset) {
+ *(ClockOut **)(((void *) dev) + elem->offset) = clk;
+ }
+ } else {
+ ClockIn *clk;
+ clk = qdev_init_clock_in(dev, elem->name, elem->callback, dev);
+ if (elem->offset) {
+ *(ClockIn **)(((void *) dev) + elem->offset) = clk;
+ }
+ }
+ }
+}
@@ -64,4 +64,71 @@ void qdev_connect_clock_out(DeviceState *dev, const char *name, ClockIn *clk,
void qdev_pass_clock(DeviceState *dev, const char *name,
DeviceState *container, const char *cont_name);
+/**
+ * ClockInitElem:
+ * @name: name of the clock (can't be NULL)
+ * @is_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(_type, _devstate, _field) \
+ (offsetof(_devstate, _field) + \
+ type_check(_type *, typeof_field(_devstate, _field)))
+
+#define QDEV_CLOCK(_is_output, _type, _devstate, _field, _callback) { \
+ .name = (stringify(_field)), \
+ .is_output = _is_output, \
+ .callback = _callback, \
+ .offset = clock_offset_value(_type, _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 ClockIn* or ClockOut*)
+ * @_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, ClockIn, _devstate, _field, _callback)
+
+#define QDEV_CLOCK_OUT(_devstate, _field) \
+ QDEV_CLOCK(true, ClockOut, _devstate, _field, NULL)
+
+/**
+ * QDEV_CLOCK_IN_NOFIELD:
+ * @_name: name of the clock
+ * @_callback: callback (or NULL) to be called with the device state as argument
+ */
+#define QDEV_CLOCK_IN_NOFIELD(_name, _callback) { \
+ .name = _name, \
+ .is_output = false, \
+ .callback = _callback, \
+ .offset = 0, \
+}
+
+#define QDEV_CLOCK_END { .name = NULL }
+
+typedef struct ClockPortInitElem ClockPortInitArray[];
+
+/**
+ * qdev_init_clocks:
+ * @dev: the device to add clocks
+ * @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 */