]>
Commit | Line | Data |
---|---|---|
1503fff3 | 1 | #include "net.h" |
ee6847d1 | 2 | #include "qdev.h" |
9f59b566 | 3 | #include "qerror.h" |
2446333c | 4 | #include "blockdev.h" |
ee6847d1 GH |
5 | |
6 | void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) | |
7 | { | |
8 | void *ptr = dev; | |
9 | ptr += prop->offset; | |
10 | return ptr; | |
11 | } | |
12 | ||
d2364ee4 MT |
13 | static uint32_t qdev_get_prop_mask(Property *prop) |
14 | { | |
15 | assert(prop->info->type == PROP_TYPE_BIT); | |
16 | return 0x1 << prop->bitnr; | |
17 | } | |
18 | ||
19 | static void bit_prop_set(DeviceState *dev, Property *props, bool val) | |
20 | { | |
21 | uint32_t *p = qdev_get_prop_ptr(dev, props); | |
22 | uint32_t mask = qdev_get_prop_mask(props); | |
23 | if (val) | |
dbd48324 | 24 | *p |= mask; |
d2364ee4 MT |
25 | else |
26 | *p &= ~mask; | |
27 | } | |
28 | ||
29 | static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src) | |
30 | { | |
31 | if (props->info->type == PROP_TYPE_BIT) { | |
32 | bool *defval = src; | |
33 | bit_prop_set(dev, props, *defval); | |
34 | } else { | |
35 | char *dst = qdev_get_prop_ptr(dev, props); | |
36 | memcpy(dst, src, props->info->size); | |
37 | } | |
38 | } | |
39 | ||
40 | /* Bit */ | |
41 | static int parse_bit(DeviceState *dev, Property *prop, const char *str) | |
42 | { | |
43 | if (!strncasecmp(str, "on", 2)) | |
44 | bit_prop_set(dev, prop, true); | |
45 | else if (!strncasecmp(str, "off", 3)) | |
46 | bit_prop_set(dev, prop, false); | |
47 | else | |
6bf38816 | 48 | return -EINVAL; |
d2364ee4 MT |
49 | return 0; |
50 | } | |
51 | ||
52 | static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) | |
53 | { | |
5a5e3d55 | 54 | uint32_t *p = qdev_get_prop_ptr(dev, prop); |
d2364ee4 MT |
55 | return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); |
56 | } | |
57 | ||
80e555c2 PB |
58 | static void get_bit(DeviceState *dev, Visitor *v, void *opaque, |
59 | const char *name, Error **errp) | |
60 | { | |
61 | Property *prop = opaque; | |
62 | uint32_t *p = qdev_get_prop_ptr(dev, prop); | |
63 | bool value = (*p & qdev_get_prop_mask(prop)) != 0; | |
64 | ||
65 | visit_type_bool(v, &value, name, errp); | |
66 | } | |
67 | ||
68 | static void set_bit(DeviceState *dev, Visitor *v, void *opaque, | |
69 | const char *name, Error **errp) | |
70 | { | |
71 | Property *prop = opaque; | |
72 | Error *local_err = NULL; | |
73 | bool value; | |
74 | ||
75 | if (dev->state != DEV_STATE_CREATED) { | |
76 | error_set(errp, QERR_PERMISSION_DENIED); | |
77 | return; | |
78 | } | |
79 | ||
80 | visit_type_bool(v, &value, name, &local_err); | |
81 | if (local_err) { | |
82 | error_propagate(errp, local_err); | |
83 | return; | |
84 | } | |
85 | bit_prop_set(dev, prop, value); | |
86 | } | |
87 | ||
d2364ee4 | 88 | PropertyInfo qdev_prop_bit = { |
cafe5bdb PB |
89 | .name = "boolean", |
90 | .legacy_name = "on/off", | |
d2364ee4 MT |
91 | .type = PROP_TYPE_BIT, |
92 | .size = sizeof(uint32_t), | |
93 | .parse = parse_bit, | |
94 | .print = print_bit, | |
80e555c2 PB |
95 | .get = get_bit, |
96 | .set = set_bit, | |
d2364ee4 MT |
97 | }; |
98 | ||
c7cc172d JQ |
99 | /* --- 8bit integer --- */ |
100 | ||
101 | static int parse_uint8(DeviceState *dev, Property *prop, const char *str) | |
102 | { | |
103 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 104 | char *end; |
c7cc172d JQ |
105 | |
106 | /* accept both hex and decimal */ | |
449041d4 KW |
107 | *ptr = strtoul(str, &end, 0); |
108 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 109 | return -EINVAL; |
449041d4 KW |
110 | } |
111 | ||
c7cc172d JQ |
112 | return 0; |
113 | } | |
114 | ||
115 | static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) | |
116 | { | |
117 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
118 | return snprintf(dest, len, "%" PRIu8, *ptr); | |
119 | } | |
120 | ||
80e555c2 PB |
121 | static void get_int8(DeviceState *dev, Visitor *v, void *opaque, |
122 | const char *name, Error **errp) | |
123 | { | |
124 | Property *prop = opaque; | |
125 | int8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
126 | int64_t value; | |
127 | ||
128 | value = *ptr; | |
129 | visit_type_int(v, &value, name, errp); | |
130 | } | |
131 | ||
132 | static void set_int8(DeviceState *dev, Visitor *v, void *opaque, | |
133 | const char *name, Error **errp) | |
134 | { | |
135 | Property *prop = opaque; | |
136 | int8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
137 | Error *local_err = NULL; | |
138 | int64_t value; | |
139 | ||
140 | if (dev->state != DEV_STATE_CREATED) { | |
141 | error_set(errp, QERR_PERMISSION_DENIED); | |
142 | return; | |
143 | } | |
144 | ||
145 | visit_type_int(v, &value, name, &local_err); | |
146 | if (local_err) { | |
147 | error_propagate(errp, local_err); | |
148 | return; | |
149 | } | |
150 | if (value > prop->info->min && value <= prop->info->max) { | |
151 | *ptr = value; | |
152 | } else { | |
153 | error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, | |
154 | dev->id?:"", name, value, prop->info->min, | |
155 | prop->info->max); | |
156 | } | |
157 | } | |
158 | ||
c7cc172d JQ |
159 | PropertyInfo qdev_prop_uint8 = { |
160 | .name = "uint8", | |
161 | .type = PROP_TYPE_UINT8, | |
162 | .size = sizeof(uint8_t), | |
163 | .parse = parse_uint8, | |
164 | .print = print_uint8, | |
80e555c2 PB |
165 | .get = get_int8, |
166 | .set = set_int8, | |
167 | .min = 0, | |
168 | .max = 255, | |
c7cc172d JQ |
169 | }; |
170 | ||
6835678c JK |
171 | /* --- 8bit hex value --- */ |
172 | ||
173 | static int parse_hex8(DeviceState *dev, Property *prop, const char *str) | |
174 | { | |
175 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
176 | char *end; | |
177 | ||
178 | *ptr = strtoul(str, &end, 16); | |
179 | if ((*end != '\0') || (end == str)) { | |
180 | return -EINVAL; | |
181 | } | |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
186 | static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) | |
187 | { | |
188 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
189 | return snprintf(dest, len, "0x%" PRIx8, *ptr); | |
190 | } | |
191 | ||
192 | PropertyInfo qdev_prop_hex8 = { | |
cafe5bdb PB |
193 | .name = "uint8", |
194 | .legacy_name = "hex8", | |
6835678c JK |
195 | .type = PROP_TYPE_UINT8, |
196 | .size = sizeof(uint8_t), | |
197 | .parse = parse_hex8, | |
198 | .print = print_hex8, | |
80e555c2 PB |
199 | .get = get_int8, |
200 | .set = set_int8, | |
201 | .min = 0, | |
202 | .max = 255, | |
6835678c JK |
203 | }; |
204 | ||
ee6847d1 GH |
205 | /* --- 16bit integer --- */ |
206 | ||
207 | static int parse_uint16(DeviceState *dev, Property *prop, const char *str) | |
208 | { | |
209 | uint16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 210 | char *end; |
ee6847d1 GH |
211 | |
212 | /* accept both hex and decimal */ | |
449041d4 KW |
213 | *ptr = strtoul(str, &end, 0); |
214 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 215 | return -EINVAL; |
449041d4 KW |
216 | } |
217 | ||
ee6847d1 GH |
218 | return 0; |
219 | } | |
220 | ||
221 | static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) | |
222 | { | |
223 | uint16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
224 | return snprintf(dest, len, "%" PRIu16, *ptr); | |
225 | } | |
226 | ||
80e555c2 PB |
227 | static void get_int16(DeviceState *dev, Visitor *v, void *opaque, |
228 | const char *name, Error **errp) | |
229 | { | |
230 | Property *prop = opaque; | |
231 | int16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
232 | int64_t value; | |
233 | ||
234 | value = *ptr; | |
235 | visit_type_int(v, &value, name, errp); | |
236 | } | |
237 | ||
238 | static void set_int16(DeviceState *dev, Visitor *v, void *opaque, | |
239 | const char *name, Error **errp) | |
240 | { | |
241 | Property *prop = opaque; | |
242 | int16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
243 | Error *local_err = NULL; | |
244 | int64_t value; | |
245 | ||
246 | if (dev->state != DEV_STATE_CREATED) { | |
247 | error_set(errp, QERR_PERMISSION_DENIED); | |
248 | return; | |
249 | } | |
250 | ||
251 | visit_type_int(v, &value, name, &local_err); | |
252 | if (local_err) { | |
253 | error_propagate(errp, local_err); | |
254 | return; | |
255 | } | |
256 | if (value > prop->info->min && value <= prop->info->max) { | |
257 | *ptr = value; | |
258 | } else { | |
259 | error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, | |
260 | dev->id?:"", name, value, prop->info->min, | |
261 | prop->info->max); | |
262 | } | |
263 | } | |
264 | ||
ee6847d1 GH |
265 | PropertyInfo qdev_prop_uint16 = { |
266 | .name = "uint16", | |
267 | .type = PROP_TYPE_UINT16, | |
268 | .size = sizeof(uint16_t), | |
269 | .parse = parse_uint16, | |
270 | .print = print_uint16, | |
80e555c2 PB |
271 | .get = get_int16, |
272 | .set = set_int16, | |
273 | .min = 0, | |
274 | .max = 65535, | |
ee6847d1 GH |
275 | }; |
276 | ||
277 | /* --- 32bit integer --- */ | |
278 | ||
279 | static int parse_uint32(DeviceState *dev, Property *prop, const char *str) | |
280 | { | |
281 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 282 | char *end; |
ee6847d1 GH |
283 | |
284 | /* accept both hex and decimal */ | |
449041d4 KW |
285 | *ptr = strtoul(str, &end, 0); |
286 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 287 | return -EINVAL; |
449041d4 KW |
288 | } |
289 | ||
ee6847d1 GH |
290 | return 0; |
291 | } | |
292 | ||
293 | static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
294 | { | |
295 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
296 | return snprintf(dest, len, "%" PRIu32, *ptr); | |
297 | } | |
298 | ||
80e555c2 PB |
299 | static void get_int32(DeviceState *dev, Visitor *v, void *opaque, |
300 | const char *name, Error **errp) | |
301 | { | |
302 | Property *prop = opaque; | |
303 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
304 | int64_t value; | |
305 | ||
306 | value = *ptr; | |
307 | visit_type_int(v, &value, name, errp); | |
308 | } | |
309 | ||
310 | static void set_int32(DeviceState *dev, Visitor *v, void *opaque, | |
311 | const char *name, Error **errp) | |
312 | { | |
313 | Property *prop = opaque; | |
314 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
315 | Error *local_err = NULL; | |
316 | int64_t value; | |
317 | ||
318 | if (dev->state != DEV_STATE_CREATED) { | |
319 | error_set(errp, QERR_PERMISSION_DENIED); | |
320 | return; | |
321 | } | |
322 | ||
323 | visit_type_int(v, &value, name, &local_err); | |
324 | if (local_err) { | |
325 | error_propagate(errp, local_err); | |
326 | return; | |
327 | } | |
328 | if (value > prop->info->min && value <= prop->info->max) { | |
329 | *ptr = value; | |
330 | } else { | |
331 | error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, | |
332 | dev->id?:"", name, value, prop->info->min, | |
333 | prop->info->max); | |
334 | } | |
335 | } | |
336 | ||
ee6847d1 GH |
337 | PropertyInfo qdev_prop_uint32 = { |
338 | .name = "uint32", | |
339 | .type = PROP_TYPE_UINT32, | |
340 | .size = sizeof(uint32_t), | |
341 | .parse = parse_uint32, | |
342 | .print = print_uint32, | |
80e555c2 PB |
343 | .get = get_int32, |
344 | .set = set_int32, | |
345 | .min = 0, | |
346 | .max = 0xFFFFFFFFULL, | |
ee6847d1 GH |
347 | }; |
348 | ||
316940b0 GH |
349 | static int parse_int32(DeviceState *dev, Property *prop, const char *str) |
350 | { | |
351 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 352 | char *end; |
316940b0 | 353 | |
449041d4 KW |
354 | *ptr = strtol(str, &end, 10); |
355 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 356 | return -EINVAL; |
449041d4 KW |
357 | } |
358 | ||
316940b0 GH |
359 | return 0; |
360 | } | |
361 | ||
362 | static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
363 | { | |
364 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
365 | return snprintf(dest, len, "%" PRId32, *ptr); | |
366 | } | |
367 | ||
368 | PropertyInfo qdev_prop_int32 = { | |
369 | .name = "int32", | |
370 | .type = PROP_TYPE_INT32, | |
371 | .size = sizeof(int32_t), | |
372 | .parse = parse_int32, | |
373 | .print = print_int32, | |
80e555c2 PB |
374 | .get = get_int32, |
375 | .set = set_int32, | |
376 | .min = -0x80000000LL, | |
377 | .max = 0x7FFFFFFFLL, | |
316940b0 GH |
378 | }; |
379 | ||
ee6847d1 GH |
380 | /* --- 32bit hex value --- */ |
381 | ||
382 | static int parse_hex32(DeviceState *dev, Property *prop, const char *str) | |
383 | { | |
384 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 385 | char *end; |
ee6847d1 | 386 | |
449041d4 KW |
387 | *ptr = strtoul(str, &end, 16); |
388 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 389 | return -EINVAL; |
449041d4 KW |
390 | } |
391 | ||
ee6847d1 GH |
392 | return 0; |
393 | } | |
394 | ||
395 | static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
396 | { | |
397 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
398 | return snprintf(dest, len, "0x%" PRIx32, *ptr); | |
399 | } | |
400 | ||
401 | PropertyInfo qdev_prop_hex32 = { | |
cafe5bdb PB |
402 | .name = "uint32", |
403 | .legacy_name = "hex32", | |
ee6847d1 GH |
404 | .type = PROP_TYPE_UINT32, |
405 | .size = sizeof(uint32_t), | |
406 | .parse = parse_hex32, | |
407 | .print = print_hex32, | |
80e555c2 PB |
408 | .get = get_int32, |
409 | .set = set_int32, | |
410 | .min = 0, | |
411 | .max = 0xFFFFFFFFULL, | |
ee6847d1 GH |
412 | }; |
413 | ||
5a053d1f BS |
414 | /* --- 64bit integer --- */ |
415 | ||
416 | static int parse_uint64(DeviceState *dev, Property *prop, const char *str) | |
417 | { | |
418 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 419 | char *end; |
5a053d1f BS |
420 | |
421 | /* accept both hex and decimal */ | |
449041d4 KW |
422 | *ptr = strtoull(str, &end, 0); |
423 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 424 | return -EINVAL; |
449041d4 KW |
425 | } |
426 | ||
5a053d1f BS |
427 | return 0; |
428 | } | |
429 | ||
430 | static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) | |
431 | { | |
432 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
433 | return snprintf(dest, len, "%" PRIu64, *ptr); | |
434 | } | |
435 | ||
80e555c2 PB |
436 | static void get_int64(DeviceState *dev, Visitor *v, void *opaque, |
437 | const char *name, Error **errp) | |
438 | { | |
439 | Property *prop = opaque; | |
440 | int64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
441 | ||
442 | visit_type_int(v, ptr, name, errp); | |
443 | } | |
444 | ||
445 | static void set_int64(DeviceState *dev, Visitor *v, void *opaque, | |
446 | const char *name, Error **errp) | |
447 | { | |
448 | Property *prop = opaque; | |
449 | int64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
450 | ||
451 | if (dev->state != DEV_STATE_CREATED) { | |
452 | error_set(errp, QERR_PERMISSION_DENIED); | |
453 | return; | |
454 | } | |
455 | ||
456 | visit_type_int(v, ptr, name, errp); | |
457 | } | |
458 | ||
5a053d1f BS |
459 | PropertyInfo qdev_prop_uint64 = { |
460 | .name = "uint64", | |
461 | .type = PROP_TYPE_UINT64, | |
462 | .size = sizeof(uint64_t), | |
463 | .parse = parse_uint64, | |
464 | .print = print_uint64, | |
80e555c2 PB |
465 | .get = get_int64, |
466 | .set = set_int64, | |
5a053d1f BS |
467 | }; |
468 | ||
469 | /* --- 64bit hex value --- */ | |
470 | ||
471 | static int parse_hex64(DeviceState *dev, Property *prop, const char *str) | |
472 | { | |
473 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
449041d4 | 474 | char *end; |
5a053d1f | 475 | |
449041d4 KW |
476 | *ptr = strtoull(str, &end, 16); |
477 | if ((*end != '\0') || (end == str)) { | |
6bf38816 | 478 | return -EINVAL; |
449041d4 KW |
479 | } |
480 | ||
5a053d1f BS |
481 | return 0; |
482 | } | |
483 | ||
484 | static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) | |
485 | { | |
486 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
487 | return snprintf(dest, len, "0x%" PRIx64, *ptr); | |
488 | } | |
489 | ||
490 | PropertyInfo qdev_prop_hex64 = { | |
cafe5bdb PB |
491 | .name = "uint64", |
492 | .legacy_name = "hex64", | |
5a053d1f BS |
493 | .type = PROP_TYPE_UINT64, |
494 | .size = sizeof(uint64_t), | |
495 | .parse = parse_hex64, | |
496 | .print = print_hex64, | |
80e555c2 PB |
497 | .get = get_int64, |
498 | .set = set_int64, | |
5a053d1f BS |
499 | }; |
500 | ||
59419663 GH |
501 | /* --- string --- */ |
502 | ||
503 | static int parse_string(DeviceState *dev, Property *prop, const char *str) | |
504 | { | |
505 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
506 | ||
507 | if (*ptr) | |
7267c094 AL |
508 | g_free(*ptr); |
509 | *ptr = g_strdup(str); | |
59419663 GH |
510 | return 0; |
511 | } | |
512 | ||
d21357df MA |
513 | static void free_string(DeviceState *dev, Property *prop) |
514 | { | |
7267c094 | 515 | g_free(*(char **)qdev_get_prop_ptr(dev, prop)); |
d21357df MA |
516 | } |
517 | ||
59419663 GH |
518 | static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) |
519 | { | |
520 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
521 | if (!*ptr) | |
522 | return snprintf(dest, len, "<null>"); | |
523 | return snprintf(dest, len, "\"%s\"", *ptr); | |
524 | } | |
525 | ||
80e555c2 PB |
526 | static void get_string(DeviceState *dev, Visitor *v, void *opaque, |
527 | const char *name, Error **errp) | |
528 | { | |
529 | Property *prop = opaque; | |
530 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
531 | ||
532 | if (!*ptr) { | |
533 | char *str = (char *)""; | |
534 | visit_type_str(v, &str, name, errp); | |
535 | } else { | |
536 | visit_type_str(v, ptr, name, errp); | |
537 | } | |
538 | } | |
539 | ||
540 | static void set_string(DeviceState *dev, Visitor *v, void *opaque, | |
541 | const char *name, Error **errp) | |
542 | { | |
543 | Property *prop = opaque; | |
544 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
545 | Error *local_err = NULL; | |
546 | char *str; | |
547 | ||
548 | if (dev->state != DEV_STATE_CREATED) { | |
549 | error_set(errp, QERR_PERMISSION_DENIED); | |
550 | return; | |
551 | } | |
552 | ||
553 | visit_type_str(v, &str, name, &local_err); | |
554 | if (local_err) { | |
555 | error_propagate(errp, local_err); | |
556 | return; | |
557 | } | |
558 | if (!*str) { | |
559 | g_free(str); | |
560 | str = NULL; | |
561 | } | |
562 | if (*ptr) { | |
563 | g_free(*ptr); | |
564 | } | |
565 | *ptr = str; | |
566 | } | |
567 | ||
59419663 GH |
568 | PropertyInfo qdev_prop_string = { |
569 | .name = "string", | |
570 | .type = PROP_TYPE_STRING, | |
571 | .size = sizeof(char*), | |
572 | .parse = parse_string, | |
573 | .print = print_string, | |
d21357df | 574 | .free = free_string, |
80e555c2 PB |
575 | .get = get_string, |
576 | .set = set_string, | |
59419663 GH |
577 | }; |
578 | ||
14b41872 GH |
579 | /* --- drive --- */ |
580 | ||
581 | static int parse_drive(DeviceState *dev, Property *prop, const char *str) | |
582 | { | |
f8b6cc00 MA |
583 | BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); |
584 | BlockDriverState *bs; | |
14b41872 | 585 | |
f8b6cc00 MA |
586 | bs = bdrv_find(str); |
587 | if (bs == NULL) | |
6bf38816 | 588 | return -ENOENT; |
fa879d62 | 589 | if (bdrv_attach_dev(bs, dev) < 0) |
18846dee | 590 | return -EEXIST; |
f8b6cc00 | 591 | *ptr = bs; |
14b41872 GH |
592 | return 0; |
593 | } | |
594 | ||
14bafc54 MA |
595 | static void free_drive(DeviceState *dev, Property *prop) |
596 | { | |
f8b6cc00 | 597 | BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); |
14bafc54 MA |
598 | |
599 | if (*ptr) { | |
fa879d62 | 600 | bdrv_detach_dev(*ptr, dev); |
f8b6cc00 | 601 | blockdev_auto_del(*ptr); |
14bafc54 MA |
602 | } |
603 | } | |
604 | ||
14b41872 GH |
605 | static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) |
606 | { | |
f8b6cc00 MA |
607 | BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); |
608 | return snprintf(dest, len, "%s", | |
609 | *ptr ? bdrv_get_device_name(*ptr) : "<null>"); | |
14b41872 GH |
610 | } |
611 | ||
80e555c2 PB |
612 | static void get_generic(DeviceState *dev, Visitor *v, void *opaque, |
613 | const char *name, Error **errp) | |
614 | { | |
615 | Property *prop = opaque; | |
616 | void **ptr = qdev_get_prop_ptr(dev, prop); | |
617 | char buffer[1024]; | |
618 | char *p = buffer; | |
619 | ||
620 | buffer[0] = 0; | |
621 | if (*ptr) { | |
622 | prop->info->print(dev, prop, buffer, sizeof(buffer)); | |
623 | } | |
624 | visit_type_str(v, &p, name, errp); | |
625 | } | |
626 | ||
627 | static void set_generic(DeviceState *dev, Visitor *v, void *opaque, | |
628 | const char *name, Error **errp) | |
629 | { | |
630 | Property *prop = opaque; | |
631 | Error *local_err = NULL; | |
632 | char *str; | |
633 | int ret; | |
634 | ||
635 | if (dev->state != DEV_STATE_CREATED) { | |
636 | error_set(errp, QERR_PERMISSION_DENIED); | |
637 | return; | |
638 | } | |
639 | ||
640 | visit_type_str(v, &str, name, &local_err); | |
641 | if (local_err) { | |
642 | error_propagate(errp, local_err); | |
643 | return; | |
644 | } | |
645 | if (!*str) { | |
646 | g_free(str); | |
647 | error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); | |
648 | return; | |
649 | } | |
650 | ret = prop->info->parse(dev, prop, str); | |
651 | error_set_from_qdev_prop_error(errp, ret, dev, prop, str); | |
652 | g_free(str); | |
653 | } | |
654 | ||
14b41872 GH |
655 | PropertyInfo qdev_prop_drive = { |
656 | .name = "drive", | |
657 | .type = PROP_TYPE_DRIVE, | |
f8b6cc00 | 658 | .size = sizeof(BlockDriverState *), |
14b41872 GH |
659 | .parse = parse_drive, |
660 | .print = print_drive, | |
80e555c2 PB |
661 | .get = get_generic, |
662 | .set = set_generic, | |
14bafc54 | 663 | .free = free_drive, |
14b41872 GH |
664 | }; |
665 | ||
313feaab GH |
666 | /* --- character device --- */ |
667 | ||
06113719 GH |
668 | static int parse_chr(DeviceState *dev, Property *prop, const char *str) |
669 | { | |
670 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
671 | ||
672 | *ptr = qemu_chr_find(str); | |
2d6c1ef4 | 673 | if (*ptr == NULL) { |
6bf38816 | 674 | return -ENOENT; |
2d6c1ef4 | 675 | } |
d5b27167 | 676 | if ((*ptr)->avail_connections < 1) { |
2d6c1ef4 AS |
677 | return -EEXIST; |
678 | } | |
d5b27167 | 679 | --(*ptr)->avail_connections; |
06113719 GH |
680 | return 0; |
681 | } | |
682 | ||
313feaab GH |
683 | static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) |
684 | { | |
685 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
bc19fcaa BS |
686 | |
687 | if (*ptr && (*ptr)->label) { | |
688 | return snprintf(dest, len, "%s", (*ptr)->label); | |
689 | } else { | |
690 | return snprintf(dest, len, "<null>"); | |
691 | } | |
313feaab GH |
692 | } |
693 | ||
694 | PropertyInfo qdev_prop_chr = { | |
695 | .name = "chr", | |
696 | .type = PROP_TYPE_CHR, | |
697 | .size = sizeof(CharDriverState*), | |
06113719 | 698 | .parse = parse_chr, |
313feaab | 699 | .print = print_chr, |
80e555c2 PB |
700 | .get = get_generic, |
701 | .set = set_generic, | |
313feaab GH |
702 | }; |
703 | ||
2ef924b4 GH |
704 | /* --- netdev device --- */ |
705 | ||
706 | static int parse_netdev(DeviceState *dev, Property *prop, const char *str) | |
707 | { | |
708 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
709 | ||
710 | *ptr = qemu_find_netdev(str); | |
711 | if (*ptr == NULL) | |
6bf38816 | 712 | return -ENOENT; |
27f3f8a3 MA |
713 | if ((*ptr)->peer) { |
714 | return -EEXIST; | |
715 | } | |
2ef924b4 GH |
716 | return 0; |
717 | } | |
718 | ||
719 | static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len) | |
720 | { | |
721 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
722 | ||
723 | if (*ptr && (*ptr)->name) { | |
724 | return snprintf(dest, len, "%s", (*ptr)->name); | |
725 | } else { | |
726 | return snprintf(dest, len, "<null>"); | |
727 | } | |
728 | } | |
729 | ||
730 | PropertyInfo qdev_prop_netdev = { | |
731 | .name = "netdev", | |
732 | .type = PROP_TYPE_NETDEV, | |
733 | .size = sizeof(VLANClientState*), | |
734 | .parse = parse_netdev, | |
735 | .print = print_netdev, | |
80e555c2 PB |
736 | .get = get_generic, |
737 | .set = set_generic, | |
2ef924b4 GH |
738 | }; |
739 | ||
851bec09 GH |
740 | /* --- vlan --- */ |
741 | ||
742 | static int parse_vlan(DeviceState *dev, Property *prop, const char *str) | |
743 | { | |
744 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
745 | int id; | |
746 | ||
747 | if (sscanf(str, "%d", &id) != 1) | |
6bf38816 | 748 | return -EINVAL; |
851bec09 GH |
749 | *ptr = qemu_find_vlan(id, 1); |
750 | if (*ptr == NULL) | |
6bf38816 | 751 | return -ENOENT; |
851bec09 GH |
752 | return 0; |
753 | } | |
754 | ||
755 | static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) | |
756 | { | |
757 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
758 | ||
759 | if (*ptr) { | |
760 | return snprintf(dest, len, "%d", (*ptr)->id); | |
761 | } else { | |
762 | return snprintf(dest, len, "<null>"); | |
763 | } | |
764 | } | |
765 | ||
80e555c2 PB |
766 | static void get_vlan(DeviceState *dev, Visitor *v, void *opaque, |
767 | const char *name, Error **errp) | |
768 | { | |
769 | Property *prop = opaque; | |
770 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
771 | int64_t id; | |
772 | ||
773 | id = *ptr ? (*ptr)->id : -1; | |
774 | visit_type_int(v, &id, name, errp); | |
775 | } | |
776 | ||
777 | static void set_vlan(DeviceState *dev, Visitor *v, void *opaque, | |
778 | const char *name, Error **errp) | |
779 | { | |
780 | Property *prop = opaque; | |
781 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
782 | Error *local_err = NULL; | |
783 | int64_t id; | |
784 | VLANState *vlan; | |
785 | ||
786 | if (dev->state != DEV_STATE_CREATED) { | |
787 | error_set(errp, QERR_PERMISSION_DENIED); | |
788 | return; | |
789 | } | |
790 | ||
791 | visit_type_int(v, &id, name, &local_err); | |
792 | if (local_err) { | |
793 | error_propagate(errp, local_err); | |
794 | return; | |
795 | } | |
796 | if (id == -1) { | |
797 | *ptr = NULL; | |
798 | return; | |
799 | } | |
800 | vlan = qemu_find_vlan(id, 1); | |
801 | if (!vlan) { | |
802 | error_set(errp, QERR_INVALID_PARAMETER_VALUE, | |
803 | name, prop->info->name); | |
804 | return; | |
805 | } | |
806 | *ptr = vlan; | |
807 | } | |
808 | ||
851bec09 GH |
809 | PropertyInfo qdev_prop_vlan = { |
810 | .name = "vlan", | |
811 | .type = PROP_TYPE_VLAN, | |
812 | .size = sizeof(VLANClientState*), | |
813 | .parse = parse_vlan, | |
814 | .print = print_vlan, | |
80e555c2 PB |
815 | .get = get_vlan, |
816 | .set = set_vlan, | |
851bec09 GH |
817 | }; |
818 | ||
ee6847d1 GH |
819 | /* --- pointer --- */ |
820 | ||
036f7166 | 821 | /* Not a proper property, just for dirty hacks. TODO Remove it! */ |
ee6847d1 GH |
822 | PropertyInfo qdev_prop_ptr = { |
823 | .name = "ptr", | |
824 | .type = PROP_TYPE_PTR, | |
825 | .size = sizeof(void*), | |
ee6847d1 GH |
826 | }; |
827 | ||
828 | /* --- mac address --- */ | |
829 | ||
830 | /* | |
831 | * accepted syntax versions: | |
832 | * 01:02:03:04:05:06 | |
833 | * 01-02-03-04-05-06 | |
834 | */ | |
835 | static int parse_mac(DeviceState *dev, Property *prop, const char *str) | |
836 | { | |
1503fff3 | 837 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
ee6847d1 GH |
838 | int i, pos; |
839 | char *p; | |
840 | ||
841 | for (i = 0, pos = 0; i < 6; i++, pos += 3) { | |
88e150a5 | 842 | if (!qemu_isxdigit(str[pos])) |
6bf38816 | 843 | return -EINVAL; |
88e150a5 | 844 | if (!qemu_isxdigit(str[pos+1])) |
6bf38816 | 845 | return -EINVAL; |
1503fff3 GH |
846 | if (i == 5) { |
847 | if (str[pos+2] != '\0') | |
6bf38816 | 848 | return -EINVAL; |
1503fff3 GH |
849 | } else { |
850 | if (str[pos+2] != ':' && str[pos+2] != '-') | |
6bf38816 | 851 | return -EINVAL; |
1503fff3 GH |
852 | } |
853 | mac->a[i] = strtol(str+pos, &p, 16); | |
ee6847d1 GH |
854 | } |
855 | return 0; | |
856 | } | |
857 | ||
858 | static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) | |
859 | { | |
1503fff3 GH |
860 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
861 | ||
ee6847d1 | 862 | return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", |
1503fff3 GH |
863 | mac->a[0], mac->a[1], mac->a[2], |
864 | mac->a[3], mac->a[4], mac->a[5]); | |
ee6847d1 GH |
865 | } |
866 | ||
867 | PropertyInfo qdev_prop_macaddr = { | |
1503fff3 | 868 | .name = "macaddr", |
ee6847d1 | 869 | .type = PROP_TYPE_MACADDR, |
1503fff3 | 870 | .size = sizeof(MACAddr), |
ee6847d1 GH |
871 | .parse = parse_mac, |
872 | .print = print_mac, | |
80e555c2 PB |
873 | .get = get_generic, |
874 | .set = set_generic, | |
ee6847d1 GH |
875 | }; |
876 | ||
05cb5fe4 GH |
877 | /* --- pci address --- */ |
878 | ||
879 | /* | |
880 | * bus-local address, i.e. "$slot" or "$slot.$fn" | |
881 | */ | |
882 | static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) | |
883 | { | |
884 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
885 | unsigned int slot, fn, n; | |
886 | ||
887 | if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { | |
888 | fn = 0; | |
889 | if (sscanf(str, "%x%n", &slot, &n) != 1) { | |
6bf38816 | 890 | return -EINVAL; |
05cb5fe4 GH |
891 | } |
892 | } | |
893 | if (str[n] != '\0') | |
6bf38816 | 894 | return -EINVAL; |
05cb5fe4 | 895 | if (fn > 7) |
6bf38816 | 896 | return -EINVAL; |
ffe3ce11 DD |
897 | if (slot > 31) |
898 | return -EINVAL; | |
05cb5fe4 GH |
899 | *ptr = slot << 3 | fn; |
900 | return 0; | |
901 | } | |
902 | ||
903 | static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) | |
904 | { | |
905 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
906 | ||
73538c31 | 907 | if (*ptr == -1) { |
05cb5fe4 GH |
908 | return snprintf(dest, len, "<unset>"); |
909 | } else { | |
910 | return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); | |
911 | } | |
912 | } | |
913 | ||
80e555c2 PB |
914 | static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque, |
915 | const char *name, Error **errp) | |
916 | { | |
917 | Property *prop = opaque; | |
918 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
919 | char buffer[32]; | |
920 | char *p = buffer; | |
921 | ||
922 | buffer[0] = 0; | |
923 | if (*ptr != -1) { | |
924 | snprintf(buffer, sizeof(buffer), "%02x.%x", *ptr >> 3, *ptr & 7); | |
925 | } | |
926 | visit_type_str(v, &p, name, errp); | |
927 | } | |
928 | ||
05cb5fe4 GH |
929 | PropertyInfo qdev_prop_pci_devfn = { |
930 | .name = "pci-devfn", | |
931 | .type = PROP_TYPE_UINT32, | |
932 | .size = sizeof(uint32_t), | |
933 | .parse = parse_pci_devfn, | |
934 | .print = print_pci_devfn, | |
80e555c2 PB |
935 | .get = get_pci_devfn, |
936 | .set = set_generic, | |
05cb5fe4 GH |
937 | }; |
938 | ||
ee6847d1 GH |
939 | /* --- public helpers --- */ |
940 | ||
941 | static Property *qdev_prop_walk(Property *props, const char *name) | |
942 | { | |
943 | if (!props) | |
944 | return NULL; | |
945 | while (props->name) { | |
946 | if (strcmp(props->name, name) == 0) | |
947 | return props; | |
948 | props++; | |
949 | } | |
950 | return NULL; | |
951 | } | |
952 | ||
953 | static Property *qdev_prop_find(DeviceState *dev, const char *name) | |
954 | { | |
955 | Property *prop; | |
956 | ||
957 | /* device properties */ | |
958 | prop = qdev_prop_walk(dev->info->props, name); | |
959 | if (prop) | |
960 | return prop; | |
961 | ||
962 | /* bus properties */ | |
963 | prop = qdev_prop_walk(dev->parent_bus->info->props, name); | |
964 | if (prop) | |
965 | return prop; | |
966 | ||
967 | return NULL; | |
968 | } | |
969 | ||
d8ed79ae GH |
970 | int qdev_prop_exists(DeviceState *dev, const char *name) |
971 | { | |
972 | return qdev_prop_find(dev, name) ? true : false; | |
973 | } | |
974 | ||
7db4c4e8 PB |
975 | void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, |
976 | Property *prop, const char *value) | |
977 | { | |
978 | switch (ret) { | |
979 | case -EEXIST: | |
980 | error_set(errp, QERR_PROPERTY_VALUE_IN_USE, | |
981 | dev->info->name, prop->name, value); | |
982 | break; | |
983 | default: | |
984 | case -EINVAL: | |
985 | error_set(errp, QERR_PROPERTY_VALUE_BAD, | |
986 | dev->info->name, prop->name, value); | |
987 | break; | |
988 | case -ENOENT: | |
989 | error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, | |
990 | dev->info->name, prop->name, value); | |
991 | break; | |
992 | case 0: | |
993 | break; | |
994 | } | |
995 | } | |
996 | ||
ee6847d1 GH |
997 | int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) |
998 | { | |
999 | Property *prop; | |
6bf38816 | 1000 | int ret; |
ee6847d1 GH |
1001 | |
1002 | prop = qdev_prop_find(dev, name); | |
036f7166 MA |
1003 | /* |
1004 | * TODO Properties without a parse method are just for dirty | |
1005 | * hacks. qdev_prop_ptr is the only such PropertyInfo. It's | |
1006 | * marked for removal. The test !prop->info->parse should be | |
1007 | * removed along with it. | |
1008 | */ | |
1009 | if (!prop || !prop->info->parse) { | |
fdcfa190 | 1010 | qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); |
ee6847d1 GH |
1011 | return -1; |
1012 | } | |
6bf38816 MA |
1013 | ret = prop->info->parse(dev, prop, value); |
1014 | if (ret < 0) { | |
7db4c4e8 PB |
1015 | Error *err; |
1016 | error_set_from_qdev_prop_error(&err, ret, dev, prop, value); | |
1017 | qerror_report_err(err); | |
1018 | error_free(err); | |
9ef5c4bf GH |
1019 | return -1; |
1020 | } | |
1021 | return 0; | |
ee6847d1 GH |
1022 | } |
1023 | ||
1024 | void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) | |
1025 | { | |
1026 | Property *prop; | |
ee6847d1 GH |
1027 | |
1028 | prop = qdev_prop_find(dev, name); | |
1029 | if (!prop) { | |
1030 | fprintf(stderr, "%s: property \"%s.%s\" not found\n", | |
1031 | __FUNCTION__, dev->info->name, name); | |
1032 | abort(); | |
1033 | } | |
1034 | if (prop->info->type != type) { | |
1035 | fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", | |
1036 | __FUNCTION__, dev->info->name, name); | |
1037 | abort(); | |
1038 | } | |
d2364ee4 | 1039 | qdev_prop_cpy(dev, prop, src); |
ee6847d1 GH |
1040 | } |
1041 | ||
f4594a3b IY |
1042 | void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) |
1043 | { | |
1044 | qdev_prop_set(dev, name, &value, PROP_TYPE_BIT); | |
1045 | } | |
1046 | ||
c7cc172d JQ |
1047 | void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) |
1048 | { | |
1049 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8); | |
1050 | } | |
1051 | ||
ee6847d1 GH |
1052 | void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
1053 | { | |
1054 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); | |
1055 | } | |
1056 | ||
1057 | void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) | |
1058 | { | |
1059 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); | |
1060 | } | |
1061 | ||
316940b0 GH |
1062 | void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
1063 | { | |
1064 | qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); | |
1065 | } | |
1066 | ||
5a053d1f BS |
1067 | void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
1068 | { | |
1069 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); | |
1070 | } | |
1071 | ||
cc984673 MA |
1072 | void qdev_prop_set_string(DeviceState *dev, const char *name, char *value) |
1073 | { | |
1074 | qdev_prop_set(dev, name, &value, PROP_TYPE_STRING); | |
1075 | } | |
1076 | ||
18846dee | 1077 | int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) |
14b41872 | 1078 | { |
18846dee MA |
1079 | int res; |
1080 | ||
fa879d62 | 1081 | res = bdrv_attach_dev(value, dev); |
18846dee MA |
1082 | if (res < 0) { |
1083 | error_report("Can't attach drive %s to %s.%s: %s", | |
1084 | bdrv_get_device_name(value), | |
1085 | dev->id ? dev->id : dev->info->name, | |
1086 | name, strerror(-res)); | |
1087 | return -1; | |
1088 | } | |
14b41872 | 1089 | qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); |
18846dee | 1090 | return 0; |
14b41872 GH |
1091 | } |
1092 | ||
18846dee MA |
1093 | void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value) |
1094 | { | |
1095 | if (qdev_prop_set_drive(dev, name, value) < 0) { | |
1096 | exit(1); | |
1097 | } | |
1098 | } | |
313feaab GH |
1099 | void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) |
1100 | { | |
1101 | qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); | |
1102 | } | |
1103 | ||
2ef924b4 GH |
1104 | void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value) |
1105 | { | |
1106 | qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV); | |
1107 | } | |
1108 | ||
851bec09 GH |
1109 | void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value) |
1110 | { | |
1111 | qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN); | |
1112 | } | |
1113 | ||
1503fff3 GH |
1114 | void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) |
1115 | { | |
1116 | qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); | |
1117 | } | |
1118 | ||
ee6847d1 GH |
1119 | void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) |
1120 | { | |
1121 | qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); | |
1122 | } | |
1123 | ||
1124 | void qdev_prop_set_defaults(DeviceState *dev, Property *props) | |
1125 | { | |
ee6847d1 GH |
1126 | if (!props) |
1127 | return; | |
1128 | while (props->name) { | |
1129 | if (props->defval) { | |
d2364ee4 | 1130 | qdev_prop_cpy(dev, props, props->defval); |
ee6847d1 GH |
1131 | } |
1132 | props++; | |
1133 | } | |
1134 | } | |
1135 | ||
458fb679 | 1136 | static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); |
b6b61144 | 1137 | |
25920d6a | 1138 | static void qdev_prop_register_global(GlobalProperty *prop) |
b6b61144 | 1139 | { |
458fb679 | 1140 | QTAILQ_INSERT_TAIL(&global_props, prop, next); |
b6b61144 GH |
1141 | } |
1142 | ||
458fb679 | 1143 | void qdev_prop_register_global_list(GlobalProperty *props) |
b6b61144 | 1144 | { |
458fb679 | 1145 | int i; |
b6b61144 | 1146 | |
458fb679 GH |
1147 | for (i = 0; props[i].driver != NULL; i++) { |
1148 | qdev_prop_register_global(props+i); | |
b6b61144 | 1149 | } |
458fb679 GH |
1150 | } |
1151 | ||
1152 | void qdev_prop_set_globals(DeviceState *dev) | |
1153 | { | |
1154 | GlobalProperty *prop; | |
1155 | ||
1156 | QTAILQ_FOREACH(prop, &global_props, next) { | |
07a8de35 GH |
1157 | if (strcmp(dev->info->name, prop->driver) != 0 && |
1158 | strcmp(dev->info->bus_info->name, prop->driver) != 0) { | |
b6b61144 GH |
1159 | continue; |
1160 | } | |
1161 | if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { | |
9ef5c4bf | 1162 | exit(1); |
b6b61144 GH |
1163 | } |
1164 | } | |
1165 | } | |
25920d6a KW |
1166 | |
1167 | static int qdev_add_one_global(QemuOpts *opts, void *opaque) | |
1168 | { | |
1169 | GlobalProperty *g; | |
1170 | ||
7267c094 | 1171 | g = g_malloc0(sizeof(*g)); |
25920d6a KW |
1172 | g->driver = qemu_opt_get(opts, "driver"); |
1173 | g->property = qemu_opt_get(opts, "property"); | |
1174 | g->value = qemu_opt_get(opts, "value"); | |
1175 | qdev_prop_register_global(g); | |
1176 | return 0; | |
1177 | } | |
1178 | ||
1179 | void qemu_add_globals(void) | |
1180 | { | |
3329f07b | 1181 | qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); |
25920d6a | 1182 | } |