]> Git Repo - qemu.git/blob - hw/qdev.c
qdev: allow reusing get/set for legacy property
[qemu.git] / hw / qdev.c
1 /*
2  *  Dynamic device configuration and creation.
3  *
4  *  Copyright (c) 2009 CodeSourcery
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* The theory here is that it should be possible to create a machine without
21    knowledge of specific devices.  Historically board init routines have
22    passed a bunch of arguments to each device, requiring the board know
23    exactly which device it is dealing with.  This file provides an abstract
24    API for device configuration and initialization.  Devices will generally
25    inherit from a particular bus (e.g. PCI or I2C) rather than
26    this API directly.  */
27
28 #include "net.h"
29 #include "qdev.h"
30 #include "sysemu.h"
31
32 int qdev_hotplug = 0;
33 static bool qdev_hot_added = false;
34 static bool qdev_hot_removed = false;
35
36 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
37 static BusState *main_system_bus;
38 static void main_system_bus_create(void);
39
40 /* Register a new device type.  */
41 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
42 {
43     DeviceClass *dc = DEVICE_GET_CLASS(dev);
44     return dc->vmsd;
45 }
46
47 BusInfo *qdev_get_bus_info(DeviceState *dev)
48 {
49     DeviceClass *dc = DEVICE_GET_CLASS(dev);
50     return dc->bus_info;
51 }
52
53 Property *qdev_get_props(DeviceState *dev)
54 {
55     DeviceClass *dc = DEVICE_GET_CLASS(dev);
56     return dc->props;
57 }
58
59 const char *qdev_fw_name(DeviceState *dev)
60 {
61     DeviceClass *dc = DEVICE_GET_CLASS(dev);
62
63     if (dc->fw_name) {
64         return dc->fw_name;
65     }
66
67     return object_get_typename(OBJECT(dev));
68 }
69
70 bool qdev_exists(const char *name)
71 {
72     return !!object_class_by_name(name);
73 }
74
75 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
76                                      Error **errp);
77
78 void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
79 {
80     Property *prop;
81
82     if (qdev_hotplug) {
83         assert(bus->allow_hotplug);
84     }
85
86     dev->parent_bus = bus;
87     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
88
89     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
90     for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
91         qdev_property_add_legacy(dev, prop, NULL);
92         qdev_property_add_static(dev, prop, NULL);
93     }
94 }
95
96 /* Create a new device.  This only initializes the device state structure
97    and allows properties to be set.  qdev_init should be called to
98    initialize the actual device emulation.  */
99 DeviceState *qdev_create(BusState *bus, const char *name)
100 {
101     DeviceState *dev;
102
103     dev = qdev_try_create(bus, name);
104     if (!dev) {
105         if (bus) {
106             hw_error("Unknown device '%s' for bus '%s'\n", name,
107                      bus->info->name);
108         } else {
109             hw_error("Unknown device '%s' for default sysbus\n", name);
110         }
111     }
112
113     return dev;
114 }
115
116 DeviceState *qdev_try_create(BusState *bus, const char *name)
117 {
118     DeviceState *dev;
119
120     dev = DEVICE(object_new(name));
121     if (!dev) {
122         return NULL;
123     }
124
125     if (!bus) {
126         bus = sysbus_get_default();
127     }
128
129     qdev_set_parent_bus(dev, bus);
130     qdev_prop_set_globals(dev);
131
132     return dev;
133 }
134
135 /* Initialize a device.  Device properties should be set before calling
136    this function.  IRQs and MMIO regions should be connected/mapped after
137    calling this function.
138    On failure, destroy the device and return negative value.
139    Return 0 on success.  */
140 int qdev_init(DeviceState *dev)
141 {
142     DeviceClass *dc = DEVICE_GET_CLASS(dev);
143     int rc;
144
145     assert(dev->state == DEV_STATE_CREATED);
146
147     rc = dc->init(dev);
148     if (rc < 0) {
149         qdev_free(dev);
150         return rc;
151     }
152     if (qdev_get_vmsd(dev)) {
153         vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
154                                        dev->instance_id_alias,
155                                        dev->alias_required_for_version);
156     }
157     dev->state = DEV_STATE_INITIALIZED;
158     if (dev->hotplugged) {
159         device_reset(dev);
160     }
161     return 0;
162 }
163
164 void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
165                                  int required_for_version)
166 {
167     assert(dev->state == DEV_STATE_CREATED);
168     dev->instance_id_alias = alias_id;
169     dev->alias_required_for_version = required_for_version;
170 }
171
172 int qdev_unplug(DeviceState *dev)
173 {
174     DeviceClass *dc = DEVICE_GET_CLASS(dev);
175
176     if (!dev->parent_bus->allow_hotplug) {
177         qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
178         return -1;
179     }
180     assert(dc->unplug != NULL);
181
182     qdev_hot_removed = true;
183
184     return dc->unplug(dev);
185 }
186
187 static int qdev_reset_one(DeviceState *dev, void *opaque)
188 {
189     device_reset(dev);
190
191     return 0;
192 }
193
194 BusState *sysbus_get_default(void)
195 {
196     if (!main_system_bus) {
197         main_system_bus_create();
198     }
199     return main_system_bus;
200 }
201
202 static int qbus_reset_one(BusState *bus, void *opaque)
203 {
204     if (bus->info->reset) {
205         return bus->info->reset(bus);
206     }
207     return 0;
208 }
209
210 void qdev_reset_all(DeviceState *dev)
211 {
212     qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
213 }
214
215 void qbus_reset_all_fn(void *opaque)
216 {
217     BusState *bus = opaque;
218     qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
219 }
220
221 /* can be used as ->unplug() callback for the simple cases */
222 int qdev_simple_unplug_cb(DeviceState *dev)
223 {
224     /* just zap it */
225     object_unparent(OBJECT(dev));
226     qdev_free(dev);
227     return 0;
228 }
229
230
231 /* Like qdev_init(), but terminate program via error_report() instead of
232    returning an error value.  This is okay during machine creation.
233    Don't use for hotplug, because there callers need to recover from
234    failure.  Exception: if you know the device's init() callback can't
235    fail, then qdev_init_nofail() can't fail either, and is therefore
236    usable even then.  But relying on the device implementation that
237    way is somewhat unclean, and best avoided.  */
238 void qdev_init_nofail(DeviceState *dev)
239 {
240     if (qdev_init(dev) < 0) {
241         error_report("Initialization of device %s failed",
242                      object_get_typename(OBJECT(dev)));
243         exit(1);
244     }
245 }
246
247 /* Unlink device from bus and free the structure.  */
248 void qdev_free(DeviceState *dev)
249 {
250     object_delete(OBJECT(dev));
251 }
252
253 void qdev_machine_creation_done(void)
254 {
255     /*
256      * ok, initial machine setup is done, starting from now we can
257      * only create hotpluggable devices
258      */
259     qdev_hotplug = 1;
260 }
261
262 bool qdev_machine_modified(void)
263 {
264     return qdev_hot_added || qdev_hot_removed;
265 }
266
267 BusState *qdev_get_parent_bus(DeviceState *dev)
268 {
269     return dev->parent_bus;
270 }
271
272 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
273 {
274     assert(dev->num_gpio_in == 0);
275     dev->num_gpio_in = n;
276     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
277 }
278
279 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
280 {
281     assert(dev->num_gpio_out == 0);
282     dev->num_gpio_out = n;
283     dev->gpio_out = pins;
284 }
285
286 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
287 {
288     assert(n >= 0 && n < dev->num_gpio_in);
289     return dev->gpio_in[n];
290 }
291
292 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
293 {
294     assert(n >= 0 && n < dev->num_gpio_out);
295     dev->gpio_out[n] = pin;
296 }
297
298 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
299 {
300     qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
301     if (nd->vlan)
302         qdev_prop_set_vlan(dev, "vlan", nd->vlan);
303     if (nd->netdev)
304         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
305     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
306         qdev_prop_exists(dev, "vectors")) {
307         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
308     }
309     nd->instantiated = 1;
310 }
311
312 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
313 {
314     BusState *bus;
315
316     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
317         if (strcmp(name, bus->name) == 0) {
318             return bus;
319         }
320     }
321     return NULL;
322 }
323
324 int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
325                        qbus_walkerfn *busfn, void *opaque)
326 {
327     DeviceState *dev;
328     int err;
329
330     if (busfn) {
331         err = busfn(bus, opaque);
332         if (err) {
333             return err;
334         }
335     }
336
337     QTAILQ_FOREACH(dev, &bus->children, sibling) {
338         err = qdev_walk_children(dev, devfn, busfn, opaque);
339         if (err < 0) {
340             return err;
341         }
342     }
343
344     return 0;
345 }
346
347 int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
348                        qbus_walkerfn *busfn, void *opaque)
349 {
350     BusState *bus;
351     int err;
352
353     if (devfn) {
354         err = devfn(dev, opaque);
355         if (err) {
356             return err;
357         }
358     }
359
360     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
361         err = qbus_walk_children(bus, devfn, busfn, opaque);
362         if (err < 0) {
363             return err;
364         }
365     }
366
367     return 0;
368 }
369
370 DeviceState *qdev_find_recursive(BusState *bus, const char *id)
371 {
372     DeviceState *dev, *ret;
373     BusState *child;
374
375     QTAILQ_FOREACH(dev, &bus->children, sibling) {
376         if (dev->id && strcmp(dev->id, id) == 0)
377             return dev;
378         QLIST_FOREACH(child, &dev->child_bus, sibling) {
379             ret = qdev_find_recursive(child, id);
380             if (ret) {
381                 return ret;
382             }
383         }
384     }
385     return NULL;
386 }
387
388 void qbus_create_inplace(BusState *bus, BusInfo *info,
389                          DeviceState *parent, const char *name)
390 {
391     char *buf;
392     int i,len;
393
394     bus->info = info;
395     bus->parent = parent;
396
397     if (name) {
398         /* use supplied name */
399         bus->name = g_strdup(name);
400     } else if (parent && parent->id) {
401         /* parent device has id -> use it for bus name */
402         len = strlen(parent->id) + 16;
403         buf = g_malloc(len);
404         snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
405         bus->name = buf;
406     } else {
407         /* no id -> use lowercase bus type for bus name */
408         len = strlen(info->name) + 16;
409         buf = g_malloc(len);
410         len = snprintf(buf, len, "%s.%d", info->name,
411                        parent ? parent->num_child_bus : 0);
412         for (i = 0; i < len; i++)
413             buf[i] = qemu_tolower(buf[i]);
414         bus->name = buf;
415     }
416
417     QTAILQ_INIT(&bus->children);
418     if (parent) {
419         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
420         parent->num_child_bus++;
421     } else if (bus != main_system_bus) {
422         /* TODO: once all bus devices are qdevified,
423            only reset handler for main_system_bus should be registered here. */
424         qemu_register_reset(qbus_reset_all_fn, bus);
425     }
426 }
427
428 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
429 {
430     BusState *bus;
431
432     bus = g_malloc0(info->size);
433     bus->qdev_allocated = 1;
434     qbus_create_inplace(bus, info, parent, name);
435     return bus;
436 }
437
438 static void main_system_bus_create(void)
439 {
440     /* assign main_system_bus before qbus_create_inplace()
441      * in order to make "if (bus != main_system_bus)" work */
442     main_system_bus = g_malloc0(system_bus_info.size);
443     main_system_bus->qdev_allocated = 1;
444     qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
445                         "main-system-bus");
446 }
447
448 void qbus_free(BusState *bus)
449 {
450     DeviceState *dev;
451
452     while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
453         qdev_free(dev);
454     }
455     if (bus->parent) {
456         QLIST_REMOVE(bus, sibling);
457         bus->parent->num_child_bus--;
458     } else {
459         assert(bus != main_system_bus); /* main_system_bus is never freed */
460         qemu_unregister_reset(qbus_reset_all_fn, bus);
461     }
462     g_free((void*)bus->name);
463     if (bus->qdev_allocated) {
464         g_free(bus);
465     }
466 }
467
468 static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
469 {
470     int l = 0;
471
472     if (dev && dev->parent_bus) {
473         char *d;
474         l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
475         if (dev->parent_bus->info->get_fw_dev_path) {
476             d = dev->parent_bus->info->get_fw_dev_path(dev);
477             l += snprintf(p + l, size - l, "%s", d);
478             g_free(d);
479         } else {
480             l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
481         }
482     }
483     l += snprintf(p + l , size - l, "/");
484
485     return l;
486 }
487
488 char* qdev_get_fw_dev_path(DeviceState *dev)
489 {
490     char path[128];
491     int l;
492
493     l = qdev_get_fw_dev_path_helper(dev, path, 128);
494
495     path[l-1] = '\0';
496
497     return strdup(path);
498 }
499
500 static char *qdev_get_type(Object *obj, Error **errp)
501 {
502     return g_strdup(object_get_typename(obj));
503 }
504
505 /**
506  * Legacy property handling
507  */
508
509 static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
510                                      const char *name, Error **errp)
511 {
512     DeviceState *dev = DEVICE(obj);
513     Property *prop = opaque;
514
515     char buffer[1024];
516     char *ptr = buffer;
517
518     prop->info->print(dev, prop, buffer, sizeof(buffer));
519     visit_type_str(v, &ptr, name, errp);
520 }
521
522 static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
523                                      const char *name, Error **errp)
524 {
525     DeviceState *dev = DEVICE(obj);
526     Property *prop = opaque;
527     Error *local_err = NULL;
528     char *ptr = NULL;
529     int ret;
530
531     if (dev->state != DEV_STATE_CREATED) {
532         error_set(errp, QERR_PERMISSION_DENIED);
533         return;
534     }
535
536     visit_type_str(v, &ptr, name, &local_err);
537     if (local_err) {
538         error_propagate(errp, local_err);
539         return;
540     }
541
542     ret = prop->info->parse(dev, prop, ptr);
543     error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
544     g_free(ptr);
545 }
546
547 /**
548  * @qdev_add_legacy_property - adds a legacy property
549  *
550  * Do not use this is new code!  Properties added through this interface will
551  * be given names and types in the "legacy" namespace.
552  *
553  * Legacy properties are string versions of other OOM properties.  The format
554  * of the string depends on the property type.
555  */
556 void qdev_property_add_legacy(DeviceState *dev, Property *prop,
557                               Error **errp)
558 {
559     gchar *name, *type;
560
561     if (!prop->info->print && !prop->info->parse) {
562         return;
563     }
564     name = g_strdup_printf("legacy-%s", prop->name);
565     type = g_strdup_printf("legacy<%s>",
566                            prop->info->legacy_name ?: prop->info->name);
567
568     object_property_add(OBJECT(dev), name, type,
569                         prop->info->print ? qdev_get_legacy_property : prop->info->get,
570                         prop->info->parse ? qdev_set_legacy_property : prop->info->set,
571                         NULL,
572                         prop, errp);
573
574     g_free(type);
575     g_free(name);
576 }
577
578 /**
579  * @qdev_property_add_static - add a @Property to a device.
580  *
581  * Static properties access data in a struct.  The actual type of the
582  * property and the field depends on the property type.
583  */
584 void qdev_property_add_static(DeviceState *dev, Property *prop,
585                               Error **errp)
586 {
587     /*
588      * TODO qdev_prop_ptr does not have getters or setters.  It must
589      * go now that it can be replaced with links.  The test should be
590      * removed along with it: all static properties are read/write.
591      */
592     if (!prop->info->get && !prop->info->set) {
593         return;
594     }
595
596     object_property_add(OBJECT(dev), prop->name, prop->info->name,
597                         prop->info->get, prop->info->set,
598                         NULL,
599                         prop, errp);
600 }
601
602 static void device_initfn(Object *obj)
603 {
604     DeviceState *dev = DEVICE(obj);
605     Property *prop;
606
607     if (qdev_hotplug) {
608         dev->hotplugged = 1;
609         qdev_hot_added = true;
610     }
611
612     dev->instance_id_alias = -1;
613     dev->state = DEV_STATE_CREATED;
614
615     qdev_prop_set_defaults(dev, qdev_get_props(dev));
616     for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
617         qdev_property_add_legacy(dev, prop, NULL);
618         qdev_property_add_static(dev, prop, NULL);
619     }
620
621     object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
622 }
623
624 /* Unlink device from bus and free the structure.  */
625 static void device_finalize(Object *obj)
626 {
627     DeviceState *dev = DEVICE(obj);
628     BusState *bus;
629     Property *prop;
630     DeviceClass *dc = DEVICE_GET_CLASS(dev);
631
632     if (dev->state == DEV_STATE_INITIALIZED) {
633         while (dev->num_child_bus) {
634             bus = QLIST_FIRST(&dev->child_bus);
635             qbus_free(bus);
636         }
637         if (qdev_get_vmsd(dev)) {
638             vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
639         }
640         if (dc->exit) {
641             dc->exit(dev);
642         }
643         if (dev->opts) {
644             qemu_opts_del(dev->opts);
645         }
646     }
647     QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
648     for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
649         if (prop->info->free) {
650             prop->info->free(dev, prop);
651         }
652     }
653 }
654
655 void device_reset(DeviceState *dev)
656 {
657     DeviceClass *klass = DEVICE_GET_CLASS(dev);
658
659     if (klass->reset) {
660         klass->reset(dev);
661     }
662 }
663
664 static TypeInfo device_type_info = {
665     .name = TYPE_DEVICE,
666     .parent = TYPE_OBJECT,
667     .instance_size = sizeof(DeviceState),
668     .instance_init = device_initfn,
669     .instance_finalize = device_finalize,
670     .abstract = true,
671     .class_size = sizeof(DeviceClass),
672 };
673
674 static void init_qdev(void)
675 {
676     type_register_static(&device_type_info);
677 }
678
679 device_init(init_qdev);
This page took 0.062435 seconds and 4 git commands to generate.