]>
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" |
7b1b5d19 | 5 | #include "qapi/qmp/qerror.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" |
ee6847d1 | 12 | |
b000dfbd PM |
13 | void qdev_prop_set_after_realize(DeviceState *dev, const char *name, |
14 | Error **errp) | |
15 | { | |
16 | if (dev->id) { | |
17 | error_setg(errp, "Attempt to set property '%s' on device '%s' " | |
18 | "(type '%s') after it was realized", name, dev->id, | |
19 | object_get_typename(OBJECT(dev))); | |
20 | } else { | |
21 | error_setg(errp, "Attempt to set property '%s' on anonymous device " | |
22 | "(type '%s') after it was realized", name, | |
23 | object_get_typename(OBJECT(dev))); | |
24 | } | |
25 | } | |
26 | ||
ea7c1e5c EH |
27 | /* returns: true if property is allowed to be set, false otherwise */ |
28 | static bool qdev_prop_allow_set(Object *obj, const char *name, | |
29 | Error **errp) | |
30 | { | |
31 | DeviceState *dev = DEVICE(obj); | |
32 | ||
33 | if (dev->realized) { | |
34 | qdev_prop_set_after_realize(dev, name, errp); | |
35 | return false; | |
36 | } | |
37 | return true; | |
38 | } | |
39 | ||
8f5d58ef IM |
40 | void qdev_prop_allow_set_link_before_realize(const Object *obj, |
41 | const char *name, | |
39f72ef9 SH |
42 | Object *val, Error **errp) |
43 | { | |
44 | DeviceState *dev = DEVICE(obj); | |
45 | ||
46 | if (dev->realized) { | |
47 | error_setg(errp, "Attempt to set link property '%s' on device '%s' " | |
48 | "(type '%s') after it was realized", | |
49 | name, dev->id, object_get_typename(obj)); | |
50 | } | |
51 | } | |
52 | ||
828ade86 | 53 | void *qdev_get_prop_ptr(Object *obj, Property *prop) |
ee6847d1 | 54 | { |
828ade86 | 55 | void *ptr = obj; |
ee6847d1 GH |
56 | ptr += prop->offset; |
57 | return ptr; | |
58 | } | |
59 | ||
7ed854af EH |
60 | static void field_prop_get(Object *obj, Visitor *v, const char *name, |
61 | void *opaque, Error **errp) | |
62 | { | |
63 | Property *prop = opaque; | |
64 | return prop->info->get(obj, v, name, opaque, errp); | |
65 | } | |
66 | ||
67 | /** | |
68 | * field_prop_getter: Return getter function to be used for property | |
69 | * | |
70 | * Return value can be NULL if @info has no getter function. | |
71 | */ | |
72 | static ObjectPropertyAccessor *field_prop_getter(const PropertyInfo *info) | |
73 | { | |
74 | return info->get ? field_prop_get : NULL; | |
75 | } | |
76 | ||
77 | static void field_prop_set(Object *obj, Visitor *v, const char *name, | |
78 | void *opaque, Error **errp) | |
79 | { | |
80 | Property *prop = opaque; | |
ea7c1e5c EH |
81 | |
82 | if (!qdev_prop_allow_set(obj, name, errp)) { | |
83 | return; | |
84 | } | |
85 | ||
7ed854af EH |
86 | return prop->info->set(obj, v, name, opaque, errp); |
87 | } | |
88 | ||
89 | /** | |
90 | * field_prop_setter: Return setter function to be used for property | |
91 | * | |
92 | * Return value can be NULL if @info has not setter function. | |
93 | */ | |
94 | static ObjectPropertyAccessor *field_prop_setter(const PropertyInfo *info) | |
95 | { | |
96 | return info->set ? field_prop_set : NULL; | |
97 | } | |
98 | ||
a2974439 PMD |
99 | void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name, |
100 | void *opaque, Error **errp) | |
d4d34b0d | 101 | { |
d4d34b0d | 102 | Property *prop = opaque; |
828ade86 | 103 | int *ptr = qdev_get_prop_ptr(obj, prop); |
d4d34b0d | 104 | |
991f0ac9 | 105 | visit_type_enum(v, name, ptr, prop->info->enum_table, errp); |
d4d34b0d MA |
106 | } |
107 | ||
a2974439 PMD |
108 | void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name, |
109 | void *opaque, Error **errp) | |
d4d34b0d | 110 | { |
d4d34b0d | 111 | Property *prop = opaque; |
828ade86 | 112 | int *ptr = qdev_get_prop_ptr(obj, prop); |
d4d34b0d | 113 | |
991f0ac9 | 114 | visit_type_enum(v, name, ptr, prop->info->enum_table, errp); |
d4d34b0d MA |
115 | } |
116 | ||
a2974439 PMD |
117 | void qdev_propinfo_set_default_value_enum(ObjectProperty *op, |
118 | const Property *prop) | |
a2740ad5 | 119 | { |
77b06bba MAL |
120 | object_property_set_default_str(op, |
121 | qapi_enum_lookup(prop->info->enum_table, prop->defval.i)); | |
a2740ad5 MAL |
122 | } |
123 | ||
79bdf29c PMD |
124 | const PropertyInfo qdev_prop_enum = { |
125 | .name = "enum", | |
126 | .get = qdev_propinfo_get_enum, | |
127 | .set = qdev_propinfo_set_enum, | |
128 | .set_default_value = qdev_propinfo_set_default_value_enum, | |
129 | }; | |
130 | ||
d4d34b0d MA |
131 | /* Bit */ |
132 | ||
d2364ee4 MT |
133 | static uint32_t qdev_get_prop_mask(Property *prop) |
134 | { | |
a3d4a1b0 | 135 | assert(prop->info == &qdev_prop_bit); |
d2364ee4 MT |
136 | return 0x1 << prop->bitnr; |
137 | } | |
138 | ||
605d9fc0 | 139 | static void bit_prop_set(Object *obj, Property *props, bool val) |
d2364ee4 | 140 | { |
828ade86 | 141 | uint32_t *p = qdev_get_prop_ptr(obj, props); |
d2364ee4 | 142 | uint32_t mask = qdev_get_prop_mask(props); |
04a2d61e | 143 | if (val) { |
dbd48324 | 144 | *p |= mask; |
04a2d61e | 145 | } else { |
d2364ee4 | 146 | *p &= ~mask; |
04a2d61e | 147 | } |
d2364ee4 MT |
148 | } |
149 | ||
d7bce999 EB |
150 | static void prop_get_bit(Object *obj, Visitor *v, const char *name, |
151 | void *opaque, Error **errp) | |
80e555c2 PB |
152 | { |
153 | Property *prop = opaque; | |
828ade86 | 154 | uint32_t *p = qdev_get_prop_ptr(obj, prop); |
80e555c2 PB |
155 | bool value = (*p & qdev_get_prop_mask(prop)) != 0; |
156 | ||
51e72bc1 | 157 | visit_type_bool(v, name, &value, errp); |
80e555c2 PB |
158 | } |
159 | ||
d7bce999 EB |
160 | static void prop_set_bit(Object *obj, Visitor *v, const char *name, |
161 | void *opaque, Error **errp) | |
80e555c2 PB |
162 | { |
163 | Property *prop = opaque; | |
80e555c2 PB |
164 | bool value; |
165 | ||
668f62ec | 166 | if (!visit_type_bool(v, name, &value, errp)) { |
80e555c2 PB |
167 | return; |
168 | } | |
605d9fc0 | 169 | bit_prop_set(obj, prop, value); |
80e555c2 PB |
170 | } |
171 | ||
77b06bba | 172 | static void set_default_value_bool(ObjectProperty *op, const Property *prop) |
a2740ad5 | 173 | { |
77b06bba | 174 | object_property_set_default_bool(op, prop->defval.u); |
a2740ad5 MAL |
175 | } |
176 | ||
1b6b7d10 | 177 | const PropertyInfo qdev_prop_bit = { |
85ca1202 | 178 | .name = "bool", |
51b2e8c3 | 179 | .description = "on/off", |
949fc823 MA |
180 | .get = prop_get_bit, |
181 | .set = prop_set_bit, | |
a2740ad5 | 182 | .set_default_value = set_default_value_bool, |
d2364ee4 MT |
183 | }; |
184 | ||
fdba6d96 GH |
185 | /* Bit64 */ |
186 | ||
187 | static uint64_t qdev_get_prop_mask64(Property *prop) | |
188 | { | |
8aedc369 | 189 | assert(prop->info == &qdev_prop_bit64); |
1fa795a8 | 190 | return 0x1ull << prop->bitnr; |
fdba6d96 GH |
191 | } |
192 | ||
605d9fc0 | 193 | static void bit64_prop_set(Object *obj, Property *props, bool val) |
fdba6d96 | 194 | { |
828ade86 | 195 | uint64_t *p = qdev_get_prop_ptr(obj, props); |
fdba6d96 GH |
196 | uint64_t mask = qdev_get_prop_mask64(props); |
197 | if (val) { | |
198 | *p |= mask; | |
199 | } else { | |
200 | *p &= ~mask; | |
201 | } | |
202 | } | |
203 | ||
d7bce999 EB |
204 | static void prop_get_bit64(Object *obj, Visitor *v, const char *name, |
205 | void *opaque, Error **errp) | |
fdba6d96 | 206 | { |
fdba6d96 | 207 | Property *prop = opaque; |
828ade86 | 208 | uint64_t *p = qdev_get_prop_ptr(obj, prop); |
fdba6d96 GH |
209 | bool value = (*p & qdev_get_prop_mask64(prop)) != 0; |
210 | ||
51e72bc1 | 211 | visit_type_bool(v, name, &value, errp); |
fdba6d96 GH |
212 | } |
213 | ||
d7bce999 EB |
214 | static void prop_set_bit64(Object *obj, Visitor *v, const char *name, |
215 | void *opaque, Error **errp) | |
fdba6d96 | 216 | { |
fdba6d96 | 217 | Property *prop = opaque; |
fdba6d96 GH |
218 | bool value; |
219 | ||
668f62ec | 220 | if (!visit_type_bool(v, name, &value, errp)) { |
fdba6d96 GH |
221 | return; |
222 | } | |
605d9fc0 | 223 | bit64_prop_set(obj, prop, value); |
fdba6d96 GH |
224 | } |
225 | ||
1b6b7d10 | 226 | const PropertyInfo qdev_prop_bit64 = { |
fdba6d96 GH |
227 | .name = "bool", |
228 | .description = "on/off", | |
229 | .get = prop_get_bit64, | |
230 | .set = prop_set_bit64, | |
a2740ad5 | 231 | .set_default_value = set_default_value_bool, |
fdba6d96 GH |
232 | }; |
233 | ||
72cc5137 IM |
234 | /* --- bool --- */ |
235 | ||
d7bce999 EB |
236 | static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque, |
237 | Error **errp) | |
72cc5137 | 238 | { |
72cc5137 | 239 | Property *prop = opaque; |
828ade86 | 240 | bool *ptr = qdev_get_prop_ptr(obj, prop); |
72cc5137 | 241 | |
51e72bc1 | 242 | visit_type_bool(v, name, ptr, errp); |
72cc5137 IM |
243 | } |
244 | ||
d7bce999 EB |
245 | static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque, |
246 | Error **errp) | |
72cc5137 | 247 | { |
72cc5137 | 248 | Property *prop = opaque; |
828ade86 | 249 | bool *ptr = qdev_get_prop_ptr(obj, prop); |
72cc5137 | 250 | |
51e72bc1 | 251 | visit_type_bool(v, name, ptr, errp); |
72cc5137 IM |
252 | } |
253 | ||
1b6b7d10 | 254 | const PropertyInfo qdev_prop_bool = { |
85ca1202 | 255 | .name = "bool", |
72cc5137 IM |
256 | .get = get_bool, |
257 | .set = set_bool, | |
a2740ad5 | 258 | .set_default_value = set_default_value_bool, |
72cc5137 IM |
259 | }; |
260 | ||
c7cc172d JQ |
261 | /* --- 8bit integer --- */ |
262 | ||
d7bce999 EB |
263 | static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque, |
264 | Error **errp) | |
80e555c2 PB |
265 | { |
266 | Property *prop = opaque; | |
828ade86 | 267 | uint8_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 268 | |
51e72bc1 | 269 | visit_type_uint8(v, name, ptr, errp); |
80e555c2 PB |
270 | } |
271 | ||
d7bce999 EB |
272 | static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque, |
273 | Error **errp) | |
80e555c2 PB |
274 | { |
275 | Property *prop = opaque; | |
828ade86 | 276 | uint8_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 277 | |
51e72bc1 | 278 | visit_type_uint8(v, name, ptr, errp); |
80e555c2 PB |
279 | } |
280 | ||
93e163e4 PMD |
281 | void qdev_propinfo_set_default_value_int(ObjectProperty *op, |
282 | const Property *prop) | |
a2740ad5 | 283 | { |
77b06bba | 284 | object_property_set_default_int(op, prop->defval.i); |
a2740ad5 MAL |
285 | } |
286 | ||
93e163e4 PMD |
287 | void qdev_propinfo_set_default_value_uint(ObjectProperty *op, |
288 | const Property *prop) | |
3fb2111f | 289 | { |
77b06bba | 290 | object_property_set_default_uint(op, prop->defval.u); |
3fb2111f MAL |
291 | } |
292 | ||
1b6b7d10 | 293 | const PropertyInfo qdev_prop_uint8 = { |
c7cc172d | 294 | .name = "uint8", |
c08fb2ac MR |
295 | .get = get_uint8, |
296 | .set = set_uint8, | |
93e163e4 | 297 | .set_default_value = qdev_propinfo_set_default_value_uint, |
c7cc172d JQ |
298 | }; |
299 | ||
ee6847d1 GH |
300 | /* --- 16bit integer --- */ |
301 | ||
364f7e83 EH |
302 | static void get_uint16(Object *obj, Visitor *v, const char *name, |
303 | void *opaque, Error **errp) | |
80e555c2 PB |
304 | { |
305 | Property *prop = opaque; | |
828ade86 | 306 | uint16_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 307 | |
51e72bc1 | 308 | visit_type_uint16(v, name, ptr, errp); |
80e555c2 PB |
309 | } |
310 | ||
d7bce999 EB |
311 | static void set_uint16(Object *obj, Visitor *v, const char *name, |
312 | void *opaque, Error **errp) | |
80e555c2 PB |
313 | { |
314 | Property *prop = opaque; | |
828ade86 | 315 | uint16_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 316 | |
51e72bc1 | 317 | visit_type_uint16(v, name, ptr, errp); |
80e555c2 PB |
318 | } |
319 | ||
1b6b7d10 | 320 | const PropertyInfo qdev_prop_uint16 = { |
ee6847d1 | 321 | .name = "uint16", |
364f7e83 | 322 | .get = get_uint16, |
c08fb2ac | 323 | .set = set_uint16, |
93e163e4 | 324 | .set_default_value = qdev_propinfo_set_default_value_uint, |
ee6847d1 GH |
325 | }; |
326 | ||
327 | /* --- 32bit integer --- */ | |
328 | ||
d7bce999 EB |
329 | static void get_uint32(Object *obj, Visitor *v, const char *name, |
330 | void *opaque, Error **errp) | |
c08fb2ac | 331 | { |
c08fb2ac | 332 | Property *prop = opaque; |
828ade86 | 333 | uint32_t *ptr = qdev_get_prop_ptr(obj, prop); |
c08fb2ac | 334 | |
51e72bc1 | 335 | visit_type_uint32(v, name, ptr, errp); |
c08fb2ac MR |
336 | } |
337 | ||
d7bce999 EB |
338 | static void set_uint32(Object *obj, Visitor *v, const char *name, |
339 | void *opaque, Error **errp) | |
c08fb2ac | 340 | { |
c08fb2ac | 341 | Property *prop = opaque; |
828ade86 | 342 | uint32_t *ptr = qdev_get_prop_ptr(obj, prop); |
c08fb2ac | 343 | |
51e72bc1 | 344 | visit_type_uint32(v, name, ptr, errp); |
c08fb2ac MR |
345 | } |
346 | ||
93e163e4 PMD |
347 | void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name, |
348 | void *opaque, Error **errp) | |
80e555c2 PB |
349 | { |
350 | Property *prop = opaque; | |
828ade86 | 351 | int32_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 352 | |
51e72bc1 | 353 | visit_type_int32(v, name, ptr, errp); |
80e555c2 PB |
354 | } |
355 | ||
d7bce999 EB |
356 | static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque, |
357 | Error **errp) | |
80e555c2 PB |
358 | { |
359 | Property *prop = opaque; | |
828ade86 | 360 | int32_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 361 | |
51e72bc1 | 362 | visit_type_int32(v, name, ptr, errp); |
80e555c2 PB |
363 | } |
364 | ||
1b6b7d10 | 365 | const PropertyInfo qdev_prop_uint32 = { |
ee6847d1 | 366 | .name = "uint32", |
c08fb2ac MR |
367 | .get = get_uint32, |
368 | .set = set_uint32, | |
93e163e4 | 369 | .set_default_value = qdev_propinfo_set_default_value_uint, |
ee6847d1 GH |
370 | }; |
371 | ||
1b6b7d10 | 372 | const PropertyInfo qdev_prop_int32 = { |
316940b0 | 373 | .name = "int32", |
93e163e4 | 374 | .get = qdev_propinfo_get_int32, |
80e555c2 | 375 | .set = set_int32, |
93e163e4 | 376 | .set_default_value = qdev_propinfo_set_default_value_int, |
316940b0 GH |
377 | }; |
378 | ||
5a053d1f BS |
379 | /* --- 64bit integer --- */ |
380 | ||
d7bce999 EB |
381 | static void get_uint64(Object *obj, Visitor *v, const char *name, |
382 | void *opaque, Error **errp) | |
80e555c2 PB |
383 | { |
384 | Property *prop = opaque; | |
828ade86 | 385 | uint64_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 386 | |
51e72bc1 | 387 | visit_type_uint64(v, name, ptr, errp); |
80e555c2 PB |
388 | } |
389 | ||
d7bce999 EB |
390 | static void set_uint64(Object *obj, Visitor *v, const char *name, |
391 | void *opaque, Error **errp) | |
80e555c2 PB |
392 | { |
393 | Property *prop = opaque; | |
828ade86 | 394 | uint64_t *ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 | 395 | |
51e72bc1 | 396 | visit_type_uint64(v, name, ptr, errp); |
80e555c2 PB |
397 | } |
398 | ||
07d1d063 PX |
399 | static void get_int64(Object *obj, Visitor *v, const char *name, |
400 | void *opaque, Error **errp) | |
401 | { | |
07d1d063 | 402 | Property *prop = opaque; |
828ade86 | 403 | int64_t *ptr = qdev_get_prop_ptr(obj, prop); |
07d1d063 PX |
404 | |
405 | visit_type_int64(v, name, ptr, errp); | |
406 | } | |
407 | ||
408 | static void set_int64(Object *obj, Visitor *v, const char *name, | |
409 | void *opaque, Error **errp) | |
410 | { | |
07d1d063 | 411 | Property *prop = opaque; |
828ade86 | 412 | int64_t *ptr = qdev_get_prop_ptr(obj, prop); |
07d1d063 | 413 | |
07d1d063 PX |
414 | visit_type_int64(v, name, ptr, errp); |
415 | } | |
416 | ||
1b6b7d10 | 417 | const PropertyInfo qdev_prop_uint64 = { |
5a053d1f | 418 | .name = "uint64", |
c08fb2ac MR |
419 | .get = get_uint64, |
420 | .set = set_uint64, | |
93e163e4 | 421 | .set_default_value = qdev_propinfo_set_default_value_uint, |
5a053d1f BS |
422 | }; |
423 | ||
07d1d063 PX |
424 | const PropertyInfo qdev_prop_int64 = { |
425 | .name = "int64", | |
426 | .get = get_int64, | |
427 | .set = set_int64, | |
93e163e4 | 428 | .set_default_value = qdev_propinfo_set_default_value_int, |
07d1d063 PX |
429 | }; |
430 | ||
59419663 GH |
431 | /* --- string --- */ |
432 | ||
dd0ba250 | 433 | static void release_string(Object *obj, const char *name, void *opaque) |
d21357df | 434 | { |
dd0ba250 | 435 | Property *prop = opaque; |
828ade86 | 436 | g_free(*(char **)qdev_get_prop_ptr(obj, prop)); |
d21357df MA |
437 | } |
438 | ||
d7bce999 EB |
439 | static void get_string(Object *obj, Visitor *v, const char *name, |
440 | void *opaque, Error **errp) | |
80e555c2 PB |
441 | { |
442 | Property *prop = opaque; | |
828ade86 | 443 | char **ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 PB |
444 | |
445 | if (!*ptr) { | |
446 | char *str = (char *)""; | |
51e72bc1 | 447 | visit_type_str(v, name, &str, errp); |
80e555c2 | 448 | } else { |
51e72bc1 | 449 | visit_type_str(v, name, ptr, errp); |
80e555c2 PB |
450 | } |
451 | } | |
452 | ||
d7bce999 EB |
453 | static void set_string(Object *obj, Visitor *v, const char *name, |
454 | void *opaque, Error **errp) | |
80e555c2 PB |
455 | { |
456 | Property *prop = opaque; | |
828ade86 | 457 | char **ptr = qdev_get_prop_ptr(obj, prop); |
80e555c2 PB |
458 | char *str; |
459 | ||
668f62ec | 460 | if (!visit_type_str(v, name, &str, errp)) { |
80e555c2 PB |
461 | return; |
462 | } | |
ef1e1e07 | 463 | g_free(*ptr); |
80e555c2 PB |
464 | *ptr = str; |
465 | } | |
466 | ||
1b6b7d10 | 467 | const PropertyInfo qdev_prop_string = { |
85ca1202 | 468 | .name = "str", |
dd0ba250 | 469 | .release = release_string, |
80e555c2 PB |
470 | .get = get_string, |
471 | .set = set_string, | |
59419663 GH |
472 | }; |
473 | ||
55e8a154 MA |
474 | /* --- on/off/auto --- */ |
475 | ||
1b6b7d10 | 476 | const PropertyInfo qdev_prop_on_off_auto = { |
55e8a154 MA |
477 | .name = "OnOffAuto", |
478 | .description = "on/off/auto", | |
f7abe0ec | 479 | .enum_table = &OnOffAuto_lookup, |
a2974439 PMD |
480 | .get = qdev_propinfo_get_enum, |
481 | .set = qdev_propinfo_set_enum, | |
482 | .set_default_value = qdev_propinfo_set_default_value_enum, | |
55e8a154 MA |
483 | }; |
484 | ||
914e74cd RK |
485 | /* --- 32bit unsigned int 'size' type --- */ |
486 | ||
93e163e4 PMD |
487 | void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name, |
488 | void *opaque, Error **errp) | |
031ffd9a | 489 | { |
031ffd9a | 490 | Property *prop = opaque; |
828ade86 | 491 | uint32_t *ptr = qdev_get_prop_ptr(obj, prop); |
031ffd9a RK |
492 | uint64_t value = *ptr; |
493 | ||
494 | visit_type_size(v, name, &value, errp); | |
495 | } | |
496 | ||
914e74cd RK |
497 | static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque, |
498 | Error **errp) | |
499 | { | |
914e74cd | 500 | Property *prop = opaque; |
828ade86 | 501 | uint32_t *ptr = qdev_get_prop_ptr(obj, prop); |
914e74cd | 502 | uint64_t value; |
914e74cd | 503 | |
668f62ec | 504 | if (!visit_type_size(v, name, &value, errp)) { |
914e74cd RK |
505 | return; |
506 | } | |
507 | ||
508 | if (value > UINT32_MAX) { | |
509 | error_setg(errp, | |
510 | "Property %s.%s doesn't take value %" PRIu64 | |
511 | " (maximum: %u)", | |
5eb32b21 | 512 | object_get_typename(obj), name, value, UINT32_MAX); |
914e74cd RK |
513 | return; |
514 | } | |
515 | ||
516 | *ptr = value; | |
517 | } | |
518 | ||
519 | const PropertyInfo qdev_prop_size32 = { | |
520 | .name = "size", | |
93e163e4 | 521 | .get = qdev_propinfo_get_size32, |
914e74cd | 522 | .set = set_size32, |
93e163e4 | 523 | .set_default_value = qdev_propinfo_set_default_value_uint, |
914e74cd RK |
524 | }; |
525 | ||
0be6bfac PM |
526 | /* --- support for array properties --- */ |
527 | ||
528 | /* Used as an opaque for the object properties we add for each | |
529 | * array element. Note that the struct Property must be first | |
530 | * in the struct so that a pointer to this works as the opaque | |
531 | * for the underlying element's property hooks as well as for | |
532 | * our own release callback. | |
533 | */ | |
534 | typedef struct { | |
535 | struct Property prop; | |
536 | char *propname; | |
537 | ObjectPropertyRelease *release; | |
538 | } ArrayElementProperty; | |
539 | ||
540 | /* object property release callback for array element properties: | |
541 | * we call the underlying element's property release hook, and | |
542 | * then free the memory we allocated when we added the property. | |
543 | */ | |
544 | static void array_element_release(Object *obj, const char *name, void *opaque) | |
545 | { | |
546 | ArrayElementProperty *p = opaque; | |
547 | if (p->release) { | |
548 | p->release(obj, name, opaque); | |
549 | } | |
550 | g_free(p->propname); | |
551 | g_free(p); | |
552 | } | |
553 | ||
d7bce999 EB |
554 | static void set_prop_arraylen(Object *obj, Visitor *v, const char *name, |
555 | void *opaque, Error **errp) | |
0be6bfac PM |
556 | { |
557 | /* Setter for the property which defines the length of a | |
558 | * variable-sized property array. As well as actually setting the | |
559 | * array-length field in the device struct, we have to create the | |
560 | * array itself and dynamically add the corresponding properties. | |
561 | */ | |
562 | DeviceState *dev = DEVICE(obj); | |
563 | Property *prop = opaque; | |
828ade86 | 564 | uint32_t *alenptr = qdev_get_prop_ptr(obj, prop); |
0be6bfac PM |
565 | void **arrayptr = (void *)dev + prop->arrayoffset; |
566 | void *eltptr; | |
567 | const char *arrayname; | |
568 | int i; | |
569 | ||
0be6bfac PM |
570 | if (*alenptr) { |
571 | error_setg(errp, "array size property %s may not be set more than once", | |
572 | name); | |
573 | return; | |
574 | } | |
668f62ec | 575 | if (!visit_type_uint32(v, name, alenptr, errp)) { |
0be6bfac PM |
576 | return; |
577 | } | |
578 | if (!*alenptr) { | |
579 | return; | |
580 | } | |
581 | ||
582 | /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix; | |
583 | * strip it off so we can get the name of the array itself. | |
584 | */ | |
585 | assert(strncmp(name, PROP_ARRAY_LEN_PREFIX, | |
586 | strlen(PROP_ARRAY_LEN_PREFIX)) == 0); | |
587 | arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX); | |
588 | ||
589 | /* Note that it is the responsibility of the individual device's deinit | |
590 | * to free the array proper. | |
591 | */ | |
592 | *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize); | |
593 | for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) { | |
594 | char *propname = g_strdup_printf("%s[%d]", arrayname, i); | |
595 | ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1); | |
596 | arrayprop->release = prop->arrayinfo->release; | |
597 | arrayprop->propname = propname; | |
598 | arrayprop->prop.info = prop->arrayinfo; | |
599 | arrayprop->prop.name = propname; | |
600 | /* This ugly piece of pointer arithmetic sets up the offset so | |
601 | * that when the underlying get/set hooks call qdev_get_prop_ptr | |
602 | * they get the right answer despite the array element not actually | |
603 | * being inside the device struct. | |
604 | */ | |
605 | arrayprop->prop.offset = eltptr - (void *)dev; | |
828ade86 | 606 | assert(qdev_get_prop_ptr(obj, &arrayprop->prop) == eltptr); |
0be6bfac PM |
607 | object_property_add(obj, propname, |
608 | arrayprop->prop.info->name, | |
7ed854af EH |
609 | field_prop_getter(arrayprop->prop.info), |
610 | field_prop_setter(arrayprop->prop.info), | |
0be6bfac | 611 | array_element_release, |
d2623129 | 612 | arrayprop); |
0be6bfac PM |
613 | } |
614 | } | |
615 | ||
1b6b7d10 | 616 | const PropertyInfo qdev_prop_arraylen = { |
0be6bfac PM |
617 | .name = "uint32", |
618 | .get = get_uint32, | |
619 | .set = set_prop_arraylen, | |
93e163e4 | 620 | .set_default_value = qdev_propinfo_set_default_value_uint, |
0be6bfac PM |
621 | }; |
622 | ||
ee6847d1 GH |
623 | /* --- public helpers --- */ |
624 | ||
625 | static Property *qdev_prop_walk(Property *props, const char *name) | |
626 | { | |
04a2d61e | 627 | if (!props) { |
ee6847d1 | 628 | return NULL; |
04a2d61e | 629 | } |
ee6847d1 | 630 | while (props->name) { |
04a2d61e | 631 | if (strcmp(props->name, name) == 0) { |
ee6847d1 | 632 | return props; |
04a2d61e | 633 | } |
ee6847d1 GH |
634 | props++; |
635 | } | |
636 | return NULL; | |
637 | } | |
638 | ||
639 | static Property *qdev_prop_find(DeviceState *dev, const char *name) | |
640 | { | |
bce54474 | 641 | ObjectClass *class; |
ee6847d1 GH |
642 | Property *prop; |
643 | ||
644 | /* device properties */ | |
bce54474 PB |
645 | class = object_get_class(OBJECT(dev)); |
646 | do { | |
385d8f22 | 647 | prop = qdev_prop_walk(DEVICE_CLASS(class)->props_, name); |
bce54474 PB |
648 | if (prop) { |
649 | return prop; | |
650 | } | |
651 | class = object_class_get_parent(class); | |
652 | } while (class != object_class_by_name(TYPE_DEVICE)); | |
ee6847d1 GH |
653 | |
654 | return NULL; | |
655 | } | |
656 | ||
c7525b18 | 657 | void error_set_from_qdev_prop_error(Error **errp, int ret, Object *obj, |
e68c2cb7 | 658 | const char *name, const char *value) |
7db4c4e8 PB |
659 | { |
660 | switch (ret) { | |
661 | case -EEXIST: | |
f231b88d | 662 | error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use", |
e68c2cb7 | 663 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
664 | break; |
665 | default: | |
666 | case -EINVAL: | |
c6bd8c70 | 667 | error_setg(errp, QERR_PROPERTY_VALUE_BAD, |
e68c2cb7 | 668 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
669 | break; |
670 | case -ENOENT: | |
f231b88d | 671 | error_setg(errp, "Property '%s.%s' can't find value '%s'", |
e68c2cb7 | 672 | object_get_typename(obj), name, value); |
7db4c4e8 PB |
673 | break; |
674 | case 0: | |
675 | break; | |
676 | } | |
677 | } | |
678 | ||
f4594a3b IY |
679 | void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) |
680 | { | |
5325cc34 | 681 | object_property_set_bool(OBJECT(dev), name, value, &error_abort); |
f4594a3b IY |
682 | } |
683 | ||
c7cc172d JQ |
684 | void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) |
685 | { | |
5325cc34 | 686 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
c7cc172d JQ |
687 | } |
688 | ||
ee6847d1 GH |
689 | void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
690 | { | |
5325cc34 | 691 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
ee6847d1 GH |
692 | } |
693 | ||
694 | void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) | |
695 | { | |
5325cc34 | 696 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
ee6847d1 GH |
697 | } |
698 | ||
316940b0 GH |
699 | void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
700 | { | |
5325cc34 | 701 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
316940b0 GH |
702 | } |
703 | ||
5a053d1f BS |
704 | void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
705 | { | |
5325cc34 | 706 | object_property_set_int(OBJECT(dev), name, value, &error_abort); |
5a053d1f BS |
707 | } |
708 | ||
3b25597b | 709 | void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) |
cc984673 | 710 | { |
5325cc34 | 711 | object_property_set_str(OBJECT(dev), name, value, &error_abort); |
cc984673 MA |
712 | } |
713 | ||
9b170e60 | 714 | void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) |
4e4fa398 | 715 | { |
9b170e60 | 716 | Property *prop; |
9b170e60 PB |
717 | |
718 | prop = qdev_prop_find(dev, name); | |
5325cc34 | 719 | object_property_set_str(OBJECT(dev), name, |
788b305c | 720 | qapi_enum_lookup(prop->info->enum_table, value), |
5325cc34 | 721 | &error_abort); |
4e4fa398 JK |
722 | } |
723 | ||
e12ca3ce MAL |
724 | static GPtrArray *global_props(void) |
725 | { | |
726 | static GPtrArray *gp; | |
727 | ||
728 | if (!gp) { | |
729 | gp = g_ptr_array_new(); | |
730 | } | |
731 | ||
732 | return gp; | |
733 | } | |
b6b61144 | 734 | |
a404b612 | 735 | void qdev_prop_register_global(GlobalProperty *prop) |
b6b61144 | 736 | { |
e12ca3ce | 737 | g_ptr_array_add(global_props(), prop); |
b6b61144 GH |
738 | } |
739 | ||
39501275 | 740 | const GlobalProperty *qdev_find_global_prop(Object *obj, |
1bc13336 MA |
741 | const char *name) |
742 | { | |
743 | GPtrArray *props = global_props(); | |
744 | const GlobalProperty *p; | |
745 | int i; | |
746 | ||
747 | for (i = 0; i < props->len; i++) { | |
748 | p = g_ptr_array_index(props, i); | |
39501275 | 749 | if (object_dynamic_cast(obj, p->driver) |
1bc13336 MA |
750 | && !strcmp(p->property, name)) { |
751 | return p; | |
752 | } | |
753 | } | |
754 | return NULL; | |
755 | } | |
756 | ||
d828c430 | 757 | int qdev_prop_check_globals(void) |
9f9260a3 | 758 | { |
e12ca3ce | 759 | int i, ret = 0; |
9f9260a3 | 760 | |
e12ca3ce MAL |
761 | for (i = 0; i < global_props()->len; i++) { |
762 | GlobalProperty *prop; | |
b3ce84fe EH |
763 | ObjectClass *oc; |
764 | DeviceClass *dc; | |
e12ca3ce MAL |
765 | |
766 | prop = g_ptr_array_index(global_props(), i); | |
b3ce84fe EH |
767 | if (prop->used) { |
768 | continue; | |
769 | } | |
b3ce84fe EH |
770 | oc = object_class_by_name(prop->driver); |
771 | oc = object_class_dynamic_cast(oc, TYPE_DEVICE); | |
772 | if (!oc) { | |
3dc6f869 AF |
773 | warn_report("global %s.%s has invalid class name", |
774 | prop->driver, prop->property); | |
b3ce84fe EH |
775 | ret = 1; |
776 | continue; | |
777 | } | |
778 | dc = DEVICE_CLASS(oc); | |
779 | if (!dc->hotpluggable && !prop->used) { | |
3dc6f869 AF |
780 | warn_report("global %s.%s=%s not used", |
781 | prop->driver, prop->property, prop->value); | |
b3ce84fe | 782 | ret = 1; |
9f9260a3 DS |
783 | continue; |
784 | } | |
9f9260a3 DS |
785 | } |
786 | return ret; | |
787 | } | |
788 | ||
5eb6a3c5 | 789 | void qdev_prop_set_globals(DeviceState *dev) |
868d378b | 790 | { |
50545b2c MAL |
791 | object_apply_global_props(OBJECT(dev), global_props(), |
792 | dev->hotplugged ? NULL : &error_fatal); | |
868d378b AF |
793 | } |
794 | ||
e8cd45c7 VL |
795 | /* --- 64bit unsigned int 'size' type --- */ |
796 | ||
d7bce999 EB |
797 | static void get_size(Object *obj, Visitor *v, const char *name, void *opaque, |
798 | Error **errp) | |
e8cd45c7 | 799 | { |
e8cd45c7 | 800 | Property *prop = opaque; |
828ade86 | 801 | uint64_t *ptr = qdev_get_prop_ptr(obj, prop); |
e8cd45c7 | 802 | |
51e72bc1 | 803 | visit_type_size(v, name, ptr, errp); |
e8cd45c7 VL |
804 | } |
805 | ||
d7bce999 EB |
806 | static void set_size(Object *obj, Visitor *v, const char *name, void *opaque, |
807 | Error **errp) | |
e8cd45c7 | 808 | { |
e8cd45c7 | 809 | Property *prop = opaque; |
828ade86 | 810 | uint64_t *ptr = qdev_get_prop_ptr(obj, prop); |
e8cd45c7 | 811 | |
51e72bc1 | 812 | visit_type_size(v, name, ptr, errp); |
e8cd45c7 VL |
813 | } |
814 | ||
1b6b7d10 | 815 | const PropertyInfo qdev_prop_size = { |
e8cd45c7 | 816 | .name = "size", |
e8cd45c7 VL |
817 | .get = get_size, |
818 | .set = set_size, | |
93e163e4 | 819 | .set_default_value = qdev_propinfo_set_default_value_uint, |
e8cd45c7 | 820 | }; |
5b4ff3c6 FZ |
821 | |
822 | /* --- object link property --- */ | |
823 | ||
c80fab0b EH |
824 | static void create_link_property(ObjectClass *oc, const char *name, |
825 | Property *prop) | |
5b4ff3c6 | 826 | { |
c80fab0b | 827 | object_class_property_add_link(oc, name, prop->link_type, |
77b06bba MAL |
828 | prop->offset, |
829 | qdev_prop_allow_set_link_before_realize, | |
d2623129 | 830 | OBJ_PROP_LINK_STRONG); |
5b4ff3c6 FZ |
831 | } |
832 | ||
1b6b7d10 | 833 | const PropertyInfo qdev_prop_link = { |
5b4ff3c6 FZ |
834 | .name = "link", |
835 | .create = create_link_property, | |
836 | }; | |
d3fd6e73 EH |
837 | |
838 | void qdev_property_add_static(DeviceState *dev, Property *prop) | |
839 | { | |
840 | Object *obj = OBJECT(dev); | |
841 | ObjectProperty *op; | |
842 | ||
843 | assert(!prop->info->create); | |
844 | ||
845 | op = object_property_add(obj, prop->name, prop->info->name, | |
7ed854af EH |
846 | field_prop_getter(prop->info), |
847 | field_prop_setter(prop->info), | |
d3fd6e73 EH |
848 | prop->info->release, |
849 | prop); | |
850 | ||
851 | object_property_set_description(obj, prop->name, | |
852 | prop->info->description); | |
853 | ||
854 | if (prop->set_default) { | |
855 | prop->info->set_default_value(op, prop); | |
856 | if (op->init) { | |
857 | op->init(obj, op); | |
858 | } | |
859 | } | |
860 | } | |
861 | ||
23a1dae8 EH |
862 | static void qdev_class_add_property(DeviceClass *klass, const char *name, |
863 | Property *prop) | |
d3fd6e73 EH |
864 | { |
865 | ObjectClass *oc = OBJECT_CLASS(klass); | |
866 | ||
867 | if (prop->info->create) { | |
c80fab0b | 868 | prop->info->create(oc, name, prop); |
d3fd6e73 EH |
869 | } else { |
870 | ObjectProperty *op; | |
871 | ||
872 | op = object_class_property_add(oc, | |
23a1dae8 | 873 | name, prop->info->name, |
7ed854af EH |
874 | field_prop_getter(prop->info), |
875 | field_prop_setter(prop->info), | |
d3fd6e73 EH |
876 | prop->info->release, |
877 | prop); | |
878 | if (prop->set_default) { | |
879 | prop->info->set_default_value(op, prop); | |
880 | } | |
881 | } | |
23a1dae8 | 882 | object_class_property_set_description(oc, name, |
d3fd6e73 EH |
883 | prop->info->description); |
884 | } | |
885 | ||
886 | /** | |
887 | * Legacy property handling | |
888 | */ | |
889 | ||
890 | static void qdev_get_legacy_property(Object *obj, Visitor *v, | |
891 | const char *name, void *opaque, | |
892 | Error **errp) | |
893 | { | |
d3fd6e73 EH |
894 | Property *prop = opaque; |
895 | ||
896 | char buffer[1024]; | |
897 | char *ptr = buffer; | |
898 | ||
40ea00b0 | 899 | prop->info->print(obj, prop, buffer, sizeof(buffer)); |
d3fd6e73 EH |
900 | visit_type_str(v, name, &ptr, errp); |
901 | } | |
902 | ||
903 | /** | |
904 | * qdev_class_add_legacy_property: | |
905 | * @dev: Device to add the property to. | |
906 | * @prop: The qdev property definition. | |
907 | * | |
908 | * Add a legacy QOM property to @dev for qdev property @prop. | |
909 | * | |
910 | * Legacy properties are string versions of QOM properties. The format of | |
911 | * the string depends on the property type. Legacy properties are only | |
912 | * needed for "info qtree". | |
913 | * | |
914 | * Do not use this in new code! QOM Properties added through this interface | |
915 | * will be given names in the "legacy" namespace. | |
916 | */ | |
917 | static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop) | |
918 | { | |
919 | g_autofree char *name = NULL; | |
920 | ||
921 | /* Register pointer properties as legacy properties */ | |
922 | if (!prop->info->print && prop->info->get) { | |
923 | return; | |
924 | } | |
925 | ||
926 | name = g_strdup_printf("legacy-%s", prop->name); | |
927 | object_class_property_add(OBJECT_CLASS(dc), name, "str", | |
928 | prop->info->print ? qdev_get_legacy_property : prop->info->get, | |
929 | NULL, NULL, prop); | |
930 | } | |
931 | ||
932 | void device_class_set_props(DeviceClass *dc, Property *props) | |
933 | { | |
934 | Property *prop; | |
935 | ||
936 | dc->props_ = props; | |
937 | for (prop = props; prop && prop->name; prop++) { | |
938 | qdev_class_add_legacy_property(dc, prop); | |
23a1dae8 | 939 | qdev_class_add_property(dc, prop->name, prop); |
d3fd6e73 EH |
940 | } |
941 | } | |
942 | ||
943 | void qdev_alias_all_properties(DeviceState *target, Object *source) | |
944 | { | |
945 | ObjectClass *class; | |
946 | Property *prop; | |
947 | ||
948 | class = object_get_class(OBJECT(target)); | |
949 | do { | |
950 | DeviceClass *dc = DEVICE_CLASS(class); | |
951 | ||
952 | for (prop = dc->props_; prop && prop->name; prop++) { | |
953 | object_property_add_alias(source, prop->name, | |
954 | OBJECT(target), prop->name); | |
955 | } | |
956 | class = object_class_get_parent(class); | |
957 | } while (class != object_class_by_name(TYPE_DEVICE)); | |
958 | } |