#include "net/net.h"
-#include "qdev.h"
+#include "hw/qdev.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
#include "net/hub.h"
#include "qapi/visitor.h"
#include "char/char.h"
+void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
+ Error **errp)
+{
+ if (dev->id) {
+ error_setg(errp, "Attempt to set property '%s' on device '%s' "
+ "(type '%s') after it was realized", name, dev->id,
+ object_get_typename(OBJECT(dev)));
+ } else {
+ error_setg(errp, "Attempt to set property '%s' on anonymous device "
+ "(type '%s') after it was realized", name,
+ object_get_typename(OBJECT(dev)));
+ }
+}
+
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
{
void *ptr = dev;
Property *prop = opaque;
int *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Error *local_err = NULL;
bool value;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Property *prop = opaque;
uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Property *prop = opaque;
uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Property *prop = opaque;
uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Error *local_err = NULL;
char *str;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
int i, pos;
char *str, *p;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
Error *local_err = NULL;
char *str;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
const int64_t min = 512;
const int64_t max = 32768;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
unsigned long dom = 0, bus = 0;
unsigned int slot = 0, func = 0;
- if (dev->state != DEV_STATE_CREATED) {
- error_set(errp, QERR_PERMISSION_DENIED);
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
return;
}
.set = set_pci_host_devaddr,
};
+/* --- support for array properties --- */
+
+/* Used as an opaque for the object properties we add for each
+ * array element. Note that the struct Property must be first
+ * in the struct so that a pointer to this works as the opaque
+ * for the underlying element's property hooks as well as for
+ * our own release callback.
+ */
+typedef struct {
+ struct Property prop;
+ char *propname;
+ ObjectPropertyRelease *release;
+} ArrayElementProperty;
+
+/* object property release callback for array element properties:
+ * we call the underlying element's property release hook, and
+ * then free the memory we allocated when we added the property.
+ */
+static void array_element_release(Object *obj, const char *name, void *opaque)
+{
+ ArrayElementProperty *p = opaque;
+ if (p->release) {
+ p->release(obj, name, opaque);
+ }
+ g_free(p->propname);
+ g_free(p);
+}
+
+static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ /* Setter for the property which defines the length of a
+ * variable-sized property array. As well as actually setting the
+ * array-length field in the device struct, we have to create the
+ * array itself and dynamically add the corresponding properties.
+ */
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
+ void **arrayptr = (void *)dev + prop->arrayoffset;
+ void *eltptr;
+ const char *arrayname;
+ int i;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+ if (*alenptr) {
+ error_setg(errp, "array size property %s may not be set more than once",
+ name);
+ return;
+ }
+ visit_type_uint32(v, alenptr, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (!*alenptr) {
+ return;
+ }
+
+ /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
+ * strip it off so we can get the name of the array itself.
+ */
+ assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
+ strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
+ arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
+
+ /* Note that it is the responsibility of the individual device's deinit
+ * to free the array proper.
+ */
+ *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
+ for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
+ char *propname = g_strdup_printf("%s[%d]", arrayname, i);
+ ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
+ arrayprop->release = prop->arrayinfo->release;
+ arrayprop->propname = propname;
+ arrayprop->prop.info = prop->arrayinfo;
+ arrayprop->prop.name = propname;
+ /* This ugly piece of pointer arithmetic sets up the offset so
+ * that when the underlying get/set hooks call qdev_get_prop_ptr
+ * they get the right answer despite the array element not actually
+ * being inside the device struct.
+ */
+ arrayprop->prop.offset = eltptr - (void *)dev;
+ assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
+ object_property_add(obj, propname,
+ arrayprop->prop.info->name,
+ arrayprop->prop.info->get,
+ arrayprop->prop.info->set,
+ array_element_release,
+ arrayprop, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ }
+}
+
+PropertyInfo qdev_prop_arraylen = {
+ .name = "uint32",
+ .get = get_uint32,
+ .set = set_prop_arraylen,
+};
+
/* --- public helpers --- */
static Property *qdev_prop_walk(Property *props, const char *name)