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