]>
Commit | Line | Data |
---|---|---|
14b41872 | 1 | #include "sysemu.h" |
1503fff3 | 2 | #include "net.h" |
ee6847d1 | 3 | #include "qdev.h" |
9f59b566 | 4 | #include "qerror.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 | { | |
54 | uint8_t *p = qdev_get_prop_ptr(dev, prop); | |
55 | return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); | |
56 | } | |
57 | ||
58 | PropertyInfo qdev_prop_bit = { | |
59 | .name = "on/off", | |
60 | .type = PROP_TYPE_BIT, | |
61 | .size = sizeof(uint32_t), | |
62 | .parse = parse_bit, | |
63 | .print = print_bit, | |
64 | }; | |
65 | ||
c7cc172d JQ |
66 | /* --- 8bit integer --- */ |
67 | ||
68 | static int parse_uint8(DeviceState *dev, Property *prop, const char *str) | |
69 | { | |
70 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
71 | const char *fmt; | |
72 | ||
73 | /* accept both hex and decimal */ | |
74 | fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx8 : "%" PRIu8; | |
75 | if (sscanf(str, fmt, ptr) != 1) | |
6bf38816 | 76 | return -EINVAL; |
c7cc172d JQ |
77 | return 0; |
78 | } | |
79 | ||
80 | static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) | |
81 | { | |
82 | uint8_t *ptr = qdev_get_prop_ptr(dev, prop); | |
83 | return snprintf(dest, len, "%" PRIu8, *ptr); | |
84 | } | |
85 | ||
86 | PropertyInfo qdev_prop_uint8 = { | |
87 | .name = "uint8", | |
88 | .type = PROP_TYPE_UINT8, | |
89 | .size = sizeof(uint8_t), | |
90 | .parse = parse_uint8, | |
91 | .print = print_uint8, | |
92 | }; | |
93 | ||
ee6847d1 GH |
94 | /* --- 16bit integer --- */ |
95 | ||
96 | static int parse_uint16(DeviceState *dev, Property *prop, const char *str) | |
97 | { | |
98 | uint16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
99 | const char *fmt; | |
100 | ||
101 | /* accept both hex and decimal */ | |
102 | fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx16 : "%" PRIu16; | |
103 | if (sscanf(str, fmt, ptr) != 1) | |
6bf38816 | 104 | return -EINVAL; |
ee6847d1 GH |
105 | return 0; |
106 | } | |
107 | ||
108 | static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) | |
109 | { | |
110 | uint16_t *ptr = qdev_get_prop_ptr(dev, prop); | |
111 | return snprintf(dest, len, "%" PRIu16, *ptr); | |
112 | } | |
113 | ||
114 | PropertyInfo qdev_prop_uint16 = { | |
115 | .name = "uint16", | |
116 | .type = PROP_TYPE_UINT16, | |
117 | .size = sizeof(uint16_t), | |
118 | .parse = parse_uint16, | |
119 | .print = print_uint16, | |
120 | }; | |
121 | ||
122 | /* --- 32bit integer --- */ | |
123 | ||
124 | static int parse_uint32(DeviceState *dev, Property *prop, const char *str) | |
125 | { | |
126 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
127 | const char *fmt; | |
128 | ||
129 | /* accept both hex and decimal */ | |
130 | fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx32 : "%" PRIu32; | |
131 | if (sscanf(str, fmt, ptr) != 1) | |
6bf38816 | 132 | return -EINVAL; |
ee6847d1 GH |
133 | return 0; |
134 | } | |
135 | ||
136 | static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
137 | { | |
138 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
139 | return snprintf(dest, len, "%" PRIu32, *ptr); | |
140 | } | |
141 | ||
142 | PropertyInfo qdev_prop_uint32 = { | |
143 | .name = "uint32", | |
144 | .type = PROP_TYPE_UINT32, | |
145 | .size = sizeof(uint32_t), | |
146 | .parse = parse_uint32, | |
147 | .print = print_uint32, | |
148 | }; | |
149 | ||
316940b0 GH |
150 | static int parse_int32(DeviceState *dev, Property *prop, const char *str) |
151 | { | |
152 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
153 | ||
154 | if (sscanf(str, "%" PRId32, ptr) != 1) | |
6bf38816 | 155 | return -EINVAL; |
316940b0 GH |
156 | return 0; |
157 | } | |
158 | ||
159 | static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
160 | { | |
161 | int32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
162 | return snprintf(dest, len, "%" PRId32, *ptr); | |
163 | } | |
164 | ||
165 | PropertyInfo qdev_prop_int32 = { | |
166 | .name = "int32", | |
167 | .type = PROP_TYPE_INT32, | |
168 | .size = sizeof(int32_t), | |
169 | .parse = parse_int32, | |
170 | .print = print_int32, | |
171 | }; | |
172 | ||
ee6847d1 GH |
173 | /* --- 32bit hex value --- */ |
174 | ||
175 | static int parse_hex32(DeviceState *dev, Property *prop, const char *str) | |
176 | { | |
177 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
178 | ||
179 | if (sscanf(str, "%" PRIx32, ptr) != 1) | |
6bf38816 | 180 | return -EINVAL; |
ee6847d1 GH |
181 | return 0; |
182 | } | |
183 | ||
184 | static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) | |
185 | { | |
186 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
187 | return snprintf(dest, len, "0x%" PRIx32, *ptr); | |
188 | } | |
189 | ||
190 | PropertyInfo qdev_prop_hex32 = { | |
191 | .name = "hex32", | |
192 | .type = PROP_TYPE_UINT32, | |
193 | .size = sizeof(uint32_t), | |
194 | .parse = parse_hex32, | |
195 | .print = print_hex32, | |
196 | }; | |
197 | ||
5a053d1f BS |
198 | /* --- 64bit integer --- */ |
199 | ||
200 | static int parse_uint64(DeviceState *dev, Property *prop, const char *str) | |
201 | { | |
202 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
203 | const char *fmt; | |
204 | ||
205 | /* accept both hex and decimal */ | |
206 | fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx64 : "%" PRIu64; | |
207 | if (sscanf(str, fmt, ptr) != 1) | |
6bf38816 | 208 | return -EINVAL; |
5a053d1f BS |
209 | return 0; |
210 | } | |
211 | ||
212 | static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) | |
213 | { | |
214 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
215 | return snprintf(dest, len, "%" PRIu64, *ptr); | |
216 | } | |
217 | ||
218 | PropertyInfo qdev_prop_uint64 = { | |
219 | .name = "uint64", | |
220 | .type = PROP_TYPE_UINT64, | |
221 | .size = sizeof(uint64_t), | |
222 | .parse = parse_uint64, | |
223 | .print = print_uint64, | |
224 | }; | |
225 | ||
226 | /* --- 64bit hex value --- */ | |
227 | ||
228 | static int parse_hex64(DeviceState *dev, Property *prop, const char *str) | |
229 | { | |
230 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
231 | ||
232 | if (sscanf(str, "%" PRIx64, ptr) != 1) | |
6bf38816 | 233 | return -EINVAL; |
5a053d1f BS |
234 | return 0; |
235 | } | |
236 | ||
237 | static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) | |
238 | { | |
239 | uint64_t *ptr = qdev_get_prop_ptr(dev, prop); | |
240 | return snprintf(dest, len, "0x%" PRIx64, *ptr); | |
241 | } | |
242 | ||
243 | PropertyInfo qdev_prop_hex64 = { | |
244 | .name = "hex64", | |
245 | .type = PROP_TYPE_UINT64, | |
246 | .size = sizeof(uint64_t), | |
247 | .parse = parse_hex64, | |
248 | .print = print_hex64, | |
249 | }; | |
250 | ||
59419663 GH |
251 | /* --- string --- */ |
252 | ||
253 | static int parse_string(DeviceState *dev, Property *prop, const char *str) | |
254 | { | |
255 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
256 | ||
257 | if (*ptr) | |
258 | qemu_free(*ptr); | |
259 | *ptr = qemu_strdup(str); | |
260 | return 0; | |
261 | } | |
262 | ||
263 | static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) | |
264 | { | |
265 | char **ptr = qdev_get_prop_ptr(dev, prop); | |
266 | if (!*ptr) | |
267 | return snprintf(dest, len, "<null>"); | |
268 | return snprintf(dest, len, "\"%s\"", *ptr); | |
269 | } | |
270 | ||
271 | PropertyInfo qdev_prop_string = { | |
272 | .name = "string", | |
273 | .type = PROP_TYPE_STRING, | |
274 | .size = sizeof(char*), | |
275 | .parse = parse_string, | |
276 | .print = print_string, | |
277 | }; | |
278 | ||
14b41872 GH |
279 | /* --- drive --- */ |
280 | ||
281 | static int parse_drive(DeviceState *dev, Property *prop, const char *str) | |
282 | { | |
283 | DriveInfo **ptr = qdev_get_prop_ptr(dev, prop); | |
284 | ||
285 | *ptr = drive_get_by_id(str); | |
286 | if (*ptr == NULL) | |
6bf38816 | 287 | return -ENOENT; |
14b41872 GH |
288 | return 0; |
289 | } | |
290 | ||
291 | static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) | |
292 | { | |
293 | DriveInfo **ptr = qdev_get_prop_ptr(dev, prop); | |
41b5e892 | 294 | return snprintf(dest, len, "%s", (*ptr) ? (*ptr)->id : "<null>"); |
14b41872 GH |
295 | } |
296 | ||
297 | PropertyInfo qdev_prop_drive = { | |
298 | .name = "drive", | |
299 | .type = PROP_TYPE_DRIVE, | |
300 | .size = sizeof(DriveInfo*), | |
301 | .parse = parse_drive, | |
302 | .print = print_drive, | |
303 | }; | |
304 | ||
313feaab GH |
305 | /* --- character device --- */ |
306 | ||
06113719 GH |
307 | static int parse_chr(DeviceState *dev, Property *prop, const char *str) |
308 | { | |
309 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
310 | ||
311 | *ptr = qemu_chr_find(str); | |
312 | if (*ptr == NULL) | |
6bf38816 | 313 | return -ENOENT; |
06113719 GH |
314 | return 0; |
315 | } | |
316 | ||
313feaab GH |
317 | static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) |
318 | { | |
319 | CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); | |
bc19fcaa BS |
320 | |
321 | if (*ptr && (*ptr)->label) { | |
322 | return snprintf(dest, len, "%s", (*ptr)->label); | |
323 | } else { | |
324 | return snprintf(dest, len, "<null>"); | |
325 | } | |
313feaab GH |
326 | } |
327 | ||
328 | PropertyInfo qdev_prop_chr = { | |
329 | .name = "chr", | |
330 | .type = PROP_TYPE_CHR, | |
331 | .size = sizeof(CharDriverState*), | |
06113719 | 332 | .parse = parse_chr, |
313feaab GH |
333 | .print = print_chr, |
334 | }; | |
335 | ||
2ef924b4 GH |
336 | /* --- netdev device --- */ |
337 | ||
338 | static int parse_netdev(DeviceState *dev, Property *prop, const char *str) | |
339 | { | |
340 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
341 | ||
342 | *ptr = qemu_find_netdev(str); | |
343 | if (*ptr == NULL) | |
6bf38816 | 344 | return -ENOENT; |
27f3f8a3 MA |
345 | if ((*ptr)->peer) { |
346 | return -EEXIST; | |
347 | } | |
2ef924b4 GH |
348 | return 0; |
349 | } | |
350 | ||
351 | static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len) | |
352 | { | |
353 | VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); | |
354 | ||
355 | if (*ptr && (*ptr)->name) { | |
356 | return snprintf(dest, len, "%s", (*ptr)->name); | |
357 | } else { | |
358 | return snprintf(dest, len, "<null>"); | |
359 | } | |
360 | } | |
361 | ||
362 | PropertyInfo qdev_prop_netdev = { | |
363 | .name = "netdev", | |
364 | .type = PROP_TYPE_NETDEV, | |
365 | .size = sizeof(VLANClientState*), | |
366 | .parse = parse_netdev, | |
367 | .print = print_netdev, | |
368 | }; | |
369 | ||
851bec09 GH |
370 | /* --- vlan --- */ |
371 | ||
372 | static int parse_vlan(DeviceState *dev, Property *prop, const char *str) | |
373 | { | |
374 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
375 | int id; | |
376 | ||
377 | if (sscanf(str, "%d", &id) != 1) | |
6bf38816 | 378 | return -EINVAL; |
851bec09 GH |
379 | *ptr = qemu_find_vlan(id, 1); |
380 | if (*ptr == NULL) | |
6bf38816 | 381 | return -ENOENT; |
851bec09 GH |
382 | return 0; |
383 | } | |
384 | ||
385 | static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) | |
386 | { | |
387 | VLANState **ptr = qdev_get_prop_ptr(dev, prop); | |
388 | ||
389 | if (*ptr) { | |
390 | return snprintf(dest, len, "%d", (*ptr)->id); | |
391 | } else { | |
392 | return snprintf(dest, len, "<null>"); | |
393 | } | |
394 | } | |
395 | ||
396 | PropertyInfo qdev_prop_vlan = { | |
397 | .name = "vlan", | |
398 | .type = PROP_TYPE_VLAN, | |
399 | .size = sizeof(VLANClientState*), | |
400 | .parse = parse_vlan, | |
401 | .print = print_vlan, | |
402 | }; | |
403 | ||
ee6847d1 GH |
404 | /* --- pointer --- */ |
405 | ||
036f7166 | 406 | /* Not a proper property, just for dirty hacks. TODO Remove it! */ |
ee6847d1 GH |
407 | PropertyInfo qdev_prop_ptr = { |
408 | .name = "ptr", | |
409 | .type = PROP_TYPE_PTR, | |
410 | .size = sizeof(void*), | |
ee6847d1 GH |
411 | }; |
412 | ||
413 | /* --- mac address --- */ | |
414 | ||
415 | /* | |
416 | * accepted syntax versions: | |
417 | * 01:02:03:04:05:06 | |
418 | * 01-02-03-04-05-06 | |
419 | */ | |
420 | static int parse_mac(DeviceState *dev, Property *prop, const char *str) | |
421 | { | |
1503fff3 | 422 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
ee6847d1 GH |
423 | int i, pos; |
424 | char *p; | |
425 | ||
426 | for (i = 0, pos = 0; i < 6; i++, pos += 3) { | |
88e150a5 | 427 | if (!qemu_isxdigit(str[pos])) |
6bf38816 | 428 | return -EINVAL; |
88e150a5 | 429 | if (!qemu_isxdigit(str[pos+1])) |
6bf38816 | 430 | return -EINVAL; |
1503fff3 GH |
431 | if (i == 5) { |
432 | if (str[pos+2] != '\0') | |
6bf38816 | 433 | return -EINVAL; |
1503fff3 GH |
434 | } else { |
435 | if (str[pos+2] != ':' && str[pos+2] != '-') | |
6bf38816 | 436 | return -EINVAL; |
1503fff3 GH |
437 | } |
438 | mac->a[i] = strtol(str+pos, &p, 16); | |
ee6847d1 GH |
439 | } |
440 | return 0; | |
441 | } | |
442 | ||
443 | static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) | |
444 | { | |
1503fff3 GH |
445 | MACAddr *mac = qdev_get_prop_ptr(dev, prop); |
446 | ||
ee6847d1 | 447 | return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", |
1503fff3 GH |
448 | mac->a[0], mac->a[1], mac->a[2], |
449 | mac->a[3], mac->a[4], mac->a[5]); | |
ee6847d1 GH |
450 | } |
451 | ||
452 | PropertyInfo qdev_prop_macaddr = { | |
1503fff3 | 453 | .name = "macaddr", |
ee6847d1 | 454 | .type = PROP_TYPE_MACADDR, |
1503fff3 | 455 | .size = sizeof(MACAddr), |
ee6847d1 GH |
456 | .parse = parse_mac, |
457 | .print = print_mac, | |
458 | }; | |
459 | ||
05cb5fe4 GH |
460 | /* --- pci address --- */ |
461 | ||
462 | /* | |
463 | * bus-local address, i.e. "$slot" or "$slot.$fn" | |
464 | */ | |
465 | static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) | |
466 | { | |
467 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
468 | unsigned int slot, fn, n; | |
469 | ||
470 | if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { | |
471 | fn = 0; | |
472 | if (sscanf(str, "%x%n", &slot, &n) != 1) { | |
6bf38816 | 473 | return -EINVAL; |
05cb5fe4 GH |
474 | } |
475 | } | |
476 | if (str[n] != '\0') | |
6bf38816 | 477 | return -EINVAL; |
05cb5fe4 | 478 | if (fn > 7) |
6bf38816 | 479 | return -EINVAL; |
05cb5fe4 GH |
480 | *ptr = slot << 3 | fn; |
481 | return 0; | |
482 | } | |
483 | ||
484 | static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) | |
485 | { | |
486 | uint32_t *ptr = qdev_get_prop_ptr(dev, prop); | |
487 | ||
73538c31 | 488 | if (*ptr == -1) { |
05cb5fe4 GH |
489 | return snprintf(dest, len, "<unset>"); |
490 | } else { | |
491 | return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); | |
492 | } | |
493 | } | |
494 | ||
495 | PropertyInfo qdev_prop_pci_devfn = { | |
496 | .name = "pci-devfn", | |
497 | .type = PROP_TYPE_UINT32, | |
498 | .size = sizeof(uint32_t), | |
499 | .parse = parse_pci_devfn, | |
500 | .print = print_pci_devfn, | |
501 | }; | |
502 | ||
ee6847d1 GH |
503 | /* --- public helpers --- */ |
504 | ||
505 | static Property *qdev_prop_walk(Property *props, const char *name) | |
506 | { | |
507 | if (!props) | |
508 | return NULL; | |
509 | while (props->name) { | |
510 | if (strcmp(props->name, name) == 0) | |
511 | return props; | |
512 | props++; | |
513 | } | |
514 | return NULL; | |
515 | } | |
516 | ||
517 | static Property *qdev_prop_find(DeviceState *dev, const char *name) | |
518 | { | |
519 | Property *prop; | |
520 | ||
521 | /* device properties */ | |
522 | prop = qdev_prop_walk(dev->info->props, name); | |
523 | if (prop) | |
524 | return prop; | |
525 | ||
526 | /* bus properties */ | |
527 | prop = qdev_prop_walk(dev->parent_bus->info->props, name); | |
528 | if (prop) | |
529 | return prop; | |
530 | ||
531 | return NULL; | |
532 | } | |
533 | ||
d8ed79ae GH |
534 | int qdev_prop_exists(DeviceState *dev, const char *name) |
535 | { | |
536 | return qdev_prop_find(dev, name) ? true : false; | |
537 | } | |
538 | ||
ee6847d1 GH |
539 | int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) |
540 | { | |
541 | Property *prop; | |
6bf38816 | 542 | int ret; |
ee6847d1 GH |
543 | |
544 | prop = qdev_prop_find(dev, name); | |
036f7166 MA |
545 | /* |
546 | * TODO Properties without a parse method are just for dirty | |
547 | * hacks. qdev_prop_ptr is the only such PropertyInfo. It's | |
548 | * marked for removal. The test !prop->info->parse should be | |
549 | * removed along with it. | |
550 | */ | |
551 | if (!prop || !prop->info->parse) { | |
fdcfa190 | 552 | qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); |
ee6847d1 GH |
553 | return -1; |
554 | } | |
6bf38816 MA |
555 | ret = prop->info->parse(dev, prop, value); |
556 | if (ret < 0) { | |
557 | switch (ret) { | |
27f3f8a3 | 558 | case -EEXIST: |
fdcfa190 MA |
559 | qerror_report(QERR_PROPERTY_VALUE_IN_USE, |
560 | dev->info->name, name, value); | |
27f3f8a3 | 561 | break; |
6bf38816 MA |
562 | default: |
563 | case -EINVAL: | |
fdcfa190 MA |
564 | qerror_report(QERR_PROPERTY_VALUE_BAD, |
565 | dev->info->name, name, value); | |
6bf38816 MA |
566 | break; |
567 | case -ENOENT: | |
fdcfa190 MA |
568 | qerror_report(QERR_PROPERTY_VALUE_NOT_FOUND, |
569 | dev->info->name, name, value); | |
6bf38816 MA |
570 | break; |
571 | } | |
9ef5c4bf GH |
572 | return -1; |
573 | } | |
574 | return 0; | |
ee6847d1 GH |
575 | } |
576 | ||
577 | void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) | |
578 | { | |
579 | Property *prop; | |
ee6847d1 GH |
580 | |
581 | prop = qdev_prop_find(dev, name); | |
582 | if (!prop) { | |
583 | fprintf(stderr, "%s: property \"%s.%s\" not found\n", | |
584 | __FUNCTION__, dev->info->name, name); | |
585 | abort(); | |
586 | } | |
587 | if (prop->info->type != type) { | |
588 | fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", | |
589 | __FUNCTION__, dev->info->name, name); | |
590 | abort(); | |
591 | } | |
d2364ee4 | 592 | qdev_prop_cpy(dev, prop, src); |
ee6847d1 GH |
593 | } |
594 | ||
c7cc172d JQ |
595 | void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) |
596 | { | |
597 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8); | |
598 | } | |
599 | ||
ee6847d1 GH |
600 | void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
601 | { | |
602 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); | |
603 | } | |
604 | ||
605 | void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) | |
606 | { | |
607 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); | |
608 | } | |
609 | ||
316940b0 GH |
610 | void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
611 | { | |
612 | qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); | |
613 | } | |
614 | ||
5a053d1f BS |
615 | void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
616 | { | |
617 | qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); | |
618 | } | |
619 | ||
14b41872 GH |
620 | void qdev_prop_set_drive(DeviceState *dev, const char *name, DriveInfo *value) |
621 | { | |
622 | qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); | |
623 | } | |
624 | ||
313feaab GH |
625 | void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) |
626 | { | |
627 | qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); | |
628 | } | |
629 | ||
2ef924b4 GH |
630 | void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value) |
631 | { | |
632 | qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV); | |
633 | } | |
634 | ||
851bec09 GH |
635 | void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value) |
636 | { | |
637 | qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN); | |
638 | } | |
639 | ||
1503fff3 GH |
640 | void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) |
641 | { | |
642 | qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); | |
643 | } | |
644 | ||
ee6847d1 GH |
645 | void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) |
646 | { | |
647 | qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); | |
648 | } | |
649 | ||
650 | void qdev_prop_set_defaults(DeviceState *dev, Property *props) | |
651 | { | |
ee6847d1 GH |
652 | if (!props) |
653 | return; | |
654 | while (props->name) { | |
655 | if (props->defval) { | |
d2364ee4 | 656 | qdev_prop_cpy(dev, props, props->defval); |
ee6847d1 GH |
657 | } |
658 | props++; | |
659 | } | |
660 | } | |
661 | ||
458fb679 | 662 | static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); |
b6b61144 | 663 | |
25920d6a | 664 | static void qdev_prop_register_global(GlobalProperty *prop) |
b6b61144 | 665 | { |
458fb679 | 666 | QTAILQ_INSERT_TAIL(&global_props, prop, next); |
b6b61144 GH |
667 | } |
668 | ||
458fb679 | 669 | void qdev_prop_register_global_list(GlobalProperty *props) |
b6b61144 | 670 | { |
458fb679 | 671 | int i; |
b6b61144 | 672 | |
458fb679 GH |
673 | for (i = 0; props[i].driver != NULL; i++) { |
674 | qdev_prop_register_global(props+i); | |
b6b61144 | 675 | } |
458fb679 GH |
676 | } |
677 | ||
678 | void qdev_prop_set_globals(DeviceState *dev) | |
679 | { | |
680 | GlobalProperty *prop; | |
681 | ||
682 | QTAILQ_FOREACH(prop, &global_props, next) { | |
07a8de35 GH |
683 | if (strcmp(dev->info->name, prop->driver) != 0 && |
684 | strcmp(dev->info->bus_info->name, prop->driver) != 0) { | |
b6b61144 GH |
685 | continue; |
686 | } | |
687 | if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { | |
9ef5c4bf | 688 | exit(1); |
b6b61144 GH |
689 | } |
690 | } | |
691 | } | |
25920d6a KW |
692 | |
693 | static int qdev_add_one_global(QemuOpts *opts, void *opaque) | |
694 | { | |
695 | GlobalProperty *g; | |
696 | ||
697 | g = qemu_mallocz(sizeof(*g)); | |
698 | g->driver = qemu_opt_get(opts, "driver"); | |
699 | g->property = qemu_opt_get(opts, "property"); | |
700 | g->value = qemu_opt_get(opts, "value"); | |
701 | qdev_prop_register_global(g); | |
702 | return 0; | |
703 | } | |
704 | ||
705 | void qemu_add_globals(void) | |
706 | { | |
707 | qemu_opts_foreach(&qemu_global_opts, qdev_add_one_global, NULL, 0); | |
708 | } |