diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2009-07-15 13:43:31 +0200 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2009-07-16 17:28:51 -0500 |
commit | ee6847d19be16c789b8bd4e553b7cd6701ba1245 (patch) | |
tree | 41845b3b1e8740ce97daf0582e124c6b6e0a6873 /hw/qdev-properties.c | |
parent | f114784f69ec3b9af342148025de14dbd1b429a5 (diff) |
qdev: rework device properties.
This patch is a major overhaul of the device properties. The properties
are saved directly in the device state struct now, the linked list of
property values is gone.
Advantages:
* We don't have to maintain the list with the property values.
* The value in the property list and the value actually used by
the device can't go out of sync any more (used to happen for
the pci.devfn == -1 case) because there is only one place where
the value is stored.
* A record describing the property is required now, you can't set
random properties any more.
There are bus-specific and device-specific properties. The former
should be used for properties common to all bus drivers. Typical
use case is bus addressing, i.e. pci.devfn and i2c.address.
Properties have a PropertyInfo struct attached with name, size and
function pointers to parse and print properties. A few common property
types have PropertyInfos defined in qdev-properties.c. Drivers are free
to implement their own very special property parsers if needed.
Properties can have default values. If unset they are zero-filled.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/qdev-properties.c')
-rw-r--r-- | hw/qdev-properties.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c new file mode 100644 index 0000000000..8b0d0ffce7 --- /dev/null +++ b/hw/qdev-properties.c @@ -0,0 +1,246 @@ +#include "qdev.h" + +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) +{ + void *ptr = dev; + ptr += prop->offset; + return ptr; +} + +/* --- 16bit integer --- */ + +static int parse_uint16(DeviceState *dev, Property *prop, const char *str) +{ + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + const char *fmt; + + /* accept both hex and decimal */ + fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx16 : "%" PRIu16; + if (sscanf(str, fmt, ptr) != 1) + return -1; + return 0; +} + +static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "%" PRIu16, *ptr); +} + +PropertyInfo qdev_prop_uint16 = { + .name = "uint16", + .type = PROP_TYPE_UINT16, + .size = sizeof(uint16_t), + .parse = parse_uint16, + .print = print_uint16, +}; + +/* --- 32bit integer --- */ + +static int parse_uint32(DeviceState *dev, Property *prop, const char *str) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + const char *fmt; + + /* accept both hex and decimal */ + fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx32 : "%" PRIu32; + if (sscanf(str, fmt, ptr) != 1) + return -1; + return 0; +} + +static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "%" PRIu32, *ptr); +} + +PropertyInfo qdev_prop_uint32 = { + .name = "uint32", + .type = PROP_TYPE_UINT32, + .size = sizeof(uint32_t), + .parse = parse_uint32, + .print = print_uint32, +}; + +/* --- 32bit hex value --- */ + +static int parse_hex32(DeviceState *dev, Property *prop, const char *str) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (sscanf(str, "%" PRIx32, ptr) != 1) + return -1; + return 0; +} + +static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "0x%" PRIx32, *ptr); +} + +PropertyInfo qdev_prop_hex32 = { + .name = "hex32", + .type = PROP_TYPE_UINT32, + .size = sizeof(uint32_t), + .parse = parse_hex32, + .print = print_hex32, +}; + +/* --- pointer --- */ + +static int print_ptr(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + void **ptr = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "<%p>", *ptr); +} + +PropertyInfo qdev_prop_ptr = { + .name = "ptr", + .type = PROP_TYPE_PTR, + .size = sizeof(void*), + .print = print_ptr, +}; + +/* --- mac address --- */ + +/* + * accepted syntax versions: + * 01:02:03:04:05:06 + * 01-02-03-04-05-06 + */ +static int parse_mac(DeviceState *dev, Property *prop, const char *str) +{ + uint8_t *mac = qdev_get_prop_ptr(dev, prop); + int i, pos; + char *p; + + for (i = 0, pos = 0; i < 6; i++, pos += 3) { + if (!isxdigit(str[pos])) + return -1; + if (!isxdigit(str[pos+1])) + return -1; + if (i == 5 && str[pos+2] != '\0') + return -1; + if (str[pos+2] != ':' && str[pos+2] != '-') + return -1; + mac[i] = strtol(str+pos, &p, 16); + } + return 0; +} + +static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + uint8_t *mac = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +PropertyInfo qdev_prop_macaddr = { + .name = "mac-addr", + .type = PROP_TYPE_MACADDR, + .size = 6, + .parse = parse_mac, + .print = print_mac, +}; + +/* --- public helpers --- */ + +static Property *qdev_prop_walk(Property *props, const char *name) +{ + if (!props) + return NULL; + while (props->name) { + if (strcmp(props->name, name) == 0) + return props; + props++; + } + return NULL; +} + +static Property *qdev_prop_find(DeviceState *dev, const char *name) +{ + Property *prop; + + /* device properties */ + prop = qdev_prop_walk(dev->info->props, name); + if (prop) + return prop; + + /* bus properties */ + prop = qdev_prop_walk(dev->parent_bus->info->props, name); + if (prop) + return prop; + + return NULL; +} + +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) +{ + Property *prop; + + prop = qdev_prop_find(dev, name); + if (!prop) { + fprintf(stderr, "property \"%s.%s\" not found\n", + dev->info->name, name); + return -1; + } + if (!prop->info->parse) { + fprintf(stderr, "property \"%s.%s\" has no parser\n", + dev->info->name, name); + return -1; + } + return prop->info->parse(dev, prop, value); +} + +void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) +{ + Property *prop; + void *dst; + + prop = qdev_prop_find(dev, name); + if (!prop) { + fprintf(stderr, "%s: property \"%s.%s\" not found\n", + __FUNCTION__, dev->info->name, name); + abort(); + } + if (prop->info->type != type) { + fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", + __FUNCTION__, dev->info->name, name); + abort(); + } + dst = qdev_get_prop_ptr(dev, prop); + memcpy(dst, src, prop->info->size); +} + +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) +{ + qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); +} + +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) +{ + qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); +} + +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) +{ + qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); +} + +void qdev_prop_set_defaults(DeviceState *dev, Property *props) +{ + char *dst; + + if (!props) + return; + while (props->name) { + if (props->defval) { + dst = qdev_get_prop_ptr(dev, props); + memcpy(dst, props->defval, props->info->size); + } + props++; + } +} + |