qom: introduce get/set methods for Property

This patch adds a visitor interface to Property.  This way, QOM will be
able to expose Properties that access a fixed field in a struct without
exposing also the everything-is-a-string "feature" of qdev properties.

Whenever the printed representation in both QOM and qdev (which is
typically the case for device backends), parse/print code can be reused
via get_generic/set_generic.  Dually, whenever multiple PropertyInfos
have the same representation in both the struct and the visitors the
code can be reused (for example among all of int32/uint32/hex32).

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Paolo Bonzini 2011-12-18 17:05:09 +01:00 committed by Anthony Liguori
parent 6aced82c4f
commit 80e555c241
3 changed files with 399 additions and 0 deletions

View File

@ -18,12 +18,53 @@ static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
}
static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
value = *ptr;
visit_type_int(v, &value, name, errp);
}
static void set_taddr(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
int64_t value;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if ((uint64_t)value <= (uint64_t) ~(target_phys_addr_t)0) {
*ptr = value;
} else {
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
dev->id?:"", name, value, (uint64_t) 0,
(uint64_t) ~(target_phys_addr_t)0);
}
}
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,
.set = set_taddr,
};
void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value)

View File

@ -55,12 +55,44 @@ static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
}
static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
uint32_t *p = qdev_get_prop_ptr(dev, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
visit_type_bool(v, &value, name, errp);
}
static void set_bit(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
Error *local_err = NULL;
bool value;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_bool(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
bit_prop_set(dev, prop, value);
}
PropertyInfo qdev_prop_bit = {
.name = "on/off",
.type = PROP_TYPE_BIT,
.size = sizeof(uint32_t),
.parse = parse_bit,
.print = print_bit,
.get = get_bit,
.set = set_bit,
};
/* --- 8bit integer --- */
@ -85,12 +117,54 @@ static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "%" PRIu8, *ptr);
}
static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
value = *ptr;
visit_type_int(v, &value, name, errp);
}
static void set_int8(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
int64_t value;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (value > prop->info->min && value <= prop->info->max) {
*ptr = value;
} else {
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
dev->id?:"", name, value, prop->info->min,
prop->info->max);
}
}
PropertyInfo qdev_prop_uint8 = {
.name = "uint8",
.type = PROP_TYPE_UINT8,
.size = sizeof(uint8_t),
.parse = parse_uint8,
.print = print_uint8,
.get = get_int8,
.set = set_int8,
.min = 0,
.max = 255,
};
/* --- 8bit hex value --- */
@ -120,6 +194,10 @@ PropertyInfo qdev_prop_hex8 = {
.size = sizeof(uint8_t),
.parse = parse_hex8,
.print = print_hex8,
.get = get_int8,
.set = set_int8,
.min = 0,
.max = 255,
};
/* --- 16bit integer --- */
@ -144,12 +222,54 @@ static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu16, *ptr);
}
static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
value = *ptr;
visit_type_int(v, &value, name, errp);
}
static void set_int16(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
int64_t value;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (value > prop->info->min && value <= prop->info->max) {
*ptr = value;
} else {
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
dev->id?:"", name, value, prop->info->min,
prop->info->max);
}
}
PropertyInfo qdev_prop_uint16 = {
.name = "uint16",
.type = PROP_TYPE_UINT16,
.size = sizeof(uint16_t),
.parse = parse_uint16,
.print = print_uint16,
.get = get_int16,
.set = set_int16,
.min = 0,
.max = 65535,
};
/* --- 32bit integer --- */
@ -174,12 +294,54 @@ static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu32, *ptr);
}
static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
value = *ptr;
visit_type_int(v, &value, name, errp);
}
static void set_int32(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
int64_t value;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (value > prop->info->min && value <= prop->info->max) {
*ptr = value;
} else {
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
dev->id?:"", name, value, prop->info->min,
prop->info->max);
}
}
PropertyInfo qdev_prop_uint32 = {
.name = "uint32",
.type = PROP_TYPE_UINT32,
.size = sizeof(uint32_t),
.parse = parse_uint32,
.print = print_uint32,
.get = get_int32,
.set = set_int32,
.min = 0,
.max = 0xFFFFFFFFULL,
};
static int parse_int32(DeviceState *dev, Property *prop, const char *str)
@ -207,6 +369,10 @@ PropertyInfo qdev_prop_int32 = {
.size = sizeof(int32_t),
.parse = parse_int32,
.print = print_int32,
.get = get_int32,
.set = set_int32,
.min = -0x80000000LL,
.max = 0x7FFFFFFFLL,
};
/* --- 32bit hex value --- */
@ -236,6 +402,10 @@ PropertyInfo qdev_prop_hex32 = {
.size = sizeof(uint32_t),
.parse = parse_hex32,
.print = print_hex32,
.get = get_int32,
.set = set_int32,
.min = 0,
.max = 0xFFFFFFFFULL,
};
/* --- 64bit integer --- */
@ -260,12 +430,37 @@ static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu64, *ptr);
}
static void get_int64(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
visit_type_int(v, ptr, name, errp);
}
static void set_int64(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, ptr, name, errp);
}
PropertyInfo qdev_prop_uint64 = {
.name = "uint64",
.type = PROP_TYPE_UINT64,
.size = sizeof(uint64_t),
.parse = parse_uint64,
.print = print_uint64,
.get = get_int64,
.set = set_int64,
};
/* --- 64bit hex value --- */
@ -295,6 +490,8 @@ PropertyInfo qdev_prop_hex64 = {
.size = sizeof(uint64_t),
.parse = parse_hex64,
.print = print_hex64,
.get = get_int64,
.set = set_int64,
};
/* --- string --- */
@ -322,6 +519,48 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "\"%s\"", *ptr);
}
static void get_string(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
if (!*ptr) {
char *str = (char *)"";
visit_type_str(v, &str, name, errp);
} else {
visit_type_str(v, ptr, name, errp);
}
}
static void set_string(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
char *str;
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;
}
if (!*str) {
g_free(str);
str = NULL;
}
if (*ptr) {
g_free(*ptr);
}
*ptr = str;
}
PropertyInfo qdev_prop_string = {
.name = "string",
.type = PROP_TYPE_STRING,
@ -329,6 +568,8 @@ PropertyInfo qdev_prop_string = {
.parse = parse_string,
.print = print_string,
.free = free_string,
.get = get_string,
.set = set_string,
};
/* --- drive --- */
@ -364,12 +605,57 @@ static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
*ptr ? bdrv_get_device_name(*ptr) : "<null>");
}
static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
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(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
Error *local_err = NULL;
char *str;
int ret;
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;
}
if (!*str) {
g_free(str);
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
return;
}
ret = prop->info->parse(dev, prop, str);
error_set_from_qdev_prop_error(errp, ret, dev, prop, str);
g_free(str);
}
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,
};
@ -407,6 +693,8 @@ PropertyInfo qdev_prop_chr = {
.size = sizeof(CharDriverState*),
.parse = parse_chr,
.print = print_chr,
.get = get_generic,
.set = set_generic,
};
/* --- netdev device --- */
@ -441,6 +729,8 @@ PropertyInfo qdev_prop_netdev = {
.size = sizeof(VLANClientState*),
.parse = parse_netdev,
.print = print_netdev,
.get = get_generic,
.set = set_generic,
};
/* --- vlan --- */
@ -469,12 +759,57 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
}
}
static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
int64_t id;
id = *ptr ? (*ptr)->id : -1;
visit_type_int(v, &id, name, errp);
}
static void set_vlan(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
int64_t id;
VLANState *vlan;
if (dev->state != DEV_STATE_CREATED) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
visit_type_int(v, &id, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (id == -1) {
*ptr = NULL;
return;
}
vlan = qemu_find_vlan(id, 1);
if (!vlan) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
name, prop->info->name);
return;
}
*ptr = vlan;
}
PropertyInfo qdev_prop_vlan = {
.name = "vlan",
.type = PROP_TYPE_VLAN,
.size = sizeof(VLANClientState*),
.parse = parse_vlan,
.print = print_vlan,
.get = get_vlan,
.set = set_vlan,
};
/* --- pointer --- */
@ -531,6 +866,8 @@ PropertyInfo qdev_prop_macaddr = {
.size = sizeof(MACAddr),
.parse = parse_mac,
.print = print_mac,
.get = get_generic,
.set = set_generic,
};
/* --- pci address --- */
@ -570,12 +907,29 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
}
}
static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
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),
.parse = parse_pci_devfn,
.print = print_pci_devfn,
.get = get_pci_devfn,
.set = set_generic,
};
/* --- public helpers --- */

View File

@ -158,9 +158,13 @@ struct PropertyInfo {
const char *name;
size_t size;
enum PropertyType type;
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);
DevicePropertyAccessor *get;
DevicePropertyAccessor *set;
};
typedef struct GlobalProperty {