]>
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 | ||
a87f3e8b AS |
683 | static void free_chr(DeviceState *dev, Property *prop) |
684 | { | |
685 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
686 | ||
687 | if (*ptr) { | |
688 | qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); | |
689 | } | |
690 | } | |
691 | ||
692 | ||
313feaab GH |
693 | static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) |
694 | { | |
695 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
bc19fcaa BS |
696 | |
697 | if (*ptr && (*ptr)->label) { | |
698 | return snprintf(dest, len, "%s", (*ptr)->label); | |
699 | } else { | |
700 | return snprintf(dest, len, "<null>"); | |
701 | } | |
313feaab GH |
702 | } |
703 | ||
704 | PropertyInfo qdev_prop_chr = { | |
705 | .name = "chr", | |
706 | .type = PROP_TYPE_CHR, | |
707 | .size = sizeof(CharDriverState*), | |
06113719 | 708 | .parse = parse_chr, |
313feaab | 709 | .print = print_chr, |
80e555c2 PB |
710 | .get = get_generic, |
711 | .set = set_generic, | |
a87f3e8b | 712 | .free = free_chr, |
313feaab GH |
713 | }; |
714 | ||
2ef924b4 GH |
715 | /* --- netdev device --- */ |
716 | ||
717 | static int parse_netdev(DeviceState *dev, Property *prop, const char *str) | |
718 | { | |
719 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
720 | ||
721 | *ptr = qemu_find_netdev(str); | |
722 | if (*ptr == NULL) | |
6bf38816 | 723 | return -ENOENT; |
27f3f8a3 MA |
724 | if ((*ptr)->peer) { |
725 | return -EEXIST; | |
726 | } | |
2ef924b4 GH |
727 | return 0; |
728 | } | |
729 | ||
730 | static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len) | |
731 | { | |
732 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
733 | ||
734 | if (*ptr && (*ptr)->name) { | |
735 | return snprintf(dest, len, "%s", (*ptr)->name); | |
736 | } else { | |
737 | return snprintf(dest, len, "<null>"); | |
738 | } | |
739 | } | |
740 | ||
741 | PropertyInfo qdev_prop_netdev = { | |
742 | .name = "netdev", | |
743 | .type = PROP_TYPE_NETDEV, | |
744 | .size = sizeof(VLANClientState*), | |
745 | .parse = parse_netdev, | |
746 | .print = print_netdev, | |
80e555c2 PB |
747 | .get = get_generic, |
748 | .set = set_generic, | |
2ef924b4 GH |
749 | }; |
750 | ||
851bec09 GH |
751 | /* --- vlan --- */ |
752 | ||
753 | static int parse_vlan(DeviceState *dev, Property *prop, const char *str) | |
754 | { | |
755 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
756 | int id; | |
757 | ||
758 | if (sscanf(str, "%d", &id) != 1) | |
6bf38816 | 759 | return -EINVAL; |
851bec09 GH |
760 | *ptr = qemu_find_vlan(id, 1); |
761 | if (*ptr == NULL) | |
6bf38816 | 762 | return -ENOENT; |
851bec09 GH |
763 | return 0; |
764 | } | |
765 | ||
766 | static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) | |
767 | { | |
768 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
769 | ||
770 | if (*ptr) { | |
771 | return snprintf(dest, len, "%d", (*ptr)->id); | |
772 | } else { | |
773 | return snprintf(dest, len, "<null>"); | |
774 | } | |
775 | } | |
776 | ||
80e555c2 PB |
777 | static void get_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 | int64_t id; | |
783 | ||
784 | id = *ptr ? (*ptr)->id : -1; | |
785 | visit_type_int(v, &id, name, errp); | |
786 | } | |
787 | ||
788 | static void set_vlan(DeviceState *dev, Visitor *v, void *opaque, | |
789 | const char *name, Error **errp) | |
790 | { | |
791 | Property *prop = opaque; | |
792 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
793 | Error *local_err = NULL; | |
794 | int64_t id; | |
795 | VLANState *vlan; | |
796 | ||
797 | if (dev->state != DEV_STATE_CREATED) { | |
798 | error_set(errp, QERR_PERMISSION_DENIED); | |
799 | return; | |
800 | } | |
801 | ||
802 | visit_type_int(v, &id, name, &local_err); | |
803 | if (local_err) { | |
804 | error_propagate(errp, local_err); | |
805 | return; | |
806 | } | |
807 | if (id == -1) { | |
808 | *ptr = NULL; | |
809 | return; | |
810 | } | |
811 | vlan = qemu_find_vlan(id, 1); | |
812 | if (!vlan) { | |
813 | error_set(errp, QERR_INVALID_PARAMETER_VALUE, | |
814 | name, prop->info->name); | |
815 | return; | |
816 | } | |
817 | *ptr = vlan; | |
818 | } | |
819 | ||
851bec09 GH |
820 | PropertyInfo qdev_prop_vlan = { |
821 | .name = "vlan", | |
822 | .type = PROP_TYPE_VLAN, | |
823 | .size = sizeof(VLANClientState*), | |
824 | .parse = parse_vlan, | |
825 | .print = print_vlan, | |
80e555c2 PB |
826 | .get = get_vlan, |
827 | .set = set_vlan, | |
851bec09 GH |
828 | }; |
829 | ||
ee6847d1 GH |
830 | /* --- pointer --- */ |
831 | ||
036f7166 | 832 | /* Not a proper property, just for dirty hacks. TODO Remove it! */ |
ee6847d1 GH |
833 | PropertyInfo qdev_prop_ptr = { |
834 | .name = "ptr", | |
835 | .type = PROP_TYPE_PTR, | |
836 | .size = sizeof(void*), | |
ee6847d1 GH |
837 | }; |
838 | ||
839 | /* --- mac address --- */ | |
840 | ||
841 | /* | |
842 | * accepted syntax versions: | |
843 | * 01:02:03:04:05:06 | |
844 | * 01-02-03-04-05-06 | |
845 | */ | |
846 | static int parse_mac(DeviceState *dev, Property *prop, const char *str) | |
847 | { | |
1503fff3 | 848 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
ee6847d1 GH |
849 | int i, pos; |
850 | char *p; | |
851 | ||
852 | for (i = 0, pos = 0; i < 6; i++, pos += 3) { | |
88e150a5 | 853 | if (!qemu_isxdigit(str[pos])) |
6bf38816 | 854 | return -EINVAL; |
88e150a5 | 855 | if (!qemu_isxdigit(str[pos+1])) |
6bf38816 | 856 | return -EINVAL; |
1503fff3 GH |
857 | if (i == 5) { |
858 | if (str[pos+2] != '\0') | |
6bf38816 | 859 | return -EINVAL; |
1503fff3 GH |
860 | } else { |
861 | if (str[pos+2] != ':' && str[pos+2] != '-') | |
6bf38816 | 862 | return -EINVAL; |
1503fff3 GH |
863 | } |
864 | mac->a[i] = strtol(str+pos, &p, 16); | |
ee6847d1 GH |
865 | } |
866 | return 0; | |
867 | } | |
868 | ||
869 | static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) | |
870 | { | |
1503fff3 GH |
871 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
872 | ||
ee6847d1 | 873 | return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", |
1503fff3 GH |
874 | mac->a[0], mac->a[1], mac->a[2], |
875 | mac->a[3], mac->a[4], mac->a[5]); | |
ee6847d1 GH |
876 | } |
877 | ||
878 | PropertyInfo qdev_prop_macaddr = { | |
1503fff3 | 879 | .name = "macaddr", |
ee6847d1 | 880 | .type = PROP_TYPE_MACADDR, |
1503fff3 | 881 | .size = sizeof(MACAddr), |
ee6847d1 GH |
882 | .parse = parse_mac, |
883 | .print = print_mac, | |
80e555c2 PB |
884 | .get = get_generic, |
885 | .set = set_generic, | |
ee6847d1 GH |
886 | }; |
887 | ||
05cb5fe4 GH |
888 | /* --- pci address --- */ |
889 | ||
890 | /* | |
891 | * bus-local address, i.e. "$slot" or "$slot.$fn" | |
892 | */ | |
893 | static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) | |
894 | { | |
895 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
896 | unsigned int slot, fn, n; | |
897 | ||
898 | if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { | |
899 | fn = 0; | |
900 | if (sscanf(str, "%x%n", &slot, &n) != 1) { | |
6bf38816 | 901 | return -EINVAL; |
05cb5fe4 GH |
902 | } |
903 | } | |
904 | if (str[n] != '\0') | |
6bf38816 | 905 | return -EINVAL; |
05cb5fe4 | 906 | if (fn > 7) |
6bf38816 | 907 | return -EINVAL; |
ffe3ce11 DD |
908 | if (slot > 31) |
909 | return -EINVAL; | |
05cb5fe4 GH |
910 | *ptr = slot << 3 | fn; |
911 | return 0; | |
912 | } | |
913 | ||
914 | static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) | |
915 | { | |
916 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
917 | ||
73538c31 | 918 | if (*ptr == -1) { |
05cb5fe4 GH |
919 | return snprintf(dest, len, "<unset>"); |
920 | } else { | |
921 | return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); | |
922 | } | |
923 | } | |
924 | ||
80e555c2 PB |
925 | static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque, |
926 | const char *name, Error **errp) | |
927 | { | |
928 | Property *prop = opaque; | |
929 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
930 | char buffer[32]; | |
931 | char *p = buffer; | |
932 | ||
933 | buffer[0] = 0; | |
934 | if (*ptr != -1) { | |
935 | snprintf(buffer, sizeof(buffer), "%02x.%x", *ptr >> 3, *ptr & 7); | |
936 | } | |
937 | visit_type_str(v, &p, name, errp); | |
938 | } | |
939 | ||
05cb5fe4 GH |
940 | PropertyInfo qdev_prop_pci_devfn = { |
941 | .name = "pci-devfn", | |
942 | .type = PROP_TYPE_UINT32, | |
943 | .size = sizeof(uint32_t), | |
944 | .parse = parse_pci_devfn, | |
945 | .print = print_pci_devfn, | |
80e555c2 PB |
946 | .get = get_pci_devfn, |
947 | .set = set_generic, | |
05cb5fe4 GH |
948 | }; |
949 | ||
ee6847d1 GH |
950 | /* --- public helpers --- */ |
951 | ||
952 | static Property *qdev_prop_walk(Property *props, const char *name) | |
953 | { | |
954 | if (!props) | |
955 | return NULL; | |
956 | while (props->name) { | |
957 | if (strcmp(props->name, name) == 0) | |
958 | return props; | |
959 | props++; | |
960 | } | |
961 | return NULL; | |
962 | } | |
963 | ||
964 | static Property *qdev_prop_find(DeviceState *dev, const char *name) | |
965 | { | |
966 | Property *prop; | |
967 | ||
968 | /* device properties */ | |
969 | prop = qdev_prop_walk(dev->info->props, name); | |
970 | if (prop) | |
971 | return prop; | |
972 | ||
973 | /* bus properties */ | |
974 | prop = qdev_prop_walk(dev->parent_bus->info->props, name); | |
975 | if (prop) | |
976 | return prop; | |
977 | ||
978 | return NULL; | |
979 | } | |
980 | ||
d8ed79ae GH |
981 | int qdev_prop_exists(DeviceState *dev, const char *name) |
982 | { | |
983 | return qdev_prop_find(dev, name) ? true : false; | |
984 | } | |
985 | ||
7db4c4e8 PB |
986 | void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, |
987 | Property *prop, const char *value) | |
988 | { | |
989 | switch (ret) { | |
990 | case -EEXIST: | |
991 | error_set(errp, QERR_PROPERTY_VALUE_IN_USE, | |
992 | dev->info->name, prop->name, value); | |
993 | break; | |
994 | default: | |
995 | case -EINVAL: | |
996 | error_set(errp, QERR_PROPERTY_VALUE_BAD, | |
997 | dev->info->name, prop->name, value); | |
998 | break; | |
999 | case -ENOENT: | |
1000 | error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, | |
1001 | dev->info->name, prop->name, value); | |
1002 | break; | |
1003 | case 0: | |
1004 | break; | |
1005 | } | |
1006 | } | |
1007 | ||
ee6847d1 GH |
1008 | int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) |
1009 | { | |
1010 | Property *prop; | |
6bf38816 | 1011 | int ret; |
ee6847d1 GH |
1012 | |
1013 | prop = qdev_prop_find(dev, name); | |
036f7166 MA |
1014 | /* |
1015 | * TODO Properties without a parse method are just for dirty | |
1016 | * hacks. qdev_prop_ptr is the only such PropertyInfo. It's | |
1017 | * marked for removal. The test !prop->info->parse should be | |
1018 | * removed along with it. | |
1019 | */ | |
1020 | if (!prop || !prop->info->parse) { | |
fdcfa190 | 1021 | qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); |
ee6847d1 GH |
1022 | return -1; |
1023 | } | |
6bf38816 MA |
1024 | ret = prop->info->parse(dev, prop, value); |
1025 | if (ret < 0) { | |
7db4c4e8 PB |
1026 | Error *err; |
1027 | error_set_from_qdev_prop_error(&err, ret, dev, prop, value); | |
1028 | qerror_report_err(err); | |
1029 | error_free(err); | |
9ef5c4bf GH |
1030 | return -1; |
1031 | } | |
1032 | return 0; | |
ee6847d1 GH |
1033 | } |
1034 | ||
1035 | void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) | |
1036 | { | |
1037 | Property *prop; | |
ee6847d1 GH |
1038 | |
1039 | prop = qdev_prop_find(dev, name); | |
1040 | if (!prop) { | |
1041 | fprintf(stderr, "%s: property \"%s.%s\" not found\n", | |
1042 | __FUNCTION__, dev->info->name, name); | |
1043 | abort(); | |
1044 | } | |
1045 | if (prop->info->type != type) { | |
1046 | fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", | |
1047 | __FUNCTION__, dev->info->name, name); | |
1048 | abort(); | |
1049 | } | |
d2364ee4 | 1050 | qdev_prop_cpy(dev, prop, src); |
ee6847d1 GH |
1051 | } |
1052 | ||
f4594a3b IY |
1053 | void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) |
1054 | { | |
1055 | qdev_prop_set(dev, name, &value, PROP_TYPE_BIT); | |
1056 | } | |
1057 | ||
c7cc172d JQ |
1058 | void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) |
1059 | { | |
1060 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8); | |
1061 | } | |
1062 | ||
ee6847d1 GH |
1063 | void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
1064 | { | |
1065 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); | |
1066 | } | |
1067 | ||
1068 | void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) | |
1069 | { | |
1070 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); | |
1071 | } | |
1072 | ||
316940b0 GH |
1073 | void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
1074 | { | |
1075 | qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); | |
1076 | } | |
1077 | ||
5a053d1f BS |
1078 | void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
1079 | { | |
1080 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); | |
1081 | } | |
1082 | ||
cc984673 MA |
1083 | void qdev_prop_set_string(DeviceState *dev, const char *name, char *value) |
1084 | { | |
1085 | qdev_prop_set(dev, name, &value, PROP_TYPE_STRING); | |
1086 | } | |
1087 | ||
18846dee | 1088 | int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) |
14b41872 | 1089 | { |
18846dee MA |
1090 | int res; |
1091 | ||
fa879d62 | 1092 | res = bdrv_attach_dev(value, dev); |
18846dee MA |
1093 | if (res < 0) { |
1094 | error_report("Can't attach drive %s to %s.%s: %s", | |
1095 | bdrv_get_device_name(value), | |
1096 | dev->id ? dev->id : dev->info->name, | |
1097 | name, strerror(-res)); | |
1098 | return -1; | |
1099 | } | |
14b41872 | 1100 | qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); |
18846dee | 1101 | return 0; |
14b41872 GH |
1102 | } |
1103 | ||
18846dee MA |
1104 | void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value) |
1105 | { | |
1106 | if (qdev_prop_set_drive(dev, name, value) < 0) { | |
1107 | exit(1); | |
1108 | } | |
1109 | } | |
313feaab GH |
1110 | void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) |
1111 | { | |
1112 | qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); | |
1113 | } | |
1114 | ||
2ef924b4 GH |
1115 | void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value) |
1116 | { | |
1117 | qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV); | |
1118 | } | |
1119 | ||
851bec09 GH |
1120 | void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value) |
1121 | { | |
1122 | qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN); | |
1123 | } | |
1124 | ||
1503fff3 GH |
1125 | void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) |
1126 | { | |
1127 | qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); | |
1128 | } | |
1129 | ||
ee6847d1 GH |
1130 | void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) |
1131 | { | |
1132 | qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); | |
1133 | } | |
1134 | ||
1135 | void qdev_prop_set_defaults(DeviceState *dev, Property *props) | |
1136 | { | |
ee6847d1 GH |
1137 | if (!props) |
1138 | return; | |
1139 | while (props->name) { | |
1140 | if (props->defval) { | |
d2364ee4 | 1141 | qdev_prop_cpy(dev, props, props->defval); |
ee6847d1 GH |
1142 | } |
1143 | props++; | |
1144 | } | |
1145 | } | |
1146 | ||
458fb679 | 1147 | static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); |
b6b61144 | 1148 | |
25920d6a | 1149 | static void qdev_prop_register_global(GlobalProperty *prop) |
b6b61144 | 1150 | { |
458fb679 | 1151 | QTAILQ_INSERT_TAIL(&global_props, prop, next); |
b6b61144 GH |
1152 | } |
1153 | ||
458fb679 | 1154 | void qdev_prop_register_global_list(GlobalProperty *props) |
b6b61144 | 1155 | { |
458fb679 | 1156 | int i; |
b6b61144 | 1157 | |
458fb679 GH |
1158 | for (i = 0; props[i].driver != NULL; i++) { |
1159 | qdev_prop_register_global(props+i); | |
b6b61144 | 1160 | } |
458fb679 GH |
1161 | } |
1162 | ||
1163 | void qdev_prop_set_globals(DeviceState *dev) | |
1164 | { | |
1165 | GlobalProperty *prop; | |
1166 | ||
1167 | QTAILQ_FOREACH(prop, &global_props, next) { | |
07a8de35 GH |
1168 | if (strcmp(dev->info->name, prop->driver) != 0 && |
1169 | strcmp(dev->info->bus_info->name, prop->driver) != 0) { | |
b6b61144 GH |
1170 | continue; |
1171 | } | |
1172 | if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { | |
9ef5c4bf | 1173 | exit(1); |
b6b61144 GH |
1174 | } |
1175 | } | |
1176 | } | |
25920d6a KW |
1177 | |
1178 | static int qdev_add_one_global(QemuOpts *opts, void *opaque) | |
1179 | { | |
1180 | GlobalProperty *g; | |
1181 | ||
7267c094 | 1182 | g = g_malloc0(sizeof(*g)); |
25920d6a KW |
1183 | g->driver = qemu_opt_get(opts, "driver"); |
1184 | g->property = qemu_opt_get(opts, "property"); | |
1185 | g->value = qemu_opt_get(opts, "value"); | |
1186 | qdev_prop_register_global(g); | |
1187 | return 0; | |
1188 | } | |
1189 | ||
1190 | void qemu_add_globals(void) | |
1191 | { | |
3329f07b | 1192 | qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); |
25920d6a | 1193 | } |