root / hw / qdev-properties.c @ 06113719
History | View | Annotate | Download (11 kB)
1 |
#include "sysemu.h" |
---|---|
2 |
#include "qdev.h" |
3 |
|
4 |
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
5 |
{ |
6 |
void *ptr = dev;
|
7 |
ptr += prop->offset; |
8 |
return ptr;
|
9 |
} |
10 |
|
11 |
/* --- 16bit integer --- */
|
12 |
|
13 |
static int parse_uint16(DeviceState *dev, Property *prop, const char *str) |
14 |
{ |
15 |
uint16_t *ptr = qdev_get_prop_ptr(dev, prop); |
16 |
const char *fmt; |
17 |
|
18 |
/* accept both hex and decimal */
|
19 |
fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx16 : "%" PRIu16; |
20 |
if (sscanf(str, fmt, ptr) != 1) |
21 |
return -1; |
22 |
return 0; |
23 |
} |
24 |
|
25 |
static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) |
26 |
{ |
27 |
uint16_t *ptr = qdev_get_prop_ptr(dev, prop); |
28 |
return snprintf(dest, len, "%" PRIu16, *ptr); |
29 |
} |
30 |
|
31 |
PropertyInfo qdev_prop_uint16 = { |
32 |
.name = "uint16",
|
33 |
.type = PROP_TYPE_UINT16, |
34 |
.size = sizeof(uint16_t),
|
35 |
.parse = parse_uint16, |
36 |
.print = print_uint16, |
37 |
}; |
38 |
|
39 |
/* --- 32bit integer --- */
|
40 |
|
41 |
static int parse_uint32(DeviceState *dev, Property *prop, const char *str) |
42 |
{ |
43 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
44 |
const char *fmt; |
45 |
|
46 |
/* accept both hex and decimal */
|
47 |
fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx32 : "%" PRIu32; |
48 |
if (sscanf(str, fmt, ptr) != 1) |
49 |
return -1; |
50 |
return 0; |
51 |
} |
52 |
|
53 |
static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) |
54 |
{ |
55 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
56 |
return snprintf(dest, len, "%" PRIu32, *ptr); |
57 |
} |
58 |
|
59 |
PropertyInfo qdev_prop_uint32 = { |
60 |
.name = "uint32",
|
61 |
.type = PROP_TYPE_UINT32, |
62 |
.size = sizeof(uint32_t),
|
63 |
.parse = parse_uint32, |
64 |
.print = print_uint32, |
65 |
}; |
66 |
|
67 |
static int parse_int32(DeviceState *dev, Property *prop, const char *str) |
68 |
{ |
69 |
int32_t *ptr = qdev_get_prop_ptr(dev, prop); |
70 |
|
71 |
if (sscanf(str, "%" PRId32, ptr) != 1) |
72 |
return -1; |
73 |
return 0; |
74 |
} |
75 |
|
76 |
static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) |
77 |
{ |
78 |
int32_t *ptr = qdev_get_prop_ptr(dev, prop); |
79 |
return snprintf(dest, len, "%" PRId32, *ptr); |
80 |
} |
81 |
|
82 |
PropertyInfo qdev_prop_int32 = { |
83 |
.name = "int32",
|
84 |
.type = PROP_TYPE_INT32, |
85 |
.size = sizeof(int32_t),
|
86 |
.parse = parse_int32, |
87 |
.print = print_int32, |
88 |
}; |
89 |
|
90 |
/* --- 32bit hex value --- */
|
91 |
|
92 |
static int parse_hex32(DeviceState *dev, Property *prop, const char *str) |
93 |
{ |
94 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
95 |
|
96 |
if (sscanf(str, "%" PRIx32, ptr) != 1) |
97 |
return -1; |
98 |
return 0; |
99 |
} |
100 |
|
101 |
static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) |
102 |
{ |
103 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
104 |
return snprintf(dest, len, "0x%" PRIx32, *ptr); |
105 |
} |
106 |
|
107 |
PropertyInfo qdev_prop_hex32 = { |
108 |
.name = "hex32",
|
109 |
.type = PROP_TYPE_UINT32, |
110 |
.size = sizeof(uint32_t),
|
111 |
.parse = parse_hex32, |
112 |
.print = print_hex32, |
113 |
}; |
114 |
|
115 |
/* --- 64bit integer --- */
|
116 |
|
117 |
static int parse_uint64(DeviceState *dev, Property *prop, const char *str) |
118 |
{ |
119 |
uint64_t *ptr = qdev_get_prop_ptr(dev, prop); |
120 |
const char *fmt; |
121 |
|
122 |
/* accept both hex and decimal */
|
123 |
fmt = strncasecmp(str, "0x",2) == 0 ? "%" PRIx64 : "%" PRIu64; |
124 |
if (sscanf(str, fmt, ptr) != 1) |
125 |
return -1; |
126 |
return 0; |
127 |
} |
128 |
|
129 |
static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) |
130 |
{ |
131 |
uint64_t *ptr = qdev_get_prop_ptr(dev, prop); |
132 |
return snprintf(dest, len, "%" PRIu64, *ptr); |
133 |
} |
134 |
|
135 |
PropertyInfo qdev_prop_uint64 = { |
136 |
.name = "uint64",
|
137 |
.type = PROP_TYPE_UINT64, |
138 |
.size = sizeof(uint64_t),
|
139 |
.parse = parse_uint64, |
140 |
.print = print_uint64, |
141 |
}; |
142 |
|
143 |
/* --- 64bit hex value --- */
|
144 |
|
145 |
static int parse_hex64(DeviceState *dev, Property *prop, const char *str) |
146 |
{ |
147 |
uint64_t *ptr = qdev_get_prop_ptr(dev, prop); |
148 |
|
149 |
if (sscanf(str, "%" PRIx64, ptr) != 1) |
150 |
return -1; |
151 |
return 0; |
152 |
} |
153 |
|
154 |
static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) |
155 |
{ |
156 |
uint64_t *ptr = qdev_get_prop_ptr(dev, prop); |
157 |
return snprintf(dest, len, "0x%" PRIx64, *ptr); |
158 |
} |
159 |
|
160 |
PropertyInfo qdev_prop_hex64 = { |
161 |
.name = "hex64",
|
162 |
.type = PROP_TYPE_UINT64, |
163 |
.size = sizeof(uint64_t),
|
164 |
.parse = parse_hex64, |
165 |
.print = print_hex64, |
166 |
}; |
167 |
|
168 |
/* --- drive --- */
|
169 |
|
170 |
static int parse_drive(DeviceState *dev, Property *prop, const char *str) |
171 |
{ |
172 |
DriveInfo **ptr = qdev_get_prop_ptr(dev, prop); |
173 |
|
174 |
*ptr = drive_get_by_id(str); |
175 |
if (*ptr == NULL) |
176 |
return -1; |
177 |
return 0; |
178 |
} |
179 |
|
180 |
static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) |
181 |
{ |
182 |
DriveInfo **ptr = qdev_get_prop_ptr(dev, prop); |
183 |
return snprintf(dest, len, "%s", (*ptr)->id); |
184 |
} |
185 |
|
186 |
PropertyInfo qdev_prop_drive = { |
187 |
.name = "drive",
|
188 |
.type = PROP_TYPE_DRIVE, |
189 |
.size = sizeof(DriveInfo*),
|
190 |
.parse = parse_drive, |
191 |
.print = print_drive, |
192 |
}; |
193 |
|
194 |
/* --- character device --- */
|
195 |
|
196 |
static int parse_chr(DeviceState *dev, Property *prop, const char *str) |
197 |
{ |
198 |
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); |
199 |
|
200 |
*ptr = qemu_chr_find(str); |
201 |
if (*ptr == NULL) |
202 |
return -1; |
203 |
return 0; |
204 |
} |
205 |
|
206 |
static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) |
207 |
{ |
208 |
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); |
209 |
|
210 |
if (*ptr && (*ptr)->label) {
|
211 |
return snprintf(dest, len, "%s", (*ptr)->label); |
212 |
} else {
|
213 |
return snprintf(dest, len, "<null>"); |
214 |
} |
215 |
} |
216 |
|
217 |
PropertyInfo qdev_prop_chr = { |
218 |
.name = "chr",
|
219 |
.type = PROP_TYPE_CHR, |
220 |
.size = sizeof(CharDriverState*),
|
221 |
.parse = parse_chr, |
222 |
.print = print_chr, |
223 |
}; |
224 |
|
225 |
/* --- pointer --- */
|
226 |
|
227 |
static int print_ptr(DeviceState *dev, Property *prop, char *dest, size_t len) |
228 |
{ |
229 |
void **ptr = qdev_get_prop_ptr(dev, prop);
|
230 |
return snprintf(dest, len, "<%p>", *ptr); |
231 |
} |
232 |
|
233 |
PropertyInfo qdev_prop_ptr = { |
234 |
.name = "ptr",
|
235 |
.type = PROP_TYPE_PTR, |
236 |
.size = sizeof(void*), |
237 |
.print = print_ptr, |
238 |
}; |
239 |
|
240 |
/* --- mac address --- */
|
241 |
|
242 |
/*
|
243 |
* accepted syntax versions:
|
244 |
* 01:02:03:04:05:06
|
245 |
* 01-02-03-04-05-06
|
246 |
*/
|
247 |
static int parse_mac(DeviceState *dev, Property *prop, const char *str) |
248 |
{ |
249 |
uint8_t *mac = qdev_get_prop_ptr(dev, prop); |
250 |
int i, pos;
|
251 |
char *p;
|
252 |
|
253 |
for (i = 0, pos = 0; i < 6; i++, pos += 3) { |
254 |
if (!qemu_isxdigit(str[pos]))
|
255 |
return -1; |
256 |
if (!qemu_isxdigit(str[pos+1])) |
257 |
return -1; |
258 |
if (i == 5 && str[pos+2] != '\0') |
259 |
return -1; |
260 |
if (str[pos+2] != ':' && str[pos+2] != '-') |
261 |
return -1; |
262 |
mac[i] = strtol(str+pos, &p, 16);
|
263 |
} |
264 |
return 0; |
265 |
} |
266 |
|
267 |
static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) |
268 |
{ |
269 |
uint8_t *mac = qdev_get_prop_ptr(dev, prop); |
270 |
return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", |
271 |
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
272 |
} |
273 |
|
274 |
PropertyInfo qdev_prop_macaddr = { |
275 |
.name = "mac-addr",
|
276 |
.type = PROP_TYPE_MACADDR, |
277 |
.size = 6,
|
278 |
.parse = parse_mac, |
279 |
.print = print_mac, |
280 |
}; |
281 |
|
282 |
/* --- pci address --- */
|
283 |
|
284 |
/*
|
285 |
* bus-local address, i.e. "$slot" or "$slot.$fn"
|
286 |
*/
|
287 |
static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) |
288 |
{ |
289 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
290 |
unsigned int slot, fn, n; |
291 |
|
292 |
if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { |
293 |
fn = 0;
|
294 |
if (sscanf(str, "%x%n", &slot, &n) != 1) { |
295 |
return -1; |
296 |
} |
297 |
} |
298 |
if (str[n] != '\0') |
299 |
return -1; |
300 |
if (fn > 7) |
301 |
return -1; |
302 |
*ptr = slot << 3 | fn;
|
303 |
return 0; |
304 |
} |
305 |
|
306 |
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) |
307 |
{ |
308 |
uint32_t *ptr = qdev_get_prop_ptr(dev, prop); |
309 |
|
310 |
if (*ptr == -1) { |
311 |
return snprintf(dest, len, "<unset>"); |
312 |
} else {
|
313 |
return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); |
314 |
} |
315 |
} |
316 |
|
317 |
PropertyInfo qdev_prop_pci_devfn = { |
318 |
.name = "pci-devfn",
|
319 |
.type = PROP_TYPE_UINT32, |
320 |
.size = sizeof(uint32_t),
|
321 |
.parse = parse_pci_devfn, |
322 |
.print = print_pci_devfn, |
323 |
}; |
324 |
|
325 |
/* --- public helpers --- */
|
326 |
|
327 |
static Property *qdev_prop_walk(Property *props, const char *name) |
328 |
{ |
329 |
if (!props)
|
330 |
return NULL; |
331 |
while (props->name) {
|
332 |
if (strcmp(props->name, name) == 0) |
333 |
return props;
|
334 |
props++; |
335 |
} |
336 |
return NULL; |
337 |
} |
338 |
|
339 |
static Property *qdev_prop_find(DeviceState *dev, const char *name) |
340 |
{ |
341 |
Property *prop; |
342 |
|
343 |
/* device properties */
|
344 |
prop = qdev_prop_walk(dev->info->props, name); |
345 |
if (prop)
|
346 |
return prop;
|
347 |
|
348 |
/* bus properties */
|
349 |
prop = qdev_prop_walk(dev->parent_bus->info->props, name); |
350 |
if (prop)
|
351 |
return prop;
|
352 |
|
353 |
return NULL; |
354 |
} |
355 |
|
356 |
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) |
357 |
{ |
358 |
Property *prop; |
359 |
|
360 |
prop = qdev_prop_find(dev, name); |
361 |
if (!prop) {
|
362 |
fprintf(stderr, "property \"%s.%s\" not found\n",
|
363 |
dev->info->name, name); |
364 |
return -1; |
365 |
} |
366 |
if (!prop->info->parse) {
|
367 |
fprintf(stderr, "property \"%s.%s\" has no parser\n",
|
368 |
dev->info->name, name); |
369 |
return -1; |
370 |
} |
371 |
return prop->info->parse(dev, prop, value);
|
372 |
} |
373 |
|
374 |
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) |
375 |
{ |
376 |
Property *prop; |
377 |
void *dst;
|
378 |
|
379 |
prop = qdev_prop_find(dev, name); |
380 |
if (!prop) {
|
381 |
fprintf(stderr, "%s: property \"%s.%s\" not found\n",
|
382 |
__FUNCTION__, dev->info->name, name); |
383 |
abort(); |
384 |
} |
385 |
if (prop->info->type != type) {
|
386 |
fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
|
387 |
__FUNCTION__, dev->info->name, name); |
388 |
abort(); |
389 |
} |
390 |
dst = qdev_get_prop_ptr(dev, prop); |
391 |
memcpy(dst, src, prop->info->size); |
392 |
} |
393 |
|
394 |
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) |
395 |
{ |
396 |
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); |
397 |
} |
398 |
|
399 |
void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) |
400 |
{ |
401 |
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); |
402 |
} |
403 |
|
404 |
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) |
405 |
{ |
406 |
qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); |
407 |
} |
408 |
|
409 |
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) |
410 |
{ |
411 |
qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); |
412 |
} |
413 |
|
414 |
void qdev_prop_set_drive(DeviceState *dev, const char *name, DriveInfo *value) |
415 |
{ |
416 |
qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); |
417 |
} |
418 |
|
419 |
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) |
420 |
{ |
421 |
qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); |
422 |
} |
423 |
|
424 |
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) |
425 |
{ |
426 |
qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); |
427 |
} |
428 |
|
429 |
void qdev_prop_set_defaults(DeviceState *dev, Property *props)
|
430 |
{ |
431 |
char *dst;
|
432 |
|
433 |
if (!props)
|
434 |
return;
|
435 |
while (props->name) {
|
436 |
if (props->defval) {
|
437 |
dst = qdev_get_prop_ptr(dev, props); |
438 |
memcpy(dst, props->defval, props->info->size); |
439 |
} |
440 |
props++; |
441 |
} |
442 |
} |
443 |
|
444 |
static CompatProperty *compat_props;
|
445 |
|
446 |
void qdev_prop_register_compat(CompatProperty *props)
|
447 |
{ |
448 |
compat_props = props; |
449 |
} |
450 |
|
451 |
void qdev_prop_set_compat(DeviceState *dev)
|
452 |
{ |
453 |
CompatProperty *prop; |
454 |
|
455 |
if (!compat_props) {
|
456 |
return;
|
457 |
} |
458 |
for (prop = compat_props; prop->driver != NULL; prop++) { |
459 |
if (strcmp(dev->info->name, prop->driver) != 0) { |
460 |
continue;
|
461 |
} |
462 |
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { |
463 |
abort(); |
464 |
} |
465 |
} |
466 |
} |