]>
Commit | Line | Data |
---|---|---|
18c86e2b | 1 | #include "qemu/osdep.h" |
a27bd6c7 | 2 | #include "hw/qdev-properties.h" |
da34e65c | 3 | #include "qapi/error.h" |
2ae16a6a | 4 | #include "qapi/qapi-types-misc.h" |
407bc4bf | 5 | #include "qobject/qlist.h" |
856dfd8a | 6 | #include "qemu/ctype.h" |
d49b6836 | 7 | #include "qemu/error-report.h" |
7b1b5d19 | 8 | #include "qapi/visitor.h" |
645b55d1 | 9 | #include "qemu/units.h" |
f7806925 | 10 | #include "qemu/cutils.h" |
a2974439 | 11 | #include "qdev-prop-internal.h" |
32400a7e | 12 | #include "qom/qom-qobject.h" |
ee6847d1 | 13 | |
b000dfbd PM |
14 | void qdev_prop_set_after_realize(DeviceState *dev, const char *name, |
15 | Error **errp) | |
16 | { | |
17 | if (dev->id) { | |
18 | error_setg(errp, "Attempt to set property '%s' on device '%s' " | |
19 | "(type '%s') after it was realized", name, dev->id, | |
20 | object_get_typename(OBJECT(dev))); | |
21 | } else { | |
22 | error_setg(errp, "Attempt to set property '%s' on anonymous device " | |
23 | "(type '%s') after it was realized", name, | |
24 | object_get_typename(OBJECT(dev))); | |
25 | } | |
26 | } | |
27 | ||
ea7c1e5c EH |
28 | /* returns: true if property is allowed to be set, false otherwise */ |
29 | static bool qdev_prop_allow_set(Object *obj, const char *name, | |
deb2bb16 | 30 | const PropertyInfo *info, Error **errp) |
ea7c1e5c EH |
31 | { |
32 | DeviceState *dev = DEVICE(obj); | |
33 | ||
deb2bb16 | 34 | if (dev->realized && !info->realized_set_allowed) { |
ea7c1e5c EH |
35 | qdev_prop_set_after_realize(dev, name, errp); |
36 | return false; | |
37 | } | |
38 | return true; | |
39 | } | |
40 | ||
8f5d58ef IM |
41 | void qdev_prop_allow_set_link_before_realize(const Object *obj, |
42 | const char *name, | |
39f72ef9 SH |
43 | Object *val, Error **errp) |
44 | { | |
45 | DeviceState *dev = DEVICE(obj); | |
46 | ||
47 | if (dev->realized) { | |
48 | error_setg(errp, "Attempt to set link property '%s' on device '%s' " | |
49 | "(type '%s') after it was realized", | |
50 | name, dev->id, object_get_typename(obj)); | |
51 | } | |
52 | } | |
53 | ||
e9c0346a | 54 | void *object_field_prop_ptr(Object *obj, const Property *prop) |
ee6847d1 | 55 | { |
828ade86 | 56 | void *ptr = obj; |
ee6847d1 GH |
57 | ptr += prop->offset; |
58 | return ptr; | |
59 | } | |
60 | ||
7ed854af EH |
61 | static void field_prop_get(Object *obj, Visitor *v, const char *name, |
62 | void *opaque, Error **errp) | |
63 | { | |
b1987a25 | 64 | const Property *prop = opaque; |
7ed854af EH |
65 | return prop->info->get(obj, v, name, opaque, errp); |
66 | } | |
67 | ||
68 | /** | |
69 | * field_prop_getter: Return getter function to be used for property | |
70 | * | |
71 | * Return value can be NULL if @info has no getter function. | |
72 | */ | |
73 | static ObjectPropertyAccessor *field_prop_getter(const PropertyInfo *info) | |
74 | { | |
75 | return info->get ? field_prop_get : NULL; | |
76 | } | |
77 | ||
78 | static void field_prop_set(Object *obj, Visitor *v, const char *name, | |
79 | void *opaque, Error **errp) | |
80 | { | |
b1987a25 | 81 | const Property *prop = opaque; |
ea7c1e5c | 82 | |
deb2bb16 | 83 | if (!qdev_prop_allow_set(obj, name, prop->info, errp)) { |
ea7c1e5c EH |
84 | return; |
85 | } | |
86 | ||
7ed854af EH |
87 | return prop->info->set(obj, v, name, opaque, errp); |
88 | } | |
89 | ||
90 | /** | |
91 | * field_prop_setter: Return setter function to be used for property | |
92 | * | |
93 | * Return value can be NULL if @info has not setter function. | |
94 | */ | |
95 | static ObjectPropertyAccessor *field_prop_setter(const PropertyInfo *info) | |
96 | { | |
97 | return info->set ? field_prop_set : NULL; | |
98 | } | |
99 | ||
a2974439 PMD |
100 | void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name, |
101 | void *opaque, Error **errp) | |
d4d34b0d | 102 | { |
b1987a25 | 103 | const Property *prop = opaque; |
1e198715 | 104 | int *ptr = object_field_prop_ptr(obj, prop); |
d4d34b0d | 105 | |
991f0ac9 | 106 | visit_type_enum(v, name, ptr, prop->info->enum_table, errp); |
d4d34b0d MA |
107 | } |
108 | ||
a2974439 PMD |
109 | void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name, |
110 | void *opaque, Error **errp) | |
d4d34b0d | 111 | { |
b1987a25 | 112 | const Property *prop = opaque; |
1e198715 | 113 | int *ptr = object_field_prop_ptr(obj, prop); |
d4d34b0d | 114 | |
991f0ac9 | 115 | visit_type_enum(v, name, ptr, prop->info->enum_table, errp); |
d4d34b0d MA |
116 | } |
117 | ||
a2974439 PMD |
118 | void qdev_propinfo_set_default_value_enum(ObjectProperty *op, |
119 | const Property *prop) | |
a2740ad5 | 120 | { |
77b06bba MAL |
121 | object_property_set_default_str(op, |
122 | qapi_enum_lookup(prop->info->enum_table, prop->defval.i)); | |
a2740ad5 MAL |
123 | } |
124 | ||
d4d34b0d MA |
125 | /* Bit */ |
126 | ||
b1987a25 | 127 | static uint32_t qdev_get_prop_mask(const Property *prop) |
d2364ee4 | 128 | { |
a3d4a1b0 | 129 | assert(prop->info == &qdev_prop_bit); |
d2364ee4 MT |
130 | return 0x1 << prop->bitnr; |
131 | } | |
132 | ||
b1987a25 | 133 | static void bit_prop_set(Object *obj, const Property *props, bool val) |
d2364ee4 | 134 | { |
1e198715 | 135 | uint32_t *p = object_field_prop_ptr(obj, props); |
d2364ee4 | 136 | uint32_t mask = qdev_get_prop_mask(props); |
04a2d61e | 137 | if (val) { |
dbd48324 | 138 | *p |= mask; |
04a2d61e | 139 | } else { |
d2364ee4 | 140 | *p &= ~mask; |
04a2d61e | 141 | } |
d2364ee4 MT |
142 | } |
143 | ||
d7bce999 EB |
144 | static void prop_get_bit(Object *obj, Visitor *v, const char *name, |
145 | void *opaque, Error **errp) | |
80e555c2 | 146 | { |
b1987a25 | 147 | const Property *prop = opaque; |
1e198715 | 148 | uint32_t *p = object_field_prop_ptr(obj, prop); |
80e555c2 PB |
149 | bool value = (*p & qdev_get_prop_mask(prop)) != 0; |
150 | ||
51e72bc1 | 151 | visit_type_bool(v, name, &value, errp); |
80e555c2 PB |
152 | } |
153 | ||
d7bce999 EB |
154 | static void prop_set_bit(Object *obj, Visitor *v, const char *name, |
155 | void *opaque, Error **errp) | |
80e555c2 | 156 | { |
b1987a25 | 157 | const Property *prop = opaque; |
80e555c2 PB |
158 | bool value; |
159 | ||
668f62ec | 160 | if (!visit_type_bool(v, name, &value, errp)) { |
80e555c2 PB |
161 | return; |
162 | } | |
605d9fc0 | 163 | bit_prop_set(obj, prop, value); |
80e555c2 PB |
164 | } |
165 | ||
77b06bba | 166 | static void set_default_value_bool(ObjectProperty *op, const Property *prop) |
a2740ad5 | 167 | { |
77b06bba | 168 | object_property_set_default_bool(op, prop->defval.u); |
a2740ad5 MAL |
169 | } |
170 | ||
1b6b7d10 | 171 | const PropertyInfo qdev_prop_bit = { |
c98dac16 | 172 | .type = "bool", |
51b2e8c3 | 173 | .description = "on/off", |
949fc823 MA |
174 | .get = prop_get_bit, |
175 | .set = prop_set_bit, | |
a2740ad5 | 176 | .set_default_value = set_default_value_bool, |
d2364ee4 MT |
177 | }; |
178 | ||
fdba6d96 GH |
179 | /* Bit64 */ |
180 | ||
b1987a25 | 181 | static uint64_t qdev_get_prop_mask64(const Property *prop) |
fdba6d96 | 182 | { |
8aedc369 | 183 | assert(prop->info == &qdev_prop_bit64); |
1fa795a8 | 184 | return 0x1ull << prop->bitnr; |
fdba6d96 GH |
185 | } |
186 | ||
b1987a25 | 187 | static void bit64_prop_set(Object *obj, const Property *props, bool val) |
fdba6d96 | 188 | { |
1e198715 | 189 | uint64_t *p = object_field_prop_ptr(obj, props); |
fdba6d96 GH |
190 | uint64_t mask = qdev_get_prop_mask64(props); |
191 | if (val) { | |
192 | *p |= mask; | |
193 | } else { | |
194 | *p &= ~mask; | |
195 | } | |
196 | } | |
197 | ||
d7bce999 EB |
198 | static void prop_get_bit64(Object *obj, Visitor *v, const char *name, |
199 | void *opaque, Error **errp) | |
fdba6d96 | 200 | { |
b1987a25 | 201 | const Property *prop = opaque; |
1e198715 | 202 | uint64_t *p = object_field_prop_ptr(obj, prop); |
fdba6d96 GH |
203 | bool value = (*p & qdev_get_prop_mask64(prop)) != 0; |
204 | ||
51e72bc1 | 205 | visit_type_bool(v, name, &value, errp); |
fdba6d96 GH |
206 | } |
207 | ||
d7bce999 EB |
208 | static void prop_set_bit64(Object *obj, Visitor *v, const char *name, |
209 | void *opaque, Error **errp) | |
fdba6d96 | 210 | { |
b1987a25 | 211 | const Property *prop = opaque; |
fdba6d96 GH |
212 | bool value; |
213 | ||
668f62ec | 214 | if (!visit_type_bool(v, name, &value, errp)) { |
fdba6d96 GH |
215 | return; |
216 | } | |
605d9fc0 | 217 | bit64_prop_set(obj, prop, value); |
fdba6d96 GH |
218 | } |
219 | ||
1b6b7d10 | 220 | const PropertyInfo qdev_prop_bit64 = { |
c98dac16 | 221 | .type = "bool", |
fdba6d96 GH |
222 | .description = "on/off", |
223 | .get = prop_get_bit64, | |
224 | .set = prop_set_bit64, | |
a2740ad5 | 225 | .set_default_value = set_default_value_bool, |
fdba6d96 GH |
226 | }; |
227 | ||
72cc5137 IM |
228 | /* --- bool --- */ |
229 | ||
d7bce999 EB |
230 | static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque, |
231 | Error **errp) | |
72cc5137 | 232 | { |
b1987a25 | 233 | const Property *prop = opaque; |
1e198715 | 234 | bool *ptr = object_field_prop_ptr(obj, prop); |
72cc5137 | 235 | |
51e72bc1 | 236 | visit_type_bool(v, name, ptr, errp); |
72cc5137 IM |
237 | } |
238 | ||
d7bce999 EB |
239 | static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque, |
240 | Error **errp) | |
72cc5137 | 241 | { |
b1987a25 | 242 | const Property *prop = opaque; |
1e198715 | 243 | bool *ptr = object_field_prop_ptr(obj, prop); |
72cc5137 | 244 | |
51e72bc1 | 245 | visit_type_bool(v, name, ptr, errp); |
72cc5137 IM |
246 | } |
247 | ||
1b6b7d10 | 248 | const PropertyInfo qdev_prop_bool = { |
c98dac16 | 249 | .type = "bool", |
45e5b493 | 250 | .description = "on/off", |
72cc5137 IM |
251 | .get = get_bool, |
252 | .set = set_bool, | |
a2740ad5 | 253 | .set_default_value = set_default_value_bool, |
72cc5137 IM |
254 | }; |
255 | ||
c7cc172d JQ |
256 | /* --- 8bit integer --- */ |
257 | ||
d7bce999 EB |
258 | static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque, |
259 | Error **errp) | |
80e555c2 | 260 | { |
b1987a25 | 261 | const Property *prop = opaque; |
1e198715 | 262 | uint8_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 263 | |
51e72bc1 | 264 | visit_type_uint8(v, name, ptr, errp); |
80e555c2 PB |
265 | } |
266 | ||
d7bce999 EB |
267 | static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque, |
268 | Error **errp) | |
80e555c2 | 269 | { |
b1987a25 | 270 | const Property *prop = opaque; |
1e198715 | 271 | uint8_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 272 | |
51e72bc1 | 273 | visit_type_uint8(v, name, ptr, errp); |
80e555c2 PB |
274 | } |
275 | ||
93e163e4 PMD |
276 | void qdev_propinfo_set_default_value_int(ObjectProperty *op, |
277 | const Property *prop) | |
a2740ad5 | 278 | { |
77b06bba | 279 | object_property_set_default_int(op, prop->defval.i); |
a2740ad5 MAL |
280 | } |
281 | ||
93e163e4 PMD |
282 | void qdev_propinfo_set_default_value_uint(ObjectProperty *op, |
283 | const Property *prop) | |
3fb2111f | 284 | { |
77b06bba | 285 | object_property_set_default_uint(op, prop->defval.u); |
3fb2111f MAL |
286 | } |
287 | ||
1b6b7d10 | 288 | const PropertyInfo qdev_prop_uint8 = { |
c98dac16 | 289 | .type = "uint8", |
c08fb2ac MR |
290 | .get = get_uint8, |
291 | .set = set_uint8, | |
93e163e4 | 292 | .set_default_value = qdev_propinfo_set_default_value_uint, |
c7cc172d JQ |
293 | }; |
294 | ||
ee6847d1 GH |
295 | /* --- 16bit integer --- */ |
296 | ||
364f7e83 EH |
297 | static void get_uint16(Object *obj, Visitor *v, const char *name, |
298 | void *opaque, Error **errp) | |
80e555c2 | 299 | { |
b1987a25 | 300 | const Property *prop = opaque; |
1e198715 | 301 | uint16_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 302 | |
51e72bc1 | 303 | visit_type_uint16(v, name, ptr, errp); |
80e555c2 PB |
304 | } |
305 | ||
d7bce999 EB |
306 | static void set_uint16(Object *obj, Visitor *v, const char *name, |
307 | void *opaque, Error **errp) | |
80e555c2 | 308 | { |
b1987a25 | 309 | const Property *prop = opaque; |
1e198715 | 310 | uint16_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 311 | |
51e72bc1 | 312 | visit_type_uint16(v, name, ptr, errp); |
80e555c2 PB |
313 | } |
314 | ||
1b6b7d10 | 315 | const PropertyInfo qdev_prop_uint16 = { |
c98dac16 | 316 | .type = "uint16", |
364f7e83 | 317 | .get = get_uint16, |
c08fb2ac | 318 | .set = set_uint16, |
93e163e4 | 319 | .set_default_value = qdev_propinfo_set_default_value_uint, |
ee6847d1 GH |
320 | }; |
321 | ||
322 | /* --- 32bit integer --- */ | |
323 | ||
d7bce999 EB |
324 | static void get_uint32(Object *obj, Visitor *v, const char *name, |
325 | void *opaque, Error **errp) | |
c08fb2ac | 326 | { |
b1987a25 | 327 | const Property *prop = opaque; |
1e198715 | 328 | uint32_t *ptr = object_field_prop_ptr(obj, prop); |
c08fb2ac | 329 | |
51e72bc1 | 330 | visit_type_uint32(v, name, ptr, errp); |
c08fb2ac MR |
331 | } |
332 | ||
d7bce999 EB |
333 | static void set_uint32(Object *obj, Visitor *v, const char *name, |
334 | void *opaque, Error **errp) | |
c08fb2ac | 335 | { |
b1987a25 | 336 | const Property *prop = opaque; |
1e198715 | 337 | uint32_t *ptr = object_field_prop_ptr(obj, prop); |
c08fb2ac | 338 | |
51e72bc1 | 339 | visit_type_uint32(v, name, ptr, errp); |
c08fb2ac MR |
340 | } |
341 | ||
93e163e4 PMD |
342 | void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name, |
343 | void *opaque, Error **errp) | |
80e555c2 | 344 | { |
b1987a25 | 345 | const Property *prop = opaque; |
1e198715 | 346 | int32_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 347 | |
51e72bc1 | 348 | visit_type_int32(v, name, ptr, errp); |
80e555c2 PB |
349 | } |
350 | ||
d7bce999 EB |
351 | static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque, |
352 | Error **errp) | |
80e555c2 | 353 | { |
b1987a25 | 354 | const Property *prop = opaque; |
1e198715 | 355 | int32_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 356 | |
51e72bc1 | 357 | visit_type_int32(v, name, ptr, errp); |
80e555c2 PB |
358 | } |
359 | ||
1b6b7d10 | 360 | const PropertyInfo qdev_prop_uint32 = { |
c98dac16 | 361 | .type = "uint32", |
c08fb2ac MR |
362 | .get = get_uint32, |
363 | .set = set_uint32, | |
93e163e4 | 364 | .set_default_value = qdev_propinfo_set_default_value_uint, |
ee6847d1 GH |
365 | }; |
366 | ||
1b6b7d10 | 367 | const PropertyInfo qdev_prop_int32 = { |
c98dac16 | 368 | .type = "int32", |
93e163e4 | 369 | .get = qdev_propinfo_get_int32, |
80e555c2 | 370 | .set = set_int32, |
93e163e4 | 371 | .set_default_value = qdev_propinfo_set_default_value_int, |
316940b0 GH |
372 | }; |
373 | ||
5a053d1f BS |
374 | /* --- 64bit integer --- */ |
375 | ||
d7bce999 EB |
376 | static void get_uint64(Object *obj, Visitor *v, const char *name, |
377 | void *opaque, Error **errp) | |
80e555c2 | 378 | { |
b1987a25 | 379 | const Property *prop = opaque; |
1e198715 | 380 | uint64_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 381 | |
51e72bc1 | 382 | visit_type_uint64(v, name, ptr, errp); |
80e555c2 PB |
383 | } |
384 | ||
d7bce999 EB |
385 | static void set_uint64(Object *obj, Visitor *v, const char *name, |
386 | void *opaque, Error **errp) | |
80e555c2 | 387 | { |
b1987a25 | 388 | const Property *prop = opaque; |
1e198715 | 389 | uint64_t *ptr = object_field_prop_ptr(obj, prop); |
80e555c2 | 390 | |
51e72bc1 | 391 | visit_type_uint64(v, name, ptr, errp); |
80e555c2 PB |
392 | } |
393 | ||
07d1d063 PX |
394 | static void get_int64(Object *obj, Visitor *v, const char *name, |
395 | void *opaque, Error **errp) | |
396 | { | |
b1987a25 | 397 | const Property *prop = opaque; |
1e198715 | 398 | int64_t *ptr = object_field_prop_ptr(obj, prop); |
07d1d063 PX |
399 | |
400 | visit_type_int64(v, name, ptr, errp); | |
401 | } | |
402 | ||
403 | static void set_int64(Object *obj, Visitor *v, const char *name, | |
404 | void *opaque, Error **errp) | |
405 | { | |
b1987a25 | 406 | const Property *prop = opaque; |
1e198715 | 407 | int64_t *ptr = object_field_prop_ptr(obj, prop); |
07d1d063 | 408 | |
07d1d063 PX |
409 | visit_type_int64(v, name, ptr, errp); |
410 | } | |
411 | ||
1b6b7d10 | 412 | const PropertyInfo qdev_prop_uint64 = { |
c98dac16 | 413 | .type = "uint64", |
c08fb2ac MR |
414 | .get = get_uint64, |
415 | .set = set_uint64, | |
93e163e4 | 416 | .set_default_value = qdev_propinfo_set_default_value_uint, |
5a053d1f BS |
417 | }; |
418 | ||
07d1d063 | 419 | const PropertyInfo qdev_prop_int64 = { |
c98dac16 | 420 | .type = "int64", |
07d1d063 PX |
421 | .get = get_int64, |
422 | .set = set_int64, | |
93e163e4 | 423 | .set_default_value = qdev_propinfo_set_default_value_int, |
07d1d063 PX |
424 | }; |
425 | ||
18c22d71 YW |
426 | static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name, |
427 | void *opaque, Error **errp) | |
428 | { | |
b1987a25 | 429 | const Property *prop = opaque; |
18c22d71 YW |
430 | uint64_t *ptr = object_field_prop_ptr(obj, prop); |
431 | ||
432 | visit_type_uint64(v, name, ptr, errp); | |
433 | if (*ptr & ~prop->bitmask) { | |
434 | error_setg(errp, "Property value for '%s' has bits outside mask '0x%" PRIx64 "'", | |
435 | name, prop->bitmask); | |
436 | } | |
437 | } | |
438 | ||
439 | const PropertyInfo qdev_prop_uint64_checkmask = { | |
c98dac16 | 440 | .type = "uint64", |
18c22d71 YW |
441 | .get = get_uint64, |
442 | .set = set_uint64_checkmask, | |
443 | }; | |
444 | ||
7bda68e8 PB |
445 | /* --- pointer-size integer --- */ |
446 | ||
447 | static void get_usize(Object *obj, Visitor *v, const char *name, void *opaque, | |
448 | Error **errp) | |
449 | { | |
450 | const Property *prop = opaque; | |
451 | ||
452 | #if HOST_LONG_BITS == 32 | |
453 | uint32_t *ptr = object_field_prop_ptr(obj, prop); | |
454 | visit_type_uint32(v, name, ptr, errp); | |
455 | #else | |
456 | uint64_t *ptr = object_field_prop_ptr(obj, prop); | |
457 | visit_type_uint64(v, name, ptr, errp); | |
458 | #endif | |
459 | } | |
460 | ||
461 | static void set_usize(Object *obj, Visitor *v, const char *name, void *opaque, | |
462 | Error **errp) | |
463 | { | |
464 | const Property *prop = opaque; | |
465 | ||
466 | #if HOST_LONG_BITS == 32 | |
467 | uint32_t *ptr = object_field_prop_ptr(obj, prop); | |
468 | visit_type_uint32(v, name, ptr, errp); | |
469 | #else | |
470 | uint64_t *ptr = object_field_prop_ptr(obj, prop); | |
471 | visit_type_uint64(v, name, ptr, errp); | |
472 | #endif | |
473 | } | |
474 | ||
475 | const PropertyInfo qdev_prop_usize = { | |
476 | .type = "usize", | |
477 | .get = get_usize, | |
478 | .set = set_usize, | |
479 | .set_default_value = qdev_propinfo_set_default_value_uint, | |
480 | }; | |
481 | ||
59419663 GH |
482 | /* --- string --- */ |
483 | ||
dd0ba250 | 484 | static void release_string(Object *obj, const char *name, void *opaque) |
d21357df | 485 | { |
b1987a25 | 486 | const Property *prop = opaque; |
1e198715 | 487 | g_free(*(char **)object_field_prop_ptr(obj, prop)); |
d21357df MA |
488 | } |
489 | ||
d7bce999 EB |
490 | static void get_string(Object *obj, Visitor *v, const char *name, |
491 | void *opaque, Error **errp) | |
80e555c2 | 492 | { |
b1987a25 | 493 | const Property *prop = opaque; |
1e198715 | 494 | char **ptr = object_field_prop_ptr(obj, prop); |
80e555c2 PB |
495 | |
496 | if (!*ptr) { | |
497 | char *str = (char *)""; | |
51e72bc1 | 498 | visit_type_str(v, name, &str, errp); |
80e555c2 | 499 | } else { |
51e72bc1 | 500 | visit_type_str(v, name, ptr, errp); |
80e555c2 PB |
501 | } |
502 | } | |
503 | ||
d7bce999 EB |
504 | static void set_string(Object *obj, Visitor *v, const char *name, |
505 | void *opaque, Error **errp) | |
80e555c2 | 506 | { |
b1987a25 | 507 | const Property *prop = opaque; |
1e198715 | 508 | char **ptr = object_field_prop_ptr(obj, prop); |
80e555c2 PB |
509 | char *str; |
510 | ||
668f62ec | 511 | if (!visit_type_str(v, name, &str, errp)) { |
80e555c2 PB |
512 | return; |
513 | } | |
ef1e1e07 | 514 | g_free(*ptr); |
80e555c2 PB |
515 | *ptr = str; |
516 | } | |
517 | ||
1b6b7d10 | 518 | const PropertyInfo qdev_prop_string = { |
c98dac16 | 519 | .type = "str", |
dd0ba250 | 520 | .release = release_string, |
80e555c2 PB |
521 | .get = get_string, |
522 | .set = set_string, | |
59419663 GH |
523 | }; |
524 | ||
55e8a154 MA |
525 | /* --- on/off/auto --- */ |
526 | ||
1b6b7d10 | 527 | const PropertyInfo qdev_prop_on_off_auto = { |
c98dac16 | 528 | .type = "OnOffAuto", |
55e8a154 | 529 | .description = "on/off/auto", |
f7abe0ec | 530 | .enum_table = &OnOffAuto_lookup, |
a2974439 PMD |
531 | .get = qdev_propinfo_get_enum, |
532 | .set = qdev_propinfo_set_enum, | |
533 | .set_default_value = qdev_propinfo_set_default_value_enum, | |
55e8a154 MA |
534 | }; |
535 | ||
914e74cd RK |
536 | /* --- 32bit unsigned int 'size' type --- */ |
537 | ||
93e163e4 PMD |
538 | void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name, |
539 | void *opaque, Error **errp) | |
031ffd9a | 540 | { |
b1987a25 | 541 | const Property *prop = opaque; |
1e198715 | 542 | uint32_t *ptr = object_field_prop_ptr(obj, prop); |
031ffd9a RK |
543 | uint64_t value = *ptr; |
544 | ||
545 | visit_type_size(v, name, &value, errp); | |
546 | } | |
547 | ||
914e74cd RK |
548 | static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, |
549 | Error **errp) | |
550 | { | |
b1987a25 | 551 | const Property *prop = opaque; |
1e198715 | 552 | uint32_t *ptr = object_field_prop_ptr(obj, prop); |
914e74cd | 553 | uint64_t value; |
914e74cd | 554 | |
668f62ec | 555 | if (!visit_type_size(v, name, &value, errp)) { |
914e74cd RK |
556 | return; |
557 | } | |
558 | ||
559 | if (value > UINT32_MAX) { | |
560 | error_setg(errp, | |
561 | "Property %s.%s doesn't take value %" PRIu64 | |
562 | " (maximum: %u)", | |
5eb32b21 | 563 | object_get_typename(obj), name, value, UINT32_MAX); |
914e74cd RK |
564 | return; |
565 | } | |
566 | ||
567 | *ptr = value; | |
568 | } | |
569 | ||
570 | const PropertyInfo qdev_prop_size32 = { | |
c98dac16 | 571 | .type = "size", |
93e163e4 | 572 | .get = qdev_propinfo_get_size32, |
914e74cd | 573 | .set = set_size32, |
93e163e4 | 574 | .set_default_value = qdev_propinfo_set_default_value_uint, |
914e74cd RK |
575 | }; |
576 | ||
0be6bfac PM |
577 | /* --- support for array properties --- */ |
578 | ||
b06f8b50 KW |
579 | typedef struct ArrayElementList ArrayElementList; |
580 | ||
581 | struct ArrayElementList { | |
582 | ArrayElementList *next; | |
583 | void *value; | |
584 | }; | |
585 | ||
586 | /* | |
587 | * Given an array property @parent_prop in @obj, return a Property for a | |
588 | * specific element of the array. Arrays are backed by an uint32_t length field | |
589 | * and an element array. @elem points at an element in this element array. | |
0be6bfac | 590 | */ |
b1987a25 | 591 | static Property array_elem_prop(Object *obj, const Property *parent_prop, |
b06f8b50 KW |
592 | const char *name, char *elem) |
593 | { | |
594 | return (Property) { | |
595 | .info = parent_prop->arrayinfo, | |
596 | .name = name, | |
597 | /* | |
598 | * This ugly piece of pointer arithmetic sets up the offset so | |
599 | * that when the underlying release hook calls qdev_get_prop_ptr | |
600 | * they get the right answer despite the array element not actually | |
601 | * being inside the device struct. | |
602 | */ | |
603 | .offset = (uintptr_t)elem - (uintptr_t)obj, | |
604 | }; | |
605 | } | |
606 | ||
607 | /* | |
608 | * Object property release callback for array properties: We call the | |
609 | * underlying element's property release hook for each element. | |
610 | * | |
611 | * Note that it is the responsibility of the individual device's deinit | |
612 | * to free the array proper. | |
0be6bfac | 613 | */ |
b06f8b50 | 614 | static void release_prop_array(Object *obj, const char *name, void *opaque) |
0be6bfac | 615 | { |
b1987a25 | 616 | const Property *prop = opaque; |
b06f8b50 KW |
617 | uint32_t *alenptr = object_field_prop_ptr(obj, prop); |
618 | void **arrayptr = (void *)obj + prop->arrayoffset; | |
619 | char *elem = *arrayptr; | |
620 | int i; | |
621 | ||
622 | if (!prop->arrayinfo->release) { | |
623 | return; | |
624 | } | |
625 | ||
626 | for (i = 0; i < *alenptr; i++) { | |
627 | Property elem_prop = array_elem_prop(obj, prop, name, elem); | |
628 | prop->arrayinfo->release(obj, NULL, &elem_prop); | |
629 | elem += prop->arrayfieldsize; | |
0be6bfac | 630 | } |
0be6bfac PM |
631 | } |
632 | ||
b06f8b50 KW |
633 | /* |
634 | * Setter for an array property. This sets both the array length (which | |
635 | * is technically the property field in the object) and the array itself | |
636 | * (a pointer to which is stored in the additional field described by | |
637 | * prop->arrayoffset). | |
638 | */ | |
639 | static void set_prop_array(Object *obj, Visitor *v, const char *name, | |
640 | void *opaque, Error **errp) | |
0be6bfac | 641 | { |
b06f8b50 | 642 | ERRP_GUARD(); |
b1987a25 | 643 | const Property *prop = opaque; |
1e198715 | 644 | uint32_t *alenptr = object_field_prop_ptr(obj, prop); |
f405e3cd | 645 | void **arrayptr = (void *)obj + prop->arrayoffset; |
b06f8b50 KW |
646 | ArrayElementList *list, *elem, *next; |
647 | const size_t size = sizeof(*list); | |
648 | char *elemptr; | |
649 | bool ok = true; | |
0be6bfac | 650 | |
0be6bfac PM |
651 | if (*alenptr) { |
652 | error_setg(errp, "array size property %s may not be set more than once", | |
653 | name); | |
654 | return; | |
655 | } | |
b06f8b50 KW |
656 | |
657 | if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) { | |
0be6bfac PM |
658 | return; |
659 | } | |
b06f8b50 KW |
660 | |
661 | /* Read the whole input into a temporary list */ | |
662 | elem = list; | |
663 | while (elem) { | |
664 | Property elem_prop; | |
665 | ||
666 | elem->value = g_malloc0(prop->arrayfieldsize); | |
667 | elem_prop = array_elem_prop(obj, prop, name, elem->value); | |
668 | prop->arrayinfo->set(obj, v, NULL, &elem_prop, errp); | |
669 | if (*errp) { | |
670 | ok = false; | |
671 | goto out_obj; | |
672 | } | |
673 | if (*alenptr == INT_MAX) { | |
674 | error_setg(errp, "array is too big"); | |
675 | return; | |
676 | } | |
677 | (*alenptr)++; | |
678 | elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem, | |
679 | size); | |
680 | } | |
681 | ||
682 | ok = visit_check_list(v, errp); | |
683 | out_obj: | |
684 | visit_end_list(v, (void**) &list); | |
685 | ||
686 | if (!ok) { | |
687 | for (elem = list; elem; elem = next) { | |
688 | Property elem_prop = array_elem_prop(obj, prop, name, | |
689 | elem->value); | |
690 | if (prop->arrayinfo->release) { | |
691 | prop->arrayinfo->release(obj, NULL, &elem_prop); | |
692 | } | |
693 | next = elem->next; | |
694 | g_free(elem->value); | |
695 | g_free(elem); | |
696 | } | |
0be6bfac PM |
697 | return; |
698 | } | |
699 | ||
b06f8b50 KW |
700 | /* |
701 | * Now that we know how big the array has to be, move the data over to a | |
702 | * linear array and free the temporary list. | |
0be6bfac | 703 | */ |
b06f8b50 KW |
704 | *arrayptr = g_malloc_n(*alenptr, prop->arrayfieldsize); |
705 | elemptr = *arrayptr; | |
706 | for (elem = list; elem; elem = next) { | |
707 | memcpy(elemptr, elem->value, prop->arrayfieldsize); | |
708 | elemptr += prop->arrayfieldsize; | |
709 | next = elem->next; | |
710 | g_free(elem->value); | |
711 | g_free(elem); | |
712 | } | |
713 | } | |
0be6bfac | 714 | |
b06f8b50 KW |
715 | static void get_prop_array(Object *obj, Visitor *v, const char *name, |
716 | void *opaque, Error **errp) | |
717 | { | |
718 | ERRP_GUARD(); | |
b1987a25 | 719 | const Property *prop = opaque; |
b06f8b50 KW |
720 | uint32_t *alenptr = object_field_prop_ptr(obj, prop); |
721 | void **arrayptr = (void *)obj + prop->arrayoffset; | |
50571883 KW |
722 | char *elemptr = *arrayptr; |
723 | ArrayElementList *list = NULL, *elem; | |
724 | ArrayElementList **tail = &list; | |
725 | const size_t size = sizeof(*list); | |
b06f8b50 KW |
726 | int i; |
727 | bool ok; | |
728 | ||
50571883 KW |
729 | /* At least the string output visitor needs a real list */ |
730 | for (i = 0; i < *alenptr; i++) { | |
731 | elem = g_new0(ArrayElementList, 1); | |
732 | elem->value = elemptr; | |
733 | elemptr += prop->arrayfieldsize; | |
734 | ||
735 | *tail = elem; | |
736 | tail = &elem->next; | |
737 | } | |
738 | ||
739 | if (!visit_start_list(v, name, (GenericList **) &list, size, errp)) { | |
b06f8b50 | 740 | return; |
0be6bfac | 741 | } |
b06f8b50 | 742 | |
50571883 KW |
743 | elem = list; |
744 | while (elem) { | |
745 | Property elem_prop = array_elem_prop(obj, prop, name, elem->value); | |
b06f8b50 KW |
746 | prop->arrayinfo->get(obj, v, NULL, &elem_prop, errp); |
747 | if (*errp) { | |
748 | goto out_obj; | |
749 | } | |
50571883 KW |
750 | elem = (ArrayElementList *) visit_next_list(v, (GenericList*) elem, |
751 | size); | |
b06f8b50 KW |
752 | } |
753 | ||
754 | /* visit_check_list() can only fail for input visitors */ | |
755 | ok = visit_check_list(v, errp); | |
756 | assert(ok); | |
757 | ||
758 | out_obj: | |
759 | visit_end_list(v, (void**) &list); | |
50571883 KW |
760 | |
761 | while (list) { | |
762 | elem = list; | |
763 | list = elem->next; | |
764 | g_free(elem); | |
765 | } | |
0be6bfac PM |
766 | } |
767 | ||
b06f8b50 KW |
768 | static void default_prop_array(ObjectProperty *op, const Property *prop) |
769 | { | |
770 | object_property_set_default_list(op); | |
771 | } | |
772 | ||
773 | const PropertyInfo qdev_prop_array = { | |
c98dac16 | 774 | .type = "list", |
b06f8b50 KW |
775 | .get = get_prop_array, |
776 | .set = set_prop_array, | |
777 | .release = release_prop_array, | |
778 | .set_default_value = default_prop_array, | |
0be6bfac PM |
779 | }; |
780 | ||
ee6847d1 GH |
781 | /* --- public helpers --- */ |
782 | ||
cb9f4b28 | 783 | static const Property *qdev_prop_walk(DeviceClass *cls, const char *name) |
ee6847d1 | 784 | { |
cb9f4b28 RH |
785 | for (int i = 0, n = cls->props_count_; i < n; ++i) { |
786 | const Property *prop = &cls->props_[i]; | |
787 | if (strcmp(prop->name, name) == 0) { | |
788 | return prop; | |
04a2d61e | 789 | } |
ee6847d1 GH |
790 | } |
791 | return NULL; | |
792 | } | |
793 | ||
d36f165d | 794 | static const Property *qdev_prop_find(DeviceState *dev, const char *name) |
ee6847d1 | 795 | { |
bce54474 | 796 | ObjectClass *class; |
d36f165d | 797 | const Property *prop; |
ee6847d1 GH |
798 | |
799 | /* device properties */ | |
bce54474 PB |
800 | class = object_get_class(OBJECT(dev)); |
801 | do { | |
cb9f4b28 | 802 | prop = qdev_prop_walk(DEVICE_CLASS(class), name); |
bce54474 PB |
803 | if (prop) { |
804 | return prop; | |
805 | } | |
806 | class = object_class_get_parent(class); | |
807 | } while (class != object_class_by_name(TYPE_DEVICE)); | |
ee6847d1 GH |
808 | |
809 | return NULL; | |
810 | } | |
811 | ||
c7525b18 | 812 | void error_set_from_qdev_prop_error(Error **errp, int ret, Object *obj, |
e68c2cb7 | 813 | const char *name, const char *value) |
7db4c4e8 PB |
814 | { |
815 | switch (ret) { | |
816 | case -EEXIST: | |
f231b88d | 817 | error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use", |
e68c2cb7 | 818 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
819 | break; |
820 | default: | |
821 | case -EINVAL: | |
be842efb | 822 | error_setg(errp, "Property '%s.%s' doesn't take value '%s'", |
e68c2cb7 | 823 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
824 | break; |
825 | case -ENOENT: | |
f231b88d | 826 | error_setg(errp, "Property '%s.%s' can't find value '%s'", |
e68c2cb7 | 827 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
828 | break; |
829 | case 0: | |
830 | break; | |
831 | } | |
832 | } | |
833 | ||
f4594a3b IY |
834 | void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) |
835 | { | |
5325cc34 | 836 | object_property_set_bool(OBJECT(dev), name, value, &error_abort); |
f4594a3b IY |
837 | } |
838 | ||
c7cc172d JQ |
839 | void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) |
840 | { | |
5325cc34 | 841 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
c7cc172d JQ |
842 | } |
843 | ||
ee6847d1 GH |
844 | void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
845 | { | |
5325cc34 | 846 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
ee6847d1 GH |
847 | } |
848 | ||
849 | void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) | |
850 | { | |
5325cc34 | 851 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
ee6847d1 GH |
852 | } |
853 | ||
316940b0 GH |
854 | void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
855 | { | |
5325cc34 | 856 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
316940b0 GH |
857 | } |
858 | ||
5a053d1f BS |
859 | void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
860 | { | |
5325cc34 | 861 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
5a053d1f BS |
862 | } |
863 | ||
3b25597b | 864 | void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) |
cc984673 | 865 | { |
5325cc34 | 866 | object_property_set_str(OBJECT(dev), name, value, &error_abort); |
cc984673 MA |
867 | } |
868 | ||
9b170e60 | 869 | void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) |
4e4fa398 | 870 | { |
d36f165d | 871 | const Property *prop; |
9b170e60 PB |
872 | |
873 | prop = qdev_prop_find(dev, name); | |
5325cc34 | 874 | object_property_set_str(OBJECT(dev), name, |
788b305c | 875 | qapi_enum_lookup(prop->info->enum_table, value), |
5325cc34 | 876 | &error_abort); |
4e4fa398 JK |
877 | } |
878 | ||
32400a7e KW |
879 | void qdev_prop_set_array(DeviceState *dev, const char *name, QList *values) |
880 | { | |
b06f8b50 KW |
881 | object_property_set_qobject(OBJECT(dev), name, QOBJECT(values), |
882 | &error_abort); | |
32400a7e KW |
883 | qobject_unref(values); |
884 | } | |
885 | ||
e12ca3ce MAL |
886 | static GPtrArray *global_props(void) |
887 | { | |
888 | static GPtrArray *gp; | |
889 | ||
890 | if (!gp) { | |
891 | gp = g_ptr_array_new(); | |
892 | } | |
893 | ||
894 | return gp; | |
895 | } | |
b6b61144 | 896 | |
a404b612 | 897 | void qdev_prop_register_global(GlobalProperty *prop) |
b6b61144 | 898 | { |
e12ca3ce | 899 | g_ptr_array_add(global_props(), prop); |
b6b61144 GH |
900 | } |
901 | ||
39501275 | 902 | const GlobalProperty *qdev_find_global_prop(Object *obj, |
1bc13336 MA |
903 | const char *name) |
904 | { | |
905 | GPtrArray *props = global_props(); | |
906 | const GlobalProperty *p; | |
907 | int i; | |
908 | ||
909 | for (i = 0; i < props->len; i++) { | |
910 | p = g_ptr_array_index(props, i); | |
39501275 | 911 | if (object_dynamic_cast(obj, p->driver) |
1bc13336 MA |
912 | && !strcmp(p->property, name)) { |
913 | return p; | |
914 | } | |
915 | } | |
916 | return NULL; | |
917 | } | |
918 | ||
d828c430 | 919 | int qdev_prop_check_globals(void) |
9f9260a3 | 920 | { |
e12ca3ce | 921 | int i, ret = 0; |
9f9260a3 | 922 | |
e12ca3ce MAL |
923 | for (i = 0; i < global_props()->len; i++) { |
924 | GlobalProperty *prop; | |
b3ce84fe EH |
925 | ObjectClass *oc; |
926 | DeviceClass *dc; | |
e12ca3ce MAL |
927 | |
928 | prop = g_ptr_array_index(global_props(), i); | |
b3ce84fe EH |
929 | if (prop->used) { |
930 | continue; | |
931 | } | |
b3ce84fe EH |
932 | oc = object_class_by_name(prop->driver); |
933 | oc = object_class_dynamic_cast(oc, TYPE_DEVICE); | |
934 | if (!oc) { | |
3dc6f869 AF |
935 | warn_report("global %s.%s has invalid class name", |
936 | prop->driver, prop->property); | |
b3ce84fe EH |
937 | ret = 1; |
938 | continue; | |
939 | } | |
940 | dc = DEVICE_CLASS(oc); | |
941 | if (!dc->hotpluggable && !prop->used) { | |
3dc6f869 AF |
942 | warn_report("global %s.%s=%s not used", |
943 | prop->driver, prop->property, prop->value); | |
b3ce84fe | 944 | ret = 1; |
9f9260a3 DS |
945 | continue; |
946 | } | |
9f9260a3 DS |
947 | } |
948 | return ret; | |
949 | } | |
950 | ||
5eb6a3c5 | 951 | void qdev_prop_set_globals(DeviceState *dev) |
868d378b | 952 | { |
50545b2c MAL |
953 | object_apply_global_props(OBJECT(dev), global_props(), |
954 | dev->hotplugged ? NULL : &error_fatal); | |
868d378b AF |
955 | } |
956 | ||
e8cd45c7 VL |
957 | /* --- 64bit unsigned int 'size' type --- */ |
958 | ||
d7bce999 EB |
959 | static void get_size(Object *obj, Visitor *v, const char *name, void *opaque, |
960 | Error **errp) | |
e8cd45c7 | 961 | { |
b1987a25 | 962 | const Property *prop = opaque; |
1e198715 | 963 | uint64_t *ptr = object_field_prop_ptr(obj, prop); |
e8cd45c7 | 964 | |
51e72bc1 | 965 | visit_type_size(v, name, ptr, errp); |
e8cd45c7 VL |
966 | } |
967 | ||
d7bce999 EB |
968 | static void set_size(Object *obj, Visitor *v, const char *name, void *opaque, |
969 | Error **errp) | |
e8cd45c7 | 970 | { |
b1987a25 | 971 | const Property *prop = opaque; |
1e198715 | 972 | uint64_t *ptr = object_field_prop_ptr(obj, prop); |
e8cd45c7 | 973 | |
51e72bc1 | 974 | visit_type_size(v, name, ptr, errp); |
e8cd45c7 VL |
975 | } |
976 | ||
1b6b7d10 | 977 | const PropertyInfo qdev_prop_size = { |
c98dac16 | 978 | .type = "size", |
e8cd45c7 VL |
979 | .get = get_size, |
980 | .set = set_size, | |
93e163e4 | 981 | .set_default_value = qdev_propinfo_set_default_value_uint, |
e8cd45c7 | 982 | }; |
5b4ff3c6 FZ |
983 | |
984 | /* --- object link property --- */ | |
985 | ||
f59c6d22 | 986 | static ObjectProperty *create_link_property(ObjectClass *oc, const char *name, |
d36f165d | 987 | const Property *prop) |
5b4ff3c6 | 988 | { |
f59c6d22 EH |
989 | return object_class_property_add_link(oc, name, prop->link_type, |
990 | prop->offset, | |
991 | qdev_prop_allow_set_link_before_realize, | |
992 | OBJ_PROP_LINK_STRONG); | |
5b4ff3c6 FZ |
993 | } |
994 | ||
1b6b7d10 | 995 | const PropertyInfo qdev_prop_link = { |
c98dac16 | 996 | .type = "link", |
5b4ff3c6 FZ |
997 | .create = create_link_property, |
998 | }; | |
d3fd6e73 | 999 | |
d36f165d | 1000 | void qdev_property_add_static(DeviceState *dev, const Property *prop) |
d3fd6e73 EH |
1001 | { |
1002 | Object *obj = OBJECT(dev); | |
1003 | ObjectProperty *op; | |
1004 | ||
1005 | assert(!prop->info->create); | |
1006 | ||
c98dac16 | 1007 | op = object_property_add(obj, prop->name, prop->info->type, |
7ed854af EH |
1008 | field_prop_getter(prop->info), |
1009 | field_prop_setter(prop->info), | |
d3fd6e73 | 1010 | prop->info->release, |
d36f165d | 1011 | (Property *)prop); |
d3fd6e73 EH |
1012 | |
1013 | object_property_set_description(obj, prop->name, | |
1014 | prop->info->description); | |
1015 | ||
1016 | if (prop->set_default) { | |
1017 | prop->info->set_default_value(op, prop); | |
1018 | if (op->init) { | |
1019 | op->init(obj, op); | |
1020 | } | |
1021 | } | |
1022 | } | |
1023 | ||
23a1dae8 | 1024 | static void qdev_class_add_property(DeviceClass *klass, const char *name, |
d36f165d | 1025 | const Property *prop) |
d3fd6e73 EH |
1026 | { |
1027 | ObjectClass *oc = OBJECT_CLASS(klass); | |
0d5d5bc5 | 1028 | ObjectProperty *op; |
d3fd6e73 EH |
1029 | |
1030 | if (prop->info->create) { | |
0d5d5bc5 | 1031 | op = prop->info->create(oc, name, prop); |
d3fd6e73 | 1032 | } else { |
d3fd6e73 | 1033 | op = object_class_property_add(oc, |
c98dac16 | 1034 | name, prop->info->type, |
7ed854af EH |
1035 | field_prop_getter(prop->info), |
1036 | field_prop_setter(prop->info), | |
d3fd6e73 | 1037 | prop->info->release, |
d36f165d | 1038 | (Property *)prop); |
d3fd6e73 | 1039 | } |
0d5d5bc5 EH |
1040 | if (prop->set_default) { |
1041 | prop->info->set_default_value(op, prop); | |
1042 | } | |
1043 | object_class_property_set_description(oc, name, prop->info->description); | |
d3fd6e73 EH |
1044 | } |
1045 | ||
1046 | /** | |
1047 | * Legacy property handling | |
1048 | */ | |
1049 | ||
1050 | static void qdev_get_legacy_property(Object *obj, Visitor *v, | |
1051 | const char *name, void *opaque, | |
1052 | Error **errp) | |
1053 | { | |
b1987a25 | 1054 | const Property *prop = opaque; |
d3fd6e73 EH |
1055 | |
1056 | char buffer[1024]; | |
1057 | char *ptr = buffer; | |
1058 | ||
40ea00b0 | 1059 | prop->info->print(obj, prop, buffer, sizeof(buffer)); |
d3fd6e73 EH |
1060 | visit_type_str(v, name, &ptr, errp); |
1061 | } | |
1062 | ||
1063 | /** | |
1064 | * qdev_class_add_legacy_property: | |
1065 | * @dev: Device to add the property to. | |
1066 | * @prop: The qdev property definition. | |
1067 | * | |
1068 | * Add a legacy QOM property to @dev for qdev property @prop. | |
1069 | * | |
1070 | * Legacy properties are string versions of QOM properties. The format of | |
1071 | * the string depends on the property type. Legacy properties are only | |
1072 | * needed for "info qtree". | |
1073 | * | |
1074 | * Do not use this in new code! QOM Properties added through this interface | |
1075 | * will be given names in the "legacy" namespace. | |
1076 | */ | |
d36f165d | 1077 | static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop) |
d3fd6e73 EH |
1078 | { |
1079 | g_autofree char *name = NULL; | |
1080 | ||
1081 | /* Register pointer properties as legacy properties */ | |
1082 | if (!prop->info->print && prop->info->get) { | |
1083 | return; | |
1084 | } | |
1085 | ||
1086 | name = g_strdup_printf("legacy-%s", prop->name); | |
1087 | object_class_property_add(OBJECT_CLASS(dc), name, "str", | |
1088 | prop->info->print ? qdev_get_legacy_property : prop->info->get, | |
d36f165d | 1089 | NULL, NULL, (Property *)prop); |
d3fd6e73 EH |
1090 | } |
1091 | ||
cb9f4b28 RH |
1092 | void device_class_set_props_n(DeviceClass *dc, const Property *props, size_t n) |
1093 | { | |
1094 | /* We used a hole in DeviceClass because that's still a lot. */ | |
1095 | assert(n <= UINT16_MAX); | |
1096 | assert(n != 0); | |
d3fd6e73 EH |
1097 | |
1098 | dc->props_ = props; | |
cb9f4b28 RH |
1099 | dc->props_count_ = n; |
1100 | ||
1101 | for (size_t i = 0; i < n; ++i) { | |
1102 | const Property *prop = &props[i]; | |
1103 | assert(prop->name); | |
d3fd6e73 | 1104 | qdev_class_add_legacy_property(dc, prop); |
23a1dae8 | 1105 | qdev_class_add_property(dc, prop->name, prop); |
d3fd6e73 EH |
1106 | } |
1107 | } | |
1108 | ||
1109 | void qdev_alias_all_properties(DeviceState *target, Object *source) | |
1110 | { | |
1111 | ObjectClass *class; | |
350147a8 SH |
1112 | ObjectPropertyIterator iter; |
1113 | ObjectProperty *prop; | |
d3fd6e73 EH |
1114 | |
1115 | class = object_get_class(OBJECT(target)); | |
d3fd6e73 | 1116 | |
350147a8 SH |
1117 | object_class_property_iter_init(&iter, class); |
1118 | while ((prop = object_property_iter_next(&iter))) { | |
1119 | if (object_property_find(source, prop->name)) { | |
1120 | continue; /* skip duplicate properties */ | |
d3fd6e73 | 1121 | } |
350147a8 SH |
1122 | |
1123 | object_property_add_alias(source, prop->name, | |
1124 | OBJECT(target), prop->name); | |
1125 | } | |
d3fd6e73 | 1126 | } |