]> git.proxmox.com Git - mirror_qemu.git/blame - hw/qdev-properties.c
qdev/prop: macros for creating typechecked properties.
[mirror_qemu.git] / hw / qdev-properties.c
CommitLineData
14b41872 1#include "sysemu.h"
ee6847d1
GH
2#include "qdev.h"
3
4void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
5{
6 void *ptr = dev;
7 ptr += prop->offset;
8 return ptr;
9}
10
11/* --- 16bit integer --- */
12
13static int parse_uint16(DeviceState *dev, Property *prop, const char *str)
14{
15 uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
16 const char *fmt;
17
18 /* accept both hex and decimal */
19 fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx16 : "%" PRIu16;
20 if (sscanf(str, fmt, ptr) != 1)
21 return -1;
22 return 0;
23}
24
25static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len)
26{
27 uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
28 return snprintf(dest, len, "%" PRIu16, *ptr);
29}
30
31PropertyInfo qdev_prop_uint16 = {
32 .name = "uint16",
33 .type = PROP_TYPE_UINT16,
34 .size = sizeof(uint16_t),
35 .parse = parse_uint16,
36 .print = print_uint16,
37};
38
39/* --- 32bit integer --- */
40
41static int parse_uint32(DeviceState *dev, Property *prop, const char *str)
42{
43 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
44 const char *fmt;
45
46 /* accept both hex and decimal */
47 fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx32 : "%" PRIu32;
48 if (sscanf(str, fmt, ptr) != 1)
49 return -1;
50 return 0;
51}
52
53static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len)
54{
55 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
56 return snprintf(dest, len, "%" PRIu32, *ptr);
57}
58
59PropertyInfo qdev_prop_uint32 = {
60 .name = "uint32",
61 .type = PROP_TYPE_UINT32,
62 .size = sizeof(uint32_t),
63 .parse = parse_uint32,
64 .print = print_uint32,
65};
66
67/* --- 32bit hex value --- */
68
69static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
70{
71 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
72
73 if (sscanf(str, "%" PRIx32, ptr) != 1)
74 return -1;
75 return 0;
76}
77
78static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
79{
80 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
81 return snprintf(dest, len, "0x%" PRIx32, *ptr);
82}
83
84PropertyInfo qdev_prop_hex32 = {
85 .name = "hex32",
86 .type = PROP_TYPE_UINT32,
87 .size = sizeof(uint32_t),
88 .parse = parse_hex32,
89 .print = print_hex32,
90};
91
5a053d1f
BS
92/* --- 64bit integer --- */
93
94static int parse_uint64(DeviceState *dev, Property *prop, const char *str)
95{
96 uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
97 const char *fmt;
98
99 /* accept both hex and decimal */
100 fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx64 : "%" PRIu64;
101 if (sscanf(str, fmt, ptr) != 1)
102 return -1;
103 return 0;
104}
105
106static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len)
107{
108 uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
109 return snprintf(dest, len, "%" PRIu64, *ptr);
110}
111
112PropertyInfo qdev_prop_uint64 = {
113 .name = "uint64",
114 .type = PROP_TYPE_UINT64,
115 .size = sizeof(uint64_t),
116 .parse = parse_uint64,
117 .print = print_uint64,
118};
119
120/* --- 64bit hex value --- */
121
122static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
123{
124 uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
125
126 if (sscanf(str, "%" PRIx64, ptr) != 1)
127 return -1;
128 return 0;
129}
130
131static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
132{
133 uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
134 return snprintf(dest, len, "0x%" PRIx64, *ptr);
135}
136
137PropertyInfo qdev_prop_hex64 = {
138 .name = "hex64",
139 .type = PROP_TYPE_UINT64,
140 .size = sizeof(uint64_t),
141 .parse = parse_hex64,
142 .print = print_hex64,
143};
144
14b41872
GH
145/* --- drive --- */
146
147static int parse_drive(DeviceState *dev, Property *prop, const char *str)
148{
149 DriveInfo **ptr = qdev_get_prop_ptr(dev, prop);
150
151 *ptr = drive_get_by_id(str);
152 if (*ptr == NULL)
153 return -1;
154 return 0;
155}
156
157static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
158{
159 DriveInfo **ptr = qdev_get_prop_ptr(dev, prop);
160 return snprintf(dest, len, "%s", (*ptr)->id);
161}
162
163PropertyInfo qdev_prop_drive = {
164 .name = "drive",
165 .type = PROP_TYPE_DRIVE,
166 .size = sizeof(DriveInfo*),
167 .parse = parse_drive,
168 .print = print_drive,
169};
170
ee6847d1
GH
171/* --- pointer --- */
172
173static int print_ptr(DeviceState *dev, Property *prop, char *dest, size_t len)
174{
175 void **ptr = qdev_get_prop_ptr(dev, prop);
176 return snprintf(dest, len, "<%p>", *ptr);
177}
178
179PropertyInfo qdev_prop_ptr = {
180 .name = "ptr",
181 .type = PROP_TYPE_PTR,
182 .size = sizeof(void*),
183 .print = print_ptr,
184};
185
186/* --- mac address --- */
187
188/*
189 * accepted syntax versions:
190 * 01:02:03:04:05:06
191 * 01-02-03-04-05-06
192 */
193static int parse_mac(DeviceState *dev, Property *prop, const char *str)
194{
195 uint8_t *mac = qdev_get_prop_ptr(dev, prop);
196 int i, pos;
197 char *p;
198
199 for (i = 0, pos = 0; i < 6; i++, pos += 3) {
88e150a5 200 if (!qemu_isxdigit(str[pos]))
ee6847d1 201 return -1;
88e150a5 202 if (!qemu_isxdigit(str[pos+1]))
ee6847d1
GH
203 return -1;
204 if (i == 5 && str[pos+2] != '\0')
205 return -1;
206 if (str[pos+2] != ':' && str[pos+2] != '-')
207 return -1;
208 mac[i] = strtol(str+pos, &p, 16);
209 }
210 return 0;
211}
212
213static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len)
214{
215 uint8_t *mac = qdev_get_prop_ptr(dev, prop);
216 return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
217 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
218}
219
220PropertyInfo qdev_prop_macaddr = {
221 .name = "mac-addr",
222 .type = PROP_TYPE_MACADDR,
223 .size = 6,
224 .parse = parse_mac,
225 .print = print_mac,
226};
227
05cb5fe4
GH
228/* --- pci address --- */
229
230/*
231 * bus-local address, i.e. "$slot" or "$slot.$fn"
232 */
233static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
234{
235 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
236 unsigned int slot, fn, n;
237
238 if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
239 fn = 0;
240 if (sscanf(str, "%x%n", &slot, &n) != 1) {
241 return -1;
242 }
243 }
244 if (str[n] != '\0')
245 return -1;
246 if (fn > 7)
247 return -1;
248 *ptr = slot << 3 | fn;
249 return 0;
250}
251
252static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
253{
254 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
255
256 if (-1 == *ptr) {
257 return snprintf(dest, len, "<unset>");
258 } else {
259 return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
260 }
261}
262
263PropertyInfo qdev_prop_pci_devfn = {
264 .name = "pci-devfn",
265 .type = PROP_TYPE_UINT32,
266 .size = sizeof(uint32_t),
267 .parse = parse_pci_devfn,
268 .print = print_pci_devfn,
269};
270
ee6847d1
GH
271/* --- public helpers --- */
272
273static Property *qdev_prop_walk(Property *props, const char *name)
274{
275 if (!props)
276 return NULL;
277 while (props->name) {
278 if (strcmp(props->name, name) == 0)
279 return props;
280 props++;
281 }
282 return NULL;
283}
284
285static Property *qdev_prop_find(DeviceState *dev, const char *name)
286{
287 Property *prop;
288
289 /* device properties */
290 prop = qdev_prop_walk(dev->info->props, name);
291 if (prop)
292 return prop;
293
294 /* bus properties */
295 prop = qdev_prop_walk(dev->parent_bus->info->props, name);
296 if (prop)
297 return prop;
298
299 return NULL;
300}
301
302int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
303{
304 Property *prop;
305
306 prop = qdev_prop_find(dev, name);
307 if (!prop) {
308 fprintf(stderr, "property \"%s.%s\" not found\n",
309 dev->info->name, name);
310 return -1;
311 }
312 if (!prop->info->parse) {
313 fprintf(stderr, "property \"%s.%s\" has no parser\n",
314 dev->info->name, name);
315 return -1;
316 }
317 return prop->info->parse(dev, prop, value);
318}
319
320void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
321{
322 Property *prop;
323 void *dst;
324
325 prop = qdev_prop_find(dev, name);
326 if (!prop) {
327 fprintf(stderr, "%s: property \"%s.%s\" not found\n",
328 __FUNCTION__, dev->info->name, name);
329 abort();
330 }
331 if (prop->info->type != type) {
332 fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
333 __FUNCTION__, dev->info->name, name);
334 abort();
335 }
336 dst = qdev_get_prop_ptr(dev, prop);
337 memcpy(dst, src, prop->info->size);
338}
339
340void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
341{
342 qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16);
343}
344
345void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
346{
347 qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32);
348}
349
5a053d1f
BS
350void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
351{
352 qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
353}
354
14b41872
GH
355void qdev_prop_set_drive(DeviceState *dev, const char *name, DriveInfo *value)
356{
357 qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
358}
359
ee6847d1
GH
360void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
361{
362 qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
363}
364
365void qdev_prop_set_defaults(DeviceState *dev, Property *props)
366{
367 char *dst;
368
369 if (!props)
370 return;
371 while (props->name) {
372 if (props->defval) {
373 dst = qdev_get_prop_ptr(dev, props);
374 memcpy(dst, props->defval, props->info->size);
375 }
376 props++;
377 }
378}
379
b6b61144
GH
380static CompatProperty *compat_props;
381
382void qdev_prop_register_compat(CompatProperty *props)
383{
384 compat_props = props;
385}
386
387void qdev_prop_set_compat(DeviceState *dev)
388{
389 CompatProperty *prop;
390
391 if (!compat_props) {
392 return;
393 }
394 for (prop = compat_props; prop->driver != NULL; prop++) {
395 if (strcmp(dev->info->name, prop->driver) != 0) {
396 continue;
397 }
398 if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
399 abort();
400 }
401 }
402}