mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'bonzini/qdev-props-for-anthony' into staging
* bonzini/qdev-props-for-anthony: (25 commits) qdev: remove unused fields from PropertyInfo qdev: initialize properties via QOM qdev: inline qdev_prop_set into qdev_prop_set_ptr qdev: access properties via QOM qdev: fix off-by-one qdev: let QOM free properties qdev: remove parse/print methods for pointer properties qdev: make the non-legacy pci address property accept an integer qdev: remove parse/print methods for mac properties qdev: remove print/parse methods from LostTickPolicy properties qdev: remove parse method for string properties qdev: allow reusing get/set for legacy property qdev: remove direct calls to print/parse qom: add property get/set wrappers for links qom: fix canonical paths vs. interfaces qom: use object_resolve_path_type for links qom: add object_resolve_path_type qom: fix off-by-one qom: add property get/set wrappers for C types qom: add QObject-based property get/set wrappers ...
This commit is contained in:
commit
a642153013
|
@ -61,8 +61,6 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_taddr = {
|
||||
.name = "taddr",
|
||||
.type = PROP_TYPE_TADDR,
|
||||
.size = sizeof(target_phys_addr_t),
|
||||
.parse = parse_taddr,
|
||||
.print = print_taddr,
|
||||
.get = get_taddr,
|
||||
|
@ -71,5 +69,8 @@ PropertyInfo qdev_prop_taddr = {
|
|||
|
||||
void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_TADDR);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
|
||||
}
|
||||
|
|
|
@ -485,22 +485,26 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent);
|
|||
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
|
||||
const char *prefix, int indent)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
if (!props)
|
||||
return;
|
||||
while (props->name) {
|
||||
/*
|
||||
* TODO Properties without a print method are just for dirty
|
||||
* hacks. qdev_prop_ptr is the only such PropertyInfo. It's
|
||||
* marked for removal. The test props->info->print should be
|
||||
* removed along with it.
|
||||
*/
|
||||
if (props->info->print) {
|
||||
props->info->print(dev, props, buf, sizeof(buf));
|
||||
qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
|
||||
for (; props->name; props++) {
|
||||
Error *err = NULL;
|
||||
char *value;
|
||||
char *legacy_name = g_strdup_printf("legacy-%s", props->name);
|
||||
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
||||
value = object_property_get_str(OBJECT(dev), legacy_name, &err);
|
||||
} else {
|
||||
value = object_property_get_str(OBJECT(dev), props->name, &err);
|
||||
}
|
||||
props++;
|
||||
g_free(legacy_name);
|
||||
|
||||
if (err) {
|
||||
error_free(err);
|
||||
continue;
|
||||
}
|
||||
qdev_printf("%s-prop: %s = %s\n", prefix, props->name,
|
||||
value && *value ? value : "<null>");
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
|||
|
||||
static uint32_t qdev_get_prop_mask(Property *prop)
|
||||
{
|
||||
assert(prop->info->type == PROP_TYPE_BIT);
|
||||
assert(prop->info == &qdev_prop_bit);
|
||||
return 0x1 << prop->bitnr;
|
||||
}
|
||||
|
||||
|
@ -26,17 +26,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val)
|
|||
*p &= ~mask;
|
||||
}
|
||||
|
||||
static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
|
||||
{
|
||||
if (props->info->type == PROP_TYPE_BIT) {
|
||||
bool *defval = src;
|
||||
bit_prop_set(dev, props, *defval);
|
||||
} else {
|
||||
char *dst = qdev_get_prop_ptr(dev, props);
|
||||
memcpy(dst, src, props->info->size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bit */
|
||||
static int parse_bit(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
|
@ -90,8 +79,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque,
|
|||
PropertyInfo qdev_prop_bit = {
|
||||
.name = "boolean",
|
||||
.legacy_name = "on/off",
|
||||
.type = PROP_TYPE_BIT,
|
||||
.size = sizeof(uint32_t),
|
||||
.parse = parse_bit,
|
||||
.print = print_bit,
|
||||
.get = get_bit,
|
||||
|
@ -151,7 +138,7 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
|
|||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
if (value > prop->info->min && value <= prop->info->max) {
|
||||
if (value >= prop->info->min && value <= prop->info->max) {
|
||||
*ptr = value;
|
||||
} else {
|
||||
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
|
||||
|
@ -162,8 +149,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint8 = {
|
||||
.name = "uint8",
|
||||
.type = PROP_TYPE_UINT8,
|
||||
.size = sizeof(uint8_t),
|
||||
.parse = parse_uint8,
|
||||
.print = print_uint8,
|
||||
.get = get_int8,
|
||||
|
@ -196,8 +181,6 @@ static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
|
|||
PropertyInfo qdev_prop_hex8 = {
|
||||
.name = "uint8",
|
||||
.legacy_name = "hex8",
|
||||
.type = PROP_TYPE_UINT8,
|
||||
.size = sizeof(uint8_t),
|
||||
.parse = parse_hex8,
|
||||
.print = print_hex8,
|
||||
.get = get_int8,
|
||||
|
@ -259,7 +242,7 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
|
|||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
if (value > prop->info->min && value <= prop->info->max) {
|
||||
if (value >= prop->info->min && value <= prop->info->max) {
|
||||
*ptr = value;
|
||||
} else {
|
||||
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
|
||||
|
@ -270,8 +253,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint16 = {
|
||||
.name = "uint16",
|
||||
.type = PROP_TYPE_UINT16,
|
||||
.size = sizeof(uint16_t),
|
||||
.parse = parse_uint16,
|
||||
.print = print_uint16,
|
||||
.get = get_int16,
|
||||
|
@ -333,7 +314,7 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
|
|||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
if (value > prop->info->min && value <= prop->info->max) {
|
||||
if (value >= prop->info->min && value <= prop->info->max) {
|
||||
*ptr = value;
|
||||
} else {
|
||||
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
|
||||
|
@ -344,8 +325,6 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint32 = {
|
||||
.name = "uint32",
|
||||
.type = PROP_TYPE_UINT32,
|
||||
.size = sizeof(uint32_t),
|
||||
.parse = parse_uint32,
|
||||
.print = print_uint32,
|
||||
.get = get_int32,
|
||||
|
@ -375,8 +354,6 @@ static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len)
|
|||
|
||||
PropertyInfo qdev_prop_int32 = {
|
||||
.name = "int32",
|
||||
.type = PROP_TYPE_INT32,
|
||||
.size = sizeof(int32_t),
|
||||
.parse = parse_int32,
|
||||
.print = print_int32,
|
||||
.get = get_int32,
|
||||
|
@ -409,8 +386,6 @@ static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
|
|||
PropertyInfo qdev_prop_hex32 = {
|
||||
.name = "uint32",
|
||||
.legacy_name = "hex32",
|
||||
.type = PROP_TYPE_UINT32,
|
||||
.size = sizeof(uint32_t),
|
||||
.parse = parse_hex32,
|
||||
.print = print_hex32,
|
||||
.get = get_int32,
|
||||
|
@ -468,8 +443,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint64 = {
|
||||
.name = "uint64",
|
||||
.type = PROP_TYPE_UINT64,
|
||||
.size = sizeof(uint64_t),
|
||||
.parse = parse_uint64,
|
||||
.print = print_uint64,
|
||||
.get = get_int64,
|
||||
|
@ -500,8 +473,6 @@ static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
|
|||
PropertyInfo qdev_prop_hex64 = {
|
||||
.name = "uint64",
|
||||
.legacy_name = "hex64",
|
||||
.type = PROP_TYPE_UINT64,
|
||||
.size = sizeof(uint64_t),
|
||||
.parse = parse_hex64,
|
||||
.print = print_hex64,
|
||||
.get = get_int64,
|
||||
|
@ -510,19 +481,10 @@ PropertyInfo qdev_prop_hex64 = {
|
|||
|
||||
/* --- string --- */
|
||||
|
||||
static int parse_string(DeviceState *dev, Property *prop, const char *str)
|
||||
static void release_string(Object *obj, const char *name, void *opaque)
|
||||
{
|
||||
char **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
if (*ptr)
|
||||
g_free(*ptr);
|
||||
*ptr = g_strdup(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_string(DeviceState *dev, Property *prop)
|
||||
{
|
||||
g_free(*(char **)qdev_get_prop_ptr(dev, prop));
|
||||
Property *prop = opaque;
|
||||
g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
|
||||
}
|
||||
|
||||
static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
|
@ -579,20 +541,16 @@ static void set_string(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_string = {
|
||||
.name = "string",
|
||||
.type = PROP_TYPE_STRING,
|
||||
.size = sizeof(char*),
|
||||
.parse = parse_string,
|
||||
.print = print_string,
|
||||
.free = free_string,
|
||||
.release = release_string,
|
||||
.get = get_string,
|
||||
.set = set_string,
|
||||
};
|
||||
|
||||
/* --- drive --- */
|
||||
|
||||
static int parse_drive(DeviceState *dev, Property *prop, const char *str)
|
||||
static int parse_drive(DeviceState *dev, const char *str, void **ptr)
|
||||
{
|
||||
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
BlockDriverState *bs;
|
||||
|
||||
bs = bdrv_find(str);
|
||||
|
@ -604,8 +562,10 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void free_drive(DeviceState *dev, Property *prop)
|
||||
static void release_drive(Object *obj, const char *name, void *opaque)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
if (*ptr) {
|
||||
|
@ -614,35 +574,30 @@ static void free_drive(DeviceState *dev, Property *prop)
|
|||
}
|
||||
}
|
||||
|
||||
static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
static const char *print_drive(void *ptr)
|
||||
{
|
||||
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%s",
|
||||
*ptr ? bdrv_get_device_name(*ptr) : "<null>");
|
||||
return bdrv_get_device_name(ptr);
|
||||
}
|
||||
|
||||
static void get_generic(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
void **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
|
||||
buffer[0] = 0;
|
||||
if (*ptr) {
|
||||
prop->info->print(dev, prop, buffer, sizeof(buffer));
|
||||
}
|
||||
visit_type_str(v, &p, name, errp);
|
||||
}
|
||||
|
||||
static void set_generic(Object *obj, Visitor *v, void *opaque,
|
||||
static void get_pointer(Object *obj, Visitor *v, Property *prop,
|
||||
const char *(*print)(void *ptr),
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
void **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *p;
|
||||
|
||||
p = (char *) (*ptr ? print(*ptr) : "");
|
||||
visit_type_str(v, &p, name, errp);
|
||||
}
|
||||
|
||||
static void set_pointer(Object *obj, Visitor *v, Property *prop,
|
||||
int (*parse)(DeviceState *dev, const char *str, void **ptr),
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
Error *local_err = NULL;
|
||||
void **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *str;
|
||||
int ret;
|
||||
|
||||
|
@ -661,41 +616,50 @@ static void set_generic(Object *obj, Visitor *v, void *opaque,
|
|||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
return;
|
||||
}
|
||||
ret = prop->info->parse(dev, prop, str);
|
||||
ret = parse(dev, str, ptr);
|
||||
error_set_from_qdev_prop_error(errp, ret, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void get_drive(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
get_pointer(obj, v, opaque, print_drive, name, errp);
|
||||
}
|
||||
|
||||
static void set_drive(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
set_pointer(obj, v, opaque, parse_drive, name, errp);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_drive = {
|
||||
.name = "drive",
|
||||
.type = PROP_TYPE_DRIVE,
|
||||
.size = sizeof(BlockDriverState *),
|
||||
.parse = parse_drive,
|
||||
.print = print_drive,
|
||||
.get = get_generic,
|
||||
.set = set_generic,
|
||||
.free = free_drive,
|
||||
.get = get_drive,
|
||||
.set = set_drive,
|
||||
.release = release_drive,
|
||||
};
|
||||
|
||||
/* --- character device --- */
|
||||
|
||||
static int parse_chr(DeviceState *dev, Property *prop, const char *str)
|
||||
static int parse_chr(DeviceState *dev, const char *str, void **ptr)
|
||||
{
|
||||
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
*ptr = qemu_chr_find(str);
|
||||
if (*ptr == NULL) {
|
||||
CharDriverState *chr = qemu_chr_find(str);
|
||||
if (chr == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((*ptr)->avail_connections < 1) {
|
||||
if (chr->avail_connections < 1) {
|
||||
return -EEXIST;
|
||||
}
|
||||
--(*ptr)->avail_connections;
|
||||
*ptr = chr;
|
||||
--chr->avail_connections;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_chr(DeviceState *dev, Property *prop)
|
||||
static void release_chr(Object *obj, const char *name, void *opaque)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
if (*ptr) {
|
||||
|
@ -704,62 +668,71 @@ static void free_chr(DeviceState *dev, Property *prop)
|
|||
}
|
||||
|
||||
|
||||
static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
static const char *print_chr(void *ptr)
|
||||
{
|
||||
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
CharDriverState *chr = ptr;
|
||||
|
||||
if (*ptr && (*ptr)->label) {
|
||||
return snprintf(dest, len, "%s", (*ptr)->label);
|
||||
} else {
|
||||
return snprintf(dest, len, "<null>");
|
||||
}
|
||||
return chr->label ? chr->label : "";
|
||||
}
|
||||
|
||||
static void get_chr(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
get_pointer(obj, v, opaque, print_chr, name, errp);
|
||||
}
|
||||
|
||||
static void set_chr(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
set_pointer(obj, v, opaque, parse_chr, name, errp);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_chr = {
|
||||
.name = "chr",
|
||||
.type = PROP_TYPE_CHR,
|
||||
.size = sizeof(CharDriverState*),
|
||||
.parse = parse_chr,
|
||||
.print = print_chr,
|
||||
.get = get_generic,
|
||||
.set = set_generic,
|
||||
.free = free_chr,
|
||||
.get = get_chr,
|
||||
.set = set_chr,
|
||||
.release = release_chr,
|
||||
};
|
||||
|
||||
/* --- netdev device --- */
|
||||
|
||||
static int parse_netdev(DeviceState *dev, Property *prop, const char *str)
|
||||
static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
|
||||
{
|
||||
VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
VLANClientState *netdev = qemu_find_netdev(str);
|
||||
|
||||
*ptr = qemu_find_netdev(str);
|
||||
if (*ptr == NULL)
|
||||
if (netdev == NULL) {
|
||||
return -ENOENT;
|
||||
if ((*ptr)->peer) {
|
||||
}
|
||||
if (netdev->peer) {
|
||||
return -EEXIST;
|
||||
}
|
||||
*ptr = netdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
static const char *print_netdev(void *ptr)
|
||||
{
|
||||
VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
VLANClientState *netdev = ptr;
|
||||
|
||||
if (*ptr && (*ptr)->name) {
|
||||
return snprintf(dest, len, "%s", (*ptr)->name);
|
||||
} else {
|
||||
return snprintf(dest, len, "<null>");
|
||||
}
|
||||
return netdev->name ? netdev->name : "";
|
||||
}
|
||||
|
||||
static void get_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
get_pointer(obj, v, opaque, print_netdev, name, errp);
|
||||
}
|
||||
|
||||
static void set_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
set_pointer(obj, v, opaque, parse_netdev, name, errp);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_netdev = {
|
||||
.name = "netdev",
|
||||
.type = PROP_TYPE_NETDEV,
|
||||
.size = sizeof(VLANClientState*),
|
||||
.parse = parse_netdev,
|
||||
.print = print_netdev,
|
||||
.get = get_generic,
|
||||
.set = set_generic,
|
||||
.get = get_netdev,
|
||||
.set = set_netdev,
|
||||
};
|
||||
|
||||
/* --- vlan --- */
|
||||
|
@ -835,8 +808,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_vlan = {
|
||||
.name = "vlan",
|
||||
.type = PROP_TYPE_VLAN,
|
||||
.size = sizeof(VLANClientState*),
|
||||
.parse = parse_vlan,
|
||||
.print = print_vlan,
|
||||
.get = get_vlan,
|
||||
|
@ -848,8 +819,6 @@ PropertyInfo qdev_prop_vlan = {
|
|||
/* Not a proper property, just for dirty hacks. TODO Remove it! */
|
||||
PropertyInfo qdev_prop_ptr = {
|
||||
.name = "ptr",
|
||||
.type = PROP_TYPE_PTR,
|
||||
.size = sizeof(void*),
|
||||
};
|
||||
|
||||
/* --- mac address --- */
|
||||
|
@ -859,95 +828,114 @@ PropertyInfo qdev_prop_ptr = {
|
|||
* 01:02:03:04:05:06
|
||||
* 01-02-03-04-05-06
|
||||
*/
|
||||
static int parse_mac(DeviceState *dev, Property *prop, const char *str)
|
||||
static void get_mac(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
MACAddr *mac = qdev_get_prop_ptr(dev, prop);
|
||||
char buffer[2 * 6 + 5 + 1];
|
||||
char *p = buffer;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac->a[0], mac->a[1], mac->a[2],
|
||||
mac->a[3], mac->a[4], mac->a[5]);
|
||||
|
||||
visit_type_str(v, &p, name, errp);
|
||||
}
|
||||
|
||||
static void set_mac(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
MACAddr *mac = qdev_get_prop_ptr(dev, prop);
|
||||
Error *local_err = NULL;
|
||||
int i, pos;
|
||||
char *p;
|
||||
char *str, *p;
|
||||
|
||||
if (dev->state != DEV_STATE_CREATED) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, &str, name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, pos = 0; i < 6; i++, pos += 3) {
|
||||
if (!qemu_isxdigit(str[pos]))
|
||||
return -EINVAL;
|
||||
goto inval;
|
||||
if (!qemu_isxdigit(str[pos+1]))
|
||||
return -EINVAL;
|
||||
goto inval;
|
||||
if (i == 5) {
|
||||
if (str[pos+2] != '\0')
|
||||
return -EINVAL;
|
||||
goto inval;
|
||||
} else {
|
||||
if (str[pos+2] != ':' && str[pos+2] != '-')
|
||||
return -EINVAL;
|
||||
goto inval;
|
||||
}
|
||||
mac->a[i] = strtol(str+pos, &p, 16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return;
|
||||
|
||||
static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
MACAddr *mac = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac->a[0], mac->a[1], mac->a[2],
|
||||
mac->a[3], mac->a[4], mac->a[5]);
|
||||
inval:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_macaddr = {
|
||||
.name = "macaddr",
|
||||
.type = PROP_TYPE_MACADDR,
|
||||
.size = sizeof(MACAddr),
|
||||
.parse = parse_mac,
|
||||
.print = print_mac,
|
||||
.get = get_generic,
|
||||
.set = set_generic,
|
||||
.get = get_mac,
|
||||
.set = set_mac,
|
||||
};
|
||||
|
||||
|
||||
/* --- lost tick policy --- */
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
LostTickPolicy code;
|
||||
} lost_tick_policy_table[] = {
|
||||
{ .name = "discard", .code = LOST_TICK_DISCARD },
|
||||
{ .name = "delay", .code = LOST_TICK_DELAY },
|
||||
{ .name = "merge", .code = LOST_TICK_MERGE },
|
||||
{ .name = "slew", .code = LOST_TICK_SLEW },
|
||||
static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = {
|
||||
[LOST_TICK_DISCARD] = "discard",
|
||||
[LOST_TICK_DELAY] = "delay",
|
||||
[LOST_TICK_MERGE] = "merge",
|
||||
[LOST_TICK_SLEW] = "slew",
|
||||
[LOST_TICK_MAX] = NULL,
|
||||
};
|
||||
|
||||
static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
|
||||
const char *str)
|
||||
{
|
||||
LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
int i;
|
||||
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) {
|
||||
if (!strcasecmp(str, lost_tick_policy_table[i].name)) {
|
||||
*ptr = lost_tick_policy_table[i].code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(lost_tick_policy_table)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
static void get_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
int *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
visit_type_enum(v, ptr, prop->info->enum_table,
|
||||
prop->info->name, prop->name, errp);
|
||||
}
|
||||
|
||||
static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
|
||||
size_t len)
|
||||
static void set_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
int *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
|
||||
if (dev->state != DEV_STATE_CREATED) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_enum(v, ptr, prop->info->enum_table,
|
||||
prop->info->name, prop->name, errp);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_losttickpolicy = {
|
||||
.name = "lost_tick_policy",
|
||||
.type = PROP_TYPE_LOSTTICKPOLICY,
|
||||
.size = sizeof(LostTickPolicy),
|
||||
.parse = parse_lost_tick_policy,
|
||||
.print = print_lost_tick_policy,
|
||||
.get = get_generic,
|
||||
.set = set_generic,
|
||||
.name = "LostTickPolicy",
|
||||
.enum_table = lost_tick_policy_table,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
};
|
||||
|
||||
/* --- pci address --- */
|
||||
|
@ -987,30 +975,18 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
|
|||
}
|
||||
}
|
||||
|
||||
static void get_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char buffer[32];
|
||||
char *p = buffer;
|
||||
|
||||
buffer[0] = 0;
|
||||
if (*ptr != -1) {
|
||||
snprintf(buffer, sizeof(buffer), "%02x.%x", *ptr >> 3, *ptr & 7);
|
||||
}
|
||||
visit_type_str(v, &p, name, errp);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_pci_devfn = {
|
||||
.name = "pci-devfn",
|
||||
.type = PROP_TYPE_UINT32,
|
||||
.size = sizeof(uint32_t),
|
||||
.name = "int32",
|
||||
.legacy_name = "pci-devfn",
|
||||
.parse = parse_pci_devfn,
|
||||
.print = print_pci_devfn,
|
||||
.get = get_pci_devfn,
|
||||
.set = set_generic,
|
||||
.get = get_int32,
|
||||
.set = set_int32,
|
||||
/* FIXME: this should be -1...255, but the address is stored
|
||||
* into an uint32_t rather than int32_t.
|
||||
*/
|
||||
.min = 0,
|
||||
.max = 0xFFFFFFFFULL,
|
||||
};
|
||||
|
||||
/* --- public helpers --- */
|
||||
|
@ -1073,24 +1049,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
|||
|
||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
||||
{
|
||||
Property *prop;
|
||||
int ret;
|
||||
char *legacy_name;
|
||||
Error *err = NULL;
|
||||
|
||||
prop = qdev_prop_find(dev, name);
|
||||
/*
|
||||
* TODO Properties without a parse method are just for dirty
|
||||
* hacks. qdev_prop_ptr is the only such PropertyInfo. It's
|
||||
* marked for removal. The test !prop->info->parse should be
|
||||
* removed along with it.
|
||||
*/
|
||||
if (!prop || !prop->info->parse) {
|
||||
qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name);
|
||||
return -1;
|
||||
legacy_name = g_strdup_printf("legacy-%s", name);
|
||||
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
||||
object_property_set_str(OBJECT(dev), value, legacy_name, &err);
|
||||
} else {
|
||||
object_property_set_str(OBJECT(dev), value, name, &err);
|
||||
}
|
||||
ret = prop->info->parse(dev, prop, value);
|
||||
if (ret < 0) {
|
||||
Error *err;
|
||||
error_set_from_qdev_prop_error(&err, ret, dev, prop, value);
|
||||
g_free(legacy_name);
|
||||
|
||||
if (err) {
|
||||
qerror_report_err(err);
|
||||
error_free(err);
|
||||
return -1;
|
||||
|
@ -1098,72 +1068,65 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
|
||||
{
|
||||
Property *prop;
|
||||
|
||||
prop = qdev_prop_find(dev, name);
|
||||
if (!prop) {
|
||||
fprintf(stderr, "%s: property \"%s.%s\" not found\n",
|
||||
__FUNCTION__, object_get_typename(OBJECT(dev)), name);
|
||||
abort();
|
||||
}
|
||||
if (prop->info->type != type) {
|
||||
fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
|
||||
__FUNCTION__, object_get_typename(OBJECT(dev)), name);
|
||||
abort();
|
||||
}
|
||||
qdev_prop_cpy(dev, prop, src);
|
||||
}
|
||||
|
||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_BIT);
|
||||
Error *errp = NULL;
|
||||
object_property_set_bool(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_INT32);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
|
||||
Error *errp = NULL;
|
||||
object_property_set_str(OBJECT(dev), value, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = bdrv_attach_dev(value, dev);
|
||||
if (res < 0) {
|
||||
error_report("Can't attach drive %s to %s.%s: %s",
|
||||
bdrv_get_device_name(value),
|
||||
dev->id ? dev->id : object_get_typename(OBJECT(dev)),
|
||||
name, strerror(-res));
|
||||
Error *errp = NULL;
|
||||
object_property_set_str(OBJECT(dev), bdrv_get_device_name(value),
|
||||
name, &errp);
|
||||
if (errp) {
|
||||
qerror_report_err(errp);
|
||||
error_free(errp);
|
||||
return -1;
|
||||
}
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1175,44 +1138,79 @@ void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverS
|
|||
}
|
||||
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_CHR);
|
||||
Error *errp = NULL;
|
||||
assert(value->label);
|
||||
object_property_set_str(OBJECT(dev), value->label, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV);
|
||||
Error *errp = NULL;
|
||||
assert(value->name);
|
||||
object_property_set_str(OBJECT(dev), value->name, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN);
|
||||
Error *errp = NULL;
|
||||
object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
|
||||
Error *errp = NULL;
|
||||
char str[2 * 6 + 5 + 1];
|
||||
snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
value[0], value[1], value[2], value[3], value[4], value[5]);
|
||||
|
||||
object_property_set_str(OBJECT(dev), str, name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
|
||||
LostTickPolicy *value)
|
||||
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
|
||||
{
|
||||
qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
|
||||
Property *prop;
|
||||
Error *errp = NULL;
|
||||
|
||||
prop = qdev_prop_find(dev, name);
|
||||
object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
|
||||
name, &errp);
|
||||
assert(!errp);
|
||||
}
|
||||
|
||||
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
|
||||
{
|
||||
qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
|
||||
Property *prop;
|
||||
void **ptr;
|
||||
|
||||
prop = qdev_prop_find(dev, name);
|
||||
assert(prop && prop->info == &qdev_prop_ptr);
|
||||
ptr = qdev_get_prop_ptr(dev, prop);
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
void qdev_prop_set_defaults(DeviceState *dev, Property *props)
|
||||
{
|
||||
Object *obj = OBJECT(dev);
|
||||
if (!props)
|
||||
return;
|
||||
while (props->name) {
|
||||
if (props->defval) {
|
||||
qdev_prop_cpy(dev, props, props->defval);
|
||||
for (; props->name; props++) {
|
||||
Error *errp = NULL;
|
||||
if (props->qtype == QTYPE_NONE) {
|
||||
continue;
|
||||
}
|
||||
props++;
|
||||
if (props->qtype == QTYPE_QBOOL) {
|
||||
object_property_set_bool(obj, props->defval, props->name, &errp);
|
||||
} else if (props->info->enum_table) {
|
||||
object_property_set_str(obj, props->info->enum_table[props->defval],
|
||||
props->name, &errp);
|
||||
} else if (props->qtype == QTYPE_QINT) {
|
||||
object_property_set_int(obj, props->defval, props->name, &errp);
|
||||
}
|
||||
assert(!errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
32
hw/qdev.c
32
hw/qdev.c
|
@ -86,11 +86,11 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
|
|||
dev->parent_bus = bus;
|
||||
QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
|
||||
|
||||
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
||||
for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
|
||||
qdev_property_add_legacy(dev, prop, NULL);
|
||||
qdev_property_add_static(dev, prop, NULL);
|
||||
}
|
||||
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
||||
}
|
||||
|
||||
/* Create a new device. This only initializes the device state structure
|
||||
|
@ -550,21 +550,24 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
|
|||
* Do not use this is new code! Properties added through this interface will
|
||||
* be given names and types in the "legacy" namespace.
|
||||
*
|
||||
* Legacy properties are always processed as strings. The format of the string
|
||||
* depends on the property type.
|
||||
* Legacy properties are string versions of other OOM properties. The format
|
||||
* of the string depends on the property type.
|
||||
*/
|
||||
void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
||||
Error **errp)
|
||||
{
|
||||
gchar *name, *type;
|
||||
|
||||
if (!prop->info->print && !prop->info->parse) {
|
||||
return;
|
||||
}
|
||||
name = g_strdup_printf("legacy-%s", prop->name);
|
||||
type = g_strdup_printf("legacy<%s>",
|
||||
prop->info->legacy_name ?: prop->info->name);
|
||||
|
||||
object_property_add(OBJECT(dev), name, type,
|
||||
prop->info->print ? qdev_get_legacy_property : NULL,
|
||||
prop->info->parse ? qdev_set_legacy_property : NULL,
|
||||
prop->info->print ? qdev_get_legacy_property : prop->info->get,
|
||||
prop->info->parse ? qdev_set_legacy_property : prop->info->set,
|
||||
NULL,
|
||||
prop, errp);
|
||||
|
||||
|
@ -581,9 +584,18 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
|||
void qdev_property_add_static(DeviceState *dev, Property *prop,
|
||||
Error **errp)
|
||||
{
|
||||
/*
|
||||
* TODO qdev_prop_ptr does not have getters or setters. It must
|
||||
* go now that it can be replaced with links. The test should be
|
||||
* removed along with it: all static properties are read/write.
|
||||
*/
|
||||
if (!prop->info->get && !prop->info->set) {
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_add(OBJECT(dev), prop->name, prop->info->name,
|
||||
prop->info->get, prop->info->set,
|
||||
NULL,
|
||||
prop->info->release,
|
||||
prop, errp);
|
||||
}
|
||||
|
||||
|
@ -600,13 +612,13 @@ static void device_initfn(Object *obj)
|
|||
dev->instance_id_alias = -1;
|
||||
dev->state = DEV_STATE_CREATED;
|
||||
|
||||
qdev_prop_set_defaults(dev, qdev_get_props(dev));
|
||||
for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
|
||||
qdev_property_add_legacy(dev, prop, NULL);
|
||||
qdev_property_add_static(dev, prop, NULL);
|
||||
}
|
||||
|
||||
object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
|
||||
qdev_prop_set_defaults(dev, qdev_get_props(dev));
|
||||
}
|
||||
|
||||
/* Unlink device from bus and free the structure. */
|
||||
|
@ -614,7 +626,6 @@ static void device_finalize(Object *obj)
|
|||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
BusState *bus;
|
||||
Property *prop;
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (dev->state == DEV_STATE_INITIALIZED) {
|
||||
|
@ -633,11 +644,6 @@ static void device_finalize(Object *obj)
|
|||
}
|
||||
}
|
||||
QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
|
||||
for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
|
||||
if (prop->info->free) {
|
||||
prop->info->free(dev, prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void device_reset(DeviceState *dev)
|
||||
|
|
39
hw/qdev.h
39
hw/qdev.h
|
@ -112,41 +112,22 @@ struct Property {
|
|||
const char *name;
|
||||
PropertyInfo *info;
|
||||
int offset;
|
||||
int bitnr;
|
||||
void *defval;
|
||||
};
|
||||
|
||||
enum PropertyType {
|
||||
PROP_TYPE_UNSPEC = 0,
|
||||
PROP_TYPE_UINT8,
|
||||
PROP_TYPE_UINT16,
|
||||
PROP_TYPE_UINT32,
|
||||
PROP_TYPE_INT32,
|
||||
PROP_TYPE_UINT64,
|
||||
PROP_TYPE_TADDR,
|
||||
PROP_TYPE_MACADDR,
|
||||
PROP_TYPE_LOSTTICKPOLICY,
|
||||
PROP_TYPE_DRIVE,
|
||||
PROP_TYPE_CHR,
|
||||
PROP_TYPE_STRING,
|
||||
PROP_TYPE_NETDEV,
|
||||
PROP_TYPE_VLAN,
|
||||
PROP_TYPE_PTR,
|
||||
PROP_TYPE_BIT,
|
||||
uint8_t bitnr;
|
||||
uint8_t qtype;
|
||||
int64_t defval;
|
||||
};
|
||||
|
||||
struct PropertyInfo {
|
||||
const char *name;
|
||||
const char *legacy_name;
|
||||
size_t size;
|
||||
enum PropertyType type;
|
||||
const char **enum_table;
|
||||
int64_t min;
|
||||
int64_t max;
|
||||
int (*parse)(DeviceState *dev, Property *prop, const char *str);
|
||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||
void (*free)(DeviceState *dev, Property *prop);
|
||||
ObjectPropertyAccessor *get;
|
||||
ObjectPropertyAccessor *set;
|
||||
ObjectPropertyRelease *release;
|
||||
};
|
||||
|
||||
typedef struct GlobalProperty {
|
||||
|
@ -254,7 +235,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
|
|||
.info = &(_prop), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
.defval = (_type[]) { _defval }, \
|
||||
.qtype = QTYPE_QINT, \
|
||||
.defval = (_type)_defval, \
|
||||
}
|
||||
#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \
|
||||
.name = (_name), \
|
||||
|
@ -262,7 +244,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
|
|||
.bitnr = (_bit), \
|
||||
.offset = offsetof(_state, _field) \
|
||||
+ type_check(uint32_t,typeof_field(_state, _field)), \
|
||||
.defval = (bool[]) { (_defval) }, \
|
||||
.qtype = QTYPE_QBOOL, \
|
||||
.defval = (bool)_defval, \
|
||||
}
|
||||
|
||||
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
|
||||
|
@ -309,7 +292,6 @@ extern PropertyInfo qdev_prop_pci_devfn;
|
|||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
|
||||
int qdev_prop_exists(DeviceState *dev, const char *name);
|
||||
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
|
||||
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
|
||||
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
|
||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
|
||||
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
|
||||
|
@ -323,8 +305,7 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
|
|||
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
|
||||
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
|
||||
void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
|
||||
LostTickPolicy *value);
|
||||
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
|
||||
/* FIXME: Remove opaque pointer properties. */
|
||||
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
|
||||
void qdev_prop_set_defaults(DeviceState *dev, Property *props);
|
||||
|
|
|
@ -55,6 +55,9 @@ typedef struct InterfaceInfo InterfaceInfo;
|
|||
*
|
||||
* #define TYPE_MY_DEVICE "my-device"
|
||||
*
|
||||
* // No new virtual functions: we can reuse the typedef for the
|
||||
* // superclass.
|
||||
* typedef DeviceClass MyDeviceClass;
|
||||
* typedef struct MyDevice
|
||||
* {
|
||||
* DeviceState parent;
|
||||
|
@ -88,8 +91,21 @@ typedef struct InterfaceInfo InterfaceInfo;
|
|||
*
|
||||
* Using object_new(), a new #Object derivative will be instantiated. You can
|
||||
* cast an #Object to a subclass (or base-class) type using
|
||||
* object_dynamic_cast(). You typically want to define a macro wrapper around
|
||||
* object_dynamic_cast_assert() to make it easier to convert to a specific type.
|
||||
* object_dynamic_cast(). You typically want to define macro wrappers around
|
||||
* OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
|
||||
* specific type:
|
||||
*
|
||||
* <example>
|
||||
* <title>Typecasting macros</title>
|
||||
* <programlisting>
|
||||
* #define MY_DEVICE_GET_CLASS(obj) \
|
||||
* OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
|
||||
* #define MY_DEVICE_CLASS(klass) \
|
||||
* OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
|
||||
* #define MY_DEVICE(obj) \
|
||||
* OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* # Class Initialization #
|
||||
*
|
||||
|
@ -108,7 +124,61 @@ typedef struct InterfaceInfo InterfaceInfo;
|
|||
*
|
||||
* Once all of the parent classes have been initialized, #TypeInfo::class_init
|
||||
* is called to let the class being instantiated provide default initialize for
|
||||
* it's virtual functions.
|
||||
* it's virtual functions. Here is how the above example might be modified
|
||||
* to introduce an overridden virtual function:
|
||||
*
|
||||
* <example>
|
||||
* <title>Overriding a virtual function</title>
|
||||
* <programlisting>
|
||||
* #include "qdev.h"
|
||||
*
|
||||
* void my_device_class_init(ObjectClass *klass, void *class_data)
|
||||
* {
|
||||
* DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
* dc->reset = my_device_reset;
|
||||
* }
|
||||
*
|
||||
* static TypeInfo my_device_info = {
|
||||
* .name = TYPE_MY_DEVICE,
|
||||
* .parent = TYPE_DEVICE,
|
||||
* .instance_size = sizeof(MyDevice),
|
||||
* .class_init = my_device_class_init,
|
||||
* };
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* Introducing new virtual functions requires a class to define its own
|
||||
* struct and to add a .class_size member to the TypeInfo. Each function
|
||||
* will also have a wrapper to call it easily:
|
||||
*
|
||||
* <example>
|
||||
* <title>Defining an abstract class</title>
|
||||
* <programlisting>
|
||||
* #include "qdev.h"
|
||||
*
|
||||
* typedef struct MyDeviceClass
|
||||
* {
|
||||
* DeviceClass parent;
|
||||
*
|
||||
* void (*frobnicate) (MyDevice *obj);
|
||||
* } MyDeviceClass;
|
||||
*
|
||||
* static TypeInfo my_device_info = {
|
||||
* .name = TYPE_MY_DEVICE,
|
||||
* .parent = TYPE_DEVICE,
|
||||
* .instance_size = sizeof(MyDevice),
|
||||
* .abstract = true, // or set a default in my_device_class_init
|
||||
* .class_size = sizeof(MyDeviceClass),
|
||||
* };
|
||||
*
|
||||
* void my_device_frobnicate(MyDevice *obj)
|
||||
* {
|
||||
* MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj);
|
||||
*
|
||||
* klass->frobnicate(obj);
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* # Interfaces #
|
||||
*
|
||||
|
@ -258,6 +328,16 @@ struct TypeInfo
|
|||
#define OBJECT(obj) \
|
||||
((Object *)(obj))
|
||||
|
||||
/**
|
||||
* OBJECT_CLASS:
|
||||
* @class: A derivative of #ObjectClas.
|
||||
*
|
||||
* Converts a class to an #ObjectClass. Since all objects are #Objects,
|
||||
* this function will always succeed.
|
||||
*/
|
||||
#define OBJECT_CLASS(class) \
|
||||
((ObjectClass *)(class))
|
||||
|
||||
/**
|
||||
* OBJECT_CHECK:
|
||||
* @type: The C type to use for the return value.
|
||||
|
@ -272,7 +352,7 @@ struct TypeInfo
|
|||
* generated.
|
||||
*/
|
||||
#define OBJECT_CHECK(type, obj, name) \
|
||||
((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
|
||||
((type *)object_dynamic_cast_assert(OBJECT(obj), (name)))
|
||||
|
||||
/**
|
||||
* OBJECT_CLASS_CHECK:
|
||||
|
@ -280,11 +360,12 @@ struct TypeInfo
|
|||
* @obj: A derivative of @type to cast.
|
||||
* @name: the QOM typename of @class.
|
||||
*
|
||||
* A type safe version of @object_check_class. This macro is typically wrapped
|
||||
* by each type to perform type safe casts of a class to a specific class type.
|
||||
* A type safe version of @object_class_dynamic_cast_assert. This macro is
|
||||
* typically wrapped by each type to perform type safe casts of a class to a
|
||||
* specific class type.
|
||||
*/
|
||||
#define OBJECT_CLASS_CHECK(class, obj, name) \
|
||||
((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
|
||||
((class *)object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name)))
|
||||
|
||||
/**
|
||||
* OBJECT_GET_CLASS:
|
||||
|
@ -299,9 +380,6 @@ struct TypeInfo
|
|||
#define OBJECT_GET_CLASS(class, obj, name) \
|
||||
OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
|
||||
|
||||
#define OBJECT_CLASS(class) \
|
||||
((ObjectClass *)(class))
|
||||
|
||||
/**
|
||||
* InterfaceClass:
|
||||
* @parent_class: the base class
|
||||
|
@ -543,6 +621,100 @@ void object_unparent(Object *obj);
|
|||
void object_property_get(Object *obj, struct Visitor *v, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set_str:
|
||||
* @value: the value to be written to the property
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Writes a string value to a property.
|
||||
*/
|
||||
void object_property_set_str(Object *obj, const char *value,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_str:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, converted to a C string, or NULL if
|
||||
* an error occurs (including when the property value is not a string).
|
||||
* The caller should free the string.
|
||||
*/
|
||||
char *object_property_get_str(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set_link:
|
||||
* @value: the value to be written to the property
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Writes an object's canonical path to a property.
|
||||
*/
|
||||
void object_property_set_link(Object *obj, Object *value,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_link:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, resolved from a path to an Object,
|
||||
* or NULL if an error occurs (including when the property value is not a
|
||||
* string or not a valid object path).
|
||||
*/
|
||||
Object *object_property_get_link(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set_bool:
|
||||
* @value: the value to be written to the property
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Writes a bool value to a property.
|
||||
*/
|
||||
void object_property_set_bool(Object *obj, bool value,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_bool:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, converted to a boolean, or NULL if
|
||||
* an error occurs (including when the property value is not a bool).
|
||||
*/
|
||||
bool object_property_get_bool(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set_int:
|
||||
* @value: the value to be written to the property
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Writes an integer value to a property.
|
||||
*/
|
||||
void object_property_set_int(Object *obj, int64_t value,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_int:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, converted to an integer, or NULL if
|
||||
* an error occurs (including when the property value is not an integer).
|
||||
*/
|
||||
int64_t object_property_get_int(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set:
|
||||
* @obj: the object
|
||||
|
@ -601,13 +773,34 @@ gchar *object_get_canonical_path(Object *obj);
|
|||
* specifying objects easy. At each level of the composition tree, the partial
|
||||
* path is matched as an absolute path. The first match is not returned. At
|
||||
* least two matches are searched for. A successful result is only returned if
|
||||
* only one match is founded. If more than one match is found, a flag is
|
||||
* return to indicate that the match was ambiguous.
|
||||
* only one match is found. If more than one match is found, a flag is
|
||||
* returned to indicate that the match was ambiguous.
|
||||
*
|
||||
* Returns: The matched object or NULL on path lookup failure.
|
||||
*/
|
||||
Object *object_resolve_path(const char *path, bool *ambiguous);
|
||||
|
||||
/**
|
||||
* object_resolve_path_type:
|
||||
* @path: the path to resolve
|
||||
* @typename: the type to look for.
|
||||
* @ambiguous: returns true if the path resolution failed because of an
|
||||
* ambiguous match
|
||||
*
|
||||
* This is similar to object_resolve_path. However, when looking for a
|
||||
* partial path only matches that implement the given type are considered.
|
||||
* This restricts the search and avoids spuriously flagging matches as
|
||||
* ambiguous.
|
||||
*
|
||||
* For both partial and absolute paths, the return value goes through
|
||||
* a dynamic cast to @typename. This is important if either the link,
|
||||
* or the typename itself are of interface types.
|
||||
*
|
||||
* Returns: The matched object or NULL on path lookup failure.
|
||||
*/
|
||||
Object *object_resolve_path_type(const char *path, const char *typename,
|
||||
bool *ambiguous);
|
||||
|
||||
/**
|
||||
* object_property_add_child:
|
||||
* @obj: the object to add a property to
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* QEMU Object Model - QObject wrappers
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QEMU_QOM_QOBJECT_H
|
||||
#define QEMU_QOM_QOBJECT_H
|
||||
|
||||
#include "qemu/object.h"
|
||||
|
||||
/*
|
||||
* object_property_get_qobject:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns: the value of the property, converted to QObject, or NULL if
|
||||
* an error occurs.
|
||||
*/
|
||||
struct QObject *object_property_get_qobject(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_set_qobject:
|
||||
* @obj: the object
|
||||
* @ret: The value that will be written to the property.
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Writes a property to a object.
|
||||
*/
|
||||
void object_property_set_qobject(Object *obj, struct QObject *qobj,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
#endif
|
|
@ -255,6 +255,7 @@ typedef enum LostTickPolicy {
|
|||
LOST_TICK_DELAY,
|
||||
LOST_TICK_MERGE,
|
||||
LOST_TICK_SLEW,
|
||||
LOST_TICK_MAX
|
||||
} LostTickPolicy;
|
||||
|
||||
void tcg_exec_init(unsigned long tb_size);
|
||||
|
|
4
qerror.c
4
qerror.c
|
@ -47,6 +47,10 @@ static const QErrorStringTable qerror_table[] = {
|
|||
.error_fmt = QERR_ADD_CLIENT_FAILED,
|
||||
.desc = "Could not add client",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_AMBIGUOUS_PATH,
|
||||
.desc = "Path '%(path)' does not uniquely identify a %(object)"
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_BAD_BUS_FOR_DEVICE,
|
||||
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
|
||||
|
|
3
qerror.h
3
qerror.h
|
@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
|
|||
#define QERR_ADD_CLIENT_FAILED \
|
||||
"{ 'class': 'AddClientFailed', 'data': {} }"
|
||||
|
||||
#define QERR_AMBIGUOUS_PATH \
|
||||
"{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
|
||||
|
||||
#define QERR_BAD_BUS_FOR_DEVICE \
|
||||
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
|
||||
|
||||
|
|
18
qmp.c
18
qmp.c
|
@ -21,9 +21,8 @@
|
|||
#include "kvm.h"
|
||||
#include "arch_init.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "blockdev.h"
|
||||
#include "qemu/qom-qobject.h"
|
||||
|
||||
NameInfo *qmp_query_name(Error **errp)
|
||||
{
|
||||
|
@ -198,7 +197,6 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
|
|||
const char *property = qdict_get_str(qdict, "property");
|
||||
QObject *value = qdict_get(qdict, "value");
|
||||
Error *local_err = NULL;
|
||||
QmpInputVisitor *mi;
|
||||
Object *obj;
|
||||
|
||||
obj = object_resolve_path(path, NULL);
|
||||
|
@ -207,10 +205,7 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
|
|||
goto out;
|
||||
}
|
||||
|
||||
mi = qmp_input_visitor_new(value);
|
||||
object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
|
||||
|
||||
qmp_input_visitor_cleanup(mi);
|
||||
object_property_set_qobject(obj, value, property, &local_err);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
|
@ -227,7 +222,6 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
|
|||
const char *path = qdict_get_str(qdict, "path");
|
||||
const char *property = qdict_get_str(qdict, "property");
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *mo;
|
||||
Object *obj;
|
||||
|
||||
obj = object_resolve_path(path, NULL);
|
||||
|
@ -236,13 +230,7 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
|
|||
goto out;
|
||||
}
|
||||
|
||||
mo = qmp_output_visitor_new();
|
||||
object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
|
||||
if (!local_err) {
|
||||
*ret = qmp_output_get_qobject(mo);
|
||||
}
|
||||
|
||||
qmp_output_visitor_cleanup(mo);
|
||||
*ret = object_property_get_qobject(obj, property, &local_err);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
qom-y = object.o container.o
|
||||
qom-y = object.o container.o qom-qobject.o
|
||||
|
|
280
qom/object.c
280
qom/object.c
|
@ -13,8 +13,14 @@
|
|||
#include "qemu/object.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "hw/qdev.h"
|
||||
// FIXME remove above
|
||||
|
||||
/* TODO: replace QObject with a simpler visitor to avoid a dependency
|
||||
* of the QOM core on QObject? */
|
||||
#include "qemu/qom-qobject.h"
|
||||
#include "qobject.h"
|
||||
#include "qbool.h"
|
||||
#include "qint.h"
|
||||
#include "qstring.h"
|
||||
|
||||
#define MAX_INTERFACES 32
|
||||
|
||||
|
@ -63,6 +69,8 @@ typedef struct Interface
|
|||
|
||||
#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
|
||||
|
||||
static Type type_interface;
|
||||
|
||||
static GHashTable *type_table_get(void)
|
||||
{
|
||||
static GHashTable *type_table;
|
||||
|
@ -368,11 +376,9 @@ void object_delete(Object *obj)
|
|||
g_free(obj);
|
||||
}
|
||||
|
||||
static bool object_is_type(Object *obj, const char *typename)
|
||||
static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
|
||||
{
|
||||
TypeImpl *target_type = type_get_by_name(typename);
|
||||
TypeImpl *type = obj->class->type;
|
||||
GSList *i;
|
||||
assert(target_type);
|
||||
|
||||
/* Check if typename is a direct ancestor of type */
|
||||
while (type) {
|
||||
|
@ -383,24 +389,45 @@ static bool object_is_type(Object *obj, const char *typename)
|
|||
type = type_get_parent(type);
|
||||
}
|
||||
|
||||
/* Check if obj has an interface of typename */
|
||||
for (i = obj->interfaces; i; i = i->next) {
|
||||
Interface *iface = i->data;
|
||||
|
||||
if (object_is_type(OBJECT(iface), typename)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool object_is_type(Object *obj, TypeImpl *target_type)
|
||||
{
|
||||
return !target_type || type_is_ancestor(obj->class->type, target_type);
|
||||
}
|
||||
|
||||
Object *object_dynamic_cast(Object *obj, const char *typename)
|
||||
{
|
||||
TypeImpl *target_type = type_get_by_name(typename);
|
||||
GSList *i;
|
||||
|
||||
/* Check if typename is a direct ancestor */
|
||||
if (object_is_type(obj, typename)) {
|
||||
/* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
|
||||
* we want to go back from interfaces to the parent.
|
||||
*/
|
||||
if (target_type && object_is_type(obj, target_type)) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Check if obj is an interface and its containing object is a direct
|
||||
* ancestor of typename. In principle we could do this test at the very
|
||||
* beginning of object_dynamic_cast, avoiding a second call to
|
||||
* object_is_type. However, casting between interfaces is relatively
|
||||
* rare, and object_is_type(obj, type_interface) would fail almost always.
|
||||
*
|
||||
* Perhaps we could add a magic value to the object header for increased
|
||||
* (run-time) type safety and to speed up tests like this one. If we ever
|
||||
* do that we can revisit the order here.
|
||||
*/
|
||||
if (object_is_type(obj, type_interface)) {
|
||||
assert(!obj->interfaces);
|
||||
obj = INTERFACE(obj)->obj;
|
||||
if (object_is_type(obj, target_type)) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
if (!target_type) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -408,21 +435,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
|
|||
for (i = obj->interfaces; i; i = i->next) {
|
||||
Interface *iface = i->data;
|
||||
|
||||
if (object_is_type(OBJECT(iface), typename)) {
|
||||
if (object_is_type(OBJECT(iface), target_type)) {
|
||||
return OBJECT(iface);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if obj is an interface and its containing object is a direct
|
||||
* ancestor of typename */
|
||||
if (object_is_type(obj, TYPE_INTERFACE)) {
|
||||
Interface *iface = INTERFACE(obj);
|
||||
|
||||
if (object_is_type(iface->obj, typename)) {
|
||||
return iface->obj;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -435,7 +452,7 @@ static void register_interface(void)
|
|||
.abstract = true,
|
||||
};
|
||||
|
||||
type_register_static(&interface_info);
|
||||
type_interface = type_register_static(&interface_info);
|
||||
}
|
||||
|
||||
device_init(register_interface);
|
||||
|
@ -648,6 +665,123 @@ void object_property_set(Object *obj, Visitor *v, const char *name,
|
|||
}
|
||||
}
|
||||
|
||||
void object_property_set_str(Object *obj, const char *value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
QString *qstr = qstring_from_str(value);
|
||||
object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
|
||||
|
||||
QDECREF(qstr);
|
||||
}
|
||||
|
||||
char *object_property_get_str(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
QObject *ret = object_property_get_qobject(obj, name, errp);
|
||||
QString *qstring;
|
||||
char *retval;
|
||||
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
qstring = qobject_to_qstring(ret);
|
||||
if (!qstring) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
|
||||
retval = NULL;
|
||||
} else {
|
||||
retval = g_strdup(qstring_get_str(qstring));
|
||||
}
|
||||
|
||||
QDECREF(qstring);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void object_property_set_link(Object *obj, Object *value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
object_property_set_str(obj, object_get_canonical_path(value),
|
||||
name, errp);
|
||||
}
|
||||
|
||||
Object *object_property_get_link(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
char *str = object_property_get_str(obj, name, errp);
|
||||
Object *target = NULL;
|
||||
|
||||
if (str && *str) {
|
||||
target = object_resolve_path(str, NULL);
|
||||
if (!target) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, str);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
return target;
|
||||
}
|
||||
|
||||
void object_property_set_bool(Object *obj, bool value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
QBool *qbool = qbool_from_int(value);
|
||||
object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
|
||||
|
||||
QDECREF(qbool);
|
||||
}
|
||||
|
||||
bool object_property_get_bool(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
QObject *ret = object_property_get_qobject(obj, name, errp);
|
||||
QBool *qbool;
|
||||
bool retval;
|
||||
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
qbool = qobject_to_qbool(ret);
|
||||
if (!qbool) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
|
||||
retval = false;
|
||||
} else {
|
||||
retval = qbool_get_int(qbool);
|
||||
}
|
||||
|
||||
QDECREF(qbool);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void object_property_set_int(Object *obj, int64_t value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
QInt *qint = qint_from_int(value);
|
||||
object_property_set_qobject(obj, QOBJECT(qint), name, errp);
|
||||
|
||||
QDECREF(qint);
|
||||
}
|
||||
|
||||
int64_t object_property_get_int(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
QObject *ret = object_property_get_qobject(obj, name, errp);
|
||||
QInt *qint;
|
||||
int64_t retval;
|
||||
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
qint = qobject_to_qint(ret);
|
||||
if (!qint) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
|
||||
retval = -1;
|
||||
} else {
|
||||
retval = qint_get_int(qint);
|
||||
}
|
||||
|
||||
QDECREF(qint);
|
||||
return retval;
|
||||
}
|
||||
|
||||
const char *object_property_get_type(Object *obj, const char *name, Error **errp)
|
||||
{
|
||||
ObjectProperty *prop = object_property_find(obj, name);
|
||||
|
@ -695,6 +829,12 @@ void object_property_add_child(Object *obj, const char *name,
|
|||
{
|
||||
gchar *type;
|
||||
|
||||
/* Registering an interface object in the composition tree will mightily
|
||||
* confuse object_get_canonical_path (which, on the other hand, knows how
|
||||
* to get the canonical path of an interface object).
|
||||
*/
|
||||
assert(!object_is_type(obj, type_interface));
|
||||
|
||||
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
|
||||
|
||||
object_property_add(obj, name, type, object_get_child_property,
|
||||
|
@ -730,6 +870,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
|
|||
bool ambiguous = false;
|
||||
const char *type;
|
||||
char *path;
|
||||
gchar *target_type;
|
||||
|
||||
type = object_property_get_type(obj, name, NULL);
|
||||
|
||||
|
@ -737,31 +878,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
if (*child) {
|
||||
object_unref(*child);
|
||||
*child = NULL;
|
||||
}
|
||||
|
||||
if (strcmp(path, "") != 0) {
|
||||
Object *target;
|
||||
|
||||
target = object_resolve_path(path, &ambiguous);
|
||||
if (target) {
|
||||
gchar *target_type;
|
||||
/* Go from link<FOO> to FOO. */
|
||||
target_type = g_strndup(&type[5], strlen(type) - 6);
|
||||
target = object_resolve_path_type(path, target_type, &ambiguous);
|
||||
|
||||
target_type = g_strdup(&type[5]);
|
||||
target_type[strlen(target_type) - 2] = 0;
|
||||
|
||||
if (object_dynamic_cast(target, target_type)) {
|
||||
object_ref(target);
|
||||
*child = target;
|
||||
} else {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
|
||||
}
|
||||
|
||||
g_free(target_type);
|
||||
if (ambiguous) {
|
||||
error_set(errp, QERR_AMBIGUOUS_PATH, path);
|
||||
} else if (target) {
|
||||
object_ref(target);
|
||||
*child = target;
|
||||
} else {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
|
||||
target = object_resolve_path(path, &ambiguous);
|
||||
if (target || ambiguous) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
|
||||
} else {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*child = NULL;
|
||||
g_free(target_type);
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
|
@ -788,6 +928,10 @@ gchar *object_get_canonical_path(Object *obj)
|
|||
Object *root = object_get_root();
|
||||
char *newpath = NULL, *path = NULL;
|
||||
|
||||
if (object_is_type(obj, type_interface)) {
|
||||
obj = INTERFACE(obj)->obj;
|
||||
}
|
||||
|
||||
while (obj != root) {
|
||||
ObjectProperty *prop = NULL;
|
||||
|
||||
|
@ -823,17 +967,18 @@ gchar *object_get_canonical_path(Object *obj)
|
|||
|
||||
static Object *object_resolve_abs_path(Object *parent,
|
||||
gchar **parts,
|
||||
const char *typename,
|
||||
int index)
|
||||
{
|
||||
ObjectProperty *prop;
|
||||
Object *child;
|
||||
|
||||
if (parts[index] == NULL) {
|
||||
return parent;
|
||||
return object_dynamic_cast(parent, typename);
|
||||
}
|
||||
|
||||
if (strcmp(parts[index], "") == 0) {
|
||||
return object_resolve_abs_path(parent, parts, index + 1);
|
||||
return object_resolve_abs_path(parent, parts, typename, index + 1);
|
||||
}
|
||||
|
||||
prop = object_property_find(parent, parts[index]);
|
||||
|
@ -855,17 +1000,18 @@ static Object *object_resolve_abs_path(Object *parent,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return object_resolve_abs_path(child, parts, index + 1);
|
||||
return object_resolve_abs_path(child, parts, typename, index + 1);
|
||||
}
|
||||
|
||||
static Object *object_resolve_partial_path(Object *parent,
|
||||
gchar **parts,
|
||||
const char *typename,
|
||||
bool *ambiguous)
|
||||
{
|
||||
Object *obj;
|
||||
ObjectProperty *prop;
|
||||
|
||||
obj = object_resolve_abs_path(parent, parts, 0);
|
||||
obj = object_resolve_abs_path(parent, parts, typename, 0);
|
||||
|
||||
QTAILQ_FOREACH(prop, &parent->properties, node) {
|
||||
Object *found;
|
||||
|
@ -874,7 +1020,8 @@ static Object *object_resolve_partial_path(Object *parent,
|
|||
continue;
|
||||
}
|
||||
|
||||
found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
|
||||
found = object_resolve_partial_path(prop->opaque, parts,
|
||||
typename, ambiguous);
|
||||
if (found) {
|
||||
if (obj) {
|
||||
if (ambiguous) {
|
||||
|
@ -893,7 +1040,8 @@ static Object *object_resolve_partial_path(Object *parent,
|
|||
return obj;
|
||||
}
|
||||
|
||||
Object *object_resolve_path(const char *path, bool *ambiguous)
|
||||
Object *object_resolve_path_type(const char *path, const char *typename,
|
||||
bool *ambiguous)
|
||||
{
|
||||
bool partial_path = true;
|
||||
Object *obj;
|
||||
|
@ -913,9 +1061,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
|
|||
if (ambiguous) {
|
||||
*ambiguous = false;
|
||||
}
|
||||
obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
|
||||
obj = object_resolve_partial_path(object_get_root(), parts,
|
||||
typename, ambiguous);
|
||||
} else {
|
||||
obj = object_resolve_abs_path(object_get_root(), parts, 1);
|
||||
obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
|
||||
}
|
||||
|
||||
g_strfreev(parts);
|
||||
|
@ -923,14 +1072,19 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
|
|||
return obj;
|
||||
}
|
||||
|
||||
Object *object_resolve_path(const char *path, bool *ambiguous)
|
||||
{
|
||||
return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
|
||||
}
|
||||
|
||||
typedef struct StringProperty
|
||||
{
|
||||
char *(*get)(Object *, Error **);
|
||||
void (*set)(Object *, const char *, Error **);
|
||||
} StringProperty;
|
||||
|
||||
static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
static void property_get_str(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
StringProperty *prop = opaque;
|
||||
char *value;
|
||||
|
@ -942,8 +1096,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
|
|||
}
|
||||
}
|
||||
|
||||
static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
static void property_set_str(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
StringProperty *prop = opaque;
|
||||
char *value;
|
||||
|
@ -959,8 +1113,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
|
|||
g_free(value);
|
||||
}
|
||||
|
||||
static void object_property_release_str(Object *obj, const char *name,
|
||||
void *opaque)
|
||||
static void property_release_str(Object *obj, const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
StringProperty *prop = opaque;
|
||||
g_free(prop);
|
||||
|
@ -977,8 +1131,8 @@ void object_property_add_str(Object *obj, const char *name,
|
|||
prop->set = set;
|
||||
|
||||
object_property_add(obj, name, "string",
|
||||
get ? object_property_get_str : NULL,
|
||||
set ? object_property_set_str : NULL,
|
||||
object_property_release_str,
|
||||
get ? property_get_str : NULL,
|
||||
set ? property_set_str : NULL,
|
||||
property_release_str,
|
||||
prop, errp);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* QEMU Object Model - QObject wrappers
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/object.h"
|
||||
#include "qemu/qom-qobject.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
|
||||
void object_property_set_qobject(Object *obj, QObject *value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
QmpInputVisitor *mi;
|
||||
mi = qmp_input_visitor_new(value);
|
||||
object_property_set(obj, qmp_input_get_visitor(mi), name, errp);
|
||||
|
||||
qmp_input_visitor_cleanup(mi);
|
||||
}
|
||||
|
||||
QObject *object_property_get_qobject(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
QObject *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *mo;
|
||||
|
||||
mo = qmp_output_visitor_new();
|
||||
object_property_get(obj, qmp_output_get_visitor(mo), name, &local_err);
|
||||
if (!local_err) {
|
||||
ret = qmp_output_get_qobject(mo);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
qmp_output_visitor_cleanup(mo);
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue