]>
Commit | Line | Data |
---|---|---|
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.1 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 "qemu/osdep.h" | |
29 | #include "qapi/error.h" | |
30 | #include "qapi/qapi-events-qdev.h" | |
31 | #include "qobject/qdict.h" | |
32 | #include "qapi/visitor.h" | |
33 | #include "qemu/error-report.h" | |
34 | #include "qemu/option.h" | |
35 | #include "hw/irq.h" | |
36 | #include "hw/qdev-properties.h" | |
37 | #include "hw/boards.h" | |
38 | #include "hw/sysbus.h" | |
39 | #include "hw/qdev-clock.h" | |
40 | #include "migration/vmstate.h" | |
41 | #include "trace.h" | |
42 | ||
43 | static bool qdev_hot_added = false; | |
44 | bool qdev_hot_removed = false; | |
45 | ||
46 | const VMStateDescription *qdev_get_vmsd(DeviceState *dev) | |
47 | { | |
48 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
49 | return dc->vmsd; | |
50 | } | |
51 | ||
52 | static void bus_free_bus_child(BusChild *kid) | |
53 | { | |
54 | object_unref(OBJECT(kid->child)); | |
55 | g_free(kid); | |
56 | } | |
57 | ||
58 | static void bus_remove_child(BusState *bus, DeviceState *child) | |
59 | { | |
60 | BusChild *kid; | |
61 | ||
62 | QTAILQ_FOREACH(kid, &bus->children, sibling) { | |
63 | if (kid->child == child) { | |
64 | char name[32]; | |
65 | ||
66 | snprintf(name, sizeof(name), "child[%d]", kid->index); | |
67 | QTAILQ_REMOVE_RCU(&bus->children, kid, sibling); | |
68 | ||
69 | bus->num_children--; | |
70 | ||
71 | /* This gives back ownership of kid->child back to us. */ | |
72 | object_property_del(OBJECT(bus), name); | |
73 | ||
74 | /* free the bus kid, when it is safe to do so*/ | |
75 | call_rcu(kid, bus_free_bus_child, rcu); | |
76 | break; | |
77 | } | |
78 | } | |
79 | } | |
80 | ||
81 | static void bus_add_child(BusState *bus, DeviceState *child) | |
82 | { | |
83 | char name[32]; | |
84 | BusChild *kid = g_malloc0(sizeof(*kid)); | |
85 | ||
86 | bus->num_children++; | |
87 | kid->index = bus->max_index++; | |
88 | kid->child = child; | |
89 | object_ref(OBJECT(kid->child)); | |
90 | ||
91 | QTAILQ_INSERT_HEAD_RCU(&bus->children, kid, sibling); | |
92 | ||
93 | /* This transfers ownership of kid->child to the property. */ | |
94 | snprintf(name, sizeof(name), "child[%d]", kid->index); | |
95 | object_property_add_link(OBJECT(bus), name, | |
96 | object_get_typename(OBJECT(child)), | |
97 | (Object **)&kid->child, | |
98 | NULL, /* read-only property */ | |
99 | 0); | |
100 | } | |
101 | ||
102 | static bool bus_check_address(BusState *bus, DeviceState *child, Error **errp) | |
103 | { | |
104 | BusClass *bc = BUS_GET_CLASS(bus); | |
105 | return !bc->check_address || bc->check_address(bus, child, errp); | |
106 | } | |
107 | ||
108 | bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp) | |
109 | { | |
110 | BusState *old_parent_bus = dev->parent_bus; | |
111 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
112 | ||
113 | assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)); | |
114 | ||
115 | if (!bus_check_address(bus, dev, errp)) { | |
116 | return false; | |
117 | } | |
118 | ||
119 | if (old_parent_bus) { | |
120 | trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)), | |
121 | old_parent_bus, object_get_typename(OBJECT(old_parent_bus)), | |
122 | OBJECT(bus), object_get_typename(OBJECT(bus))); | |
123 | /* | |
124 | * Keep a reference to the device while it's not plugged into | |
125 | * any bus, to avoid it potentially evaporating when it is | |
126 | * dereffed in bus_remove_child(). | |
127 | * Also keep the ref of the parent bus until the end, so that | |
128 | * we can safely call resettable_change_parent() below. | |
129 | */ | |
130 | object_ref(OBJECT(dev)); | |
131 | bus_remove_child(dev->parent_bus, dev); | |
132 | } | |
133 | dev->parent_bus = bus; | |
134 | object_ref(OBJECT(bus)); | |
135 | bus_add_child(bus, dev); | |
136 | if (dev->realized) { | |
137 | resettable_change_parent(OBJECT(dev), OBJECT(bus), | |
138 | OBJECT(old_parent_bus)); | |
139 | } | |
140 | if (old_parent_bus) { | |
141 | object_unref(OBJECT(old_parent_bus)); | |
142 | object_unref(OBJECT(dev)); | |
143 | } | |
144 | return true; | |
145 | } | |
146 | ||
147 | DeviceState *qdev_new(const char *name) | |
148 | { | |
149 | return DEVICE(object_new(name)); | |
150 | } | |
151 | ||
152 | DeviceState *qdev_try_new(const char *name) | |
153 | { | |
154 | ObjectClass *oc = module_object_class_by_name(name); | |
155 | if (!oc) { | |
156 | return NULL; | |
157 | } | |
158 | return DEVICE(object_new_with_class(oc)); | |
159 | } | |
160 | ||
161 | static QTAILQ_HEAD(, DeviceListener) device_listeners | |
162 | = QTAILQ_HEAD_INITIALIZER(device_listeners); | |
163 | ||
164 | enum ListenerDirection { Forward, Reverse }; | |
165 | ||
166 | #define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \ | |
167 | do { \ | |
168 | DeviceListener *_listener; \ | |
169 | \ | |
170 | switch (_direction) { \ | |
171 | case Forward: \ | |
172 | QTAILQ_FOREACH(_listener, &device_listeners, link) { \ | |
173 | if (_listener->_callback) { \ | |
174 | _listener->_callback(_listener, ##_args); \ | |
175 | } \ | |
176 | } \ | |
177 | break; \ | |
178 | case Reverse: \ | |
179 | QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \ | |
180 | link) { \ | |
181 | if (_listener->_callback) { \ | |
182 | _listener->_callback(_listener, ##_args); \ | |
183 | } \ | |
184 | } \ | |
185 | break; \ | |
186 | default: \ | |
187 | abort(); \ | |
188 | } \ | |
189 | } while (0) | |
190 | ||
191 | static int device_listener_add(DeviceState *dev, void *opaque) | |
192 | { | |
193 | DEVICE_LISTENER_CALL(realize, Forward, dev); | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | void device_listener_register(DeviceListener *listener) | |
199 | { | |
200 | QTAILQ_INSERT_TAIL(&device_listeners, listener, link); | |
201 | ||
202 | qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add, | |
203 | NULL, NULL); | |
204 | } | |
205 | ||
206 | void device_listener_unregister(DeviceListener *listener) | |
207 | { | |
208 | QTAILQ_REMOVE(&device_listeners, listener, link); | |
209 | } | |
210 | ||
211 | bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp) | |
212 | { | |
213 | ERRP_GUARD(); | |
214 | DeviceListener *listener; | |
215 | ||
216 | QTAILQ_FOREACH(listener, &device_listeners, link) { | |
217 | if (listener->hide_device) { | |
218 | if (listener->hide_device(listener, opts, from_json, errp)) { | |
219 | return true; | |
220 | } else if (*errp) { | |
221 | return false; | |
222 | } | |
223 | } | |
224 | } | |
225 | ||
226 | return false; | |
227 | } | |
228 | ||
229 | void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, | |
230 | int required_for_version) | |
231 | { | |
232 | assert(!dev->realized); | |
233 | dev->instance_id_alias = alias_id; | |
234 | dev->alias_required_for_version = required_for_version; | |
235 | } | |
236 | ||
237 | void device_cold_reset(DeviceState *dev) | |
238 | { | |
239 | resettable_reset(OBJECT(dev), RESET_TYPE_COLD); | |
240 | } | |
241 | ||
242 | bool device_is_in_reset(DeviceState *dev) | |
243 | { | |
244 | return resettable_is_in_reset(OBJECT(dev)); | |
245 | } | |
246 | ||
247 | static ResettableState *device_get_reset_state(Object *obj) | |
248 | { | |
249 | DeviceState *dev = DEVICE(obj); | |
250 | return &dev->reset; | |
251 | } | |
252 | ||
253 | static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, | |
254 | void *opaque, ResetType type) | |
255 | { | |
256 | DeviceState *dev = DEVICE(obj); | |
257 | BusState *bus; | |
258 | ||
259 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
260 | cb(OBJECT(bus), opaque, type); | |
261 | } | |
262 | } | |
263 | ||
264 | bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) | |
265 | { | |
266 | assert(!dev->realized && !dev->parent_bus); | |
267 | ||
268 | if (bus) { | |
269 | if (!qdev_set_parent_bus(dev, bus, errp)) { | |
270 | return false; | |
271 | } | |
272 | } else { | |
273 | assert(!DEVICE_GET_CLASS(dev)->bus_type); | |
274 | } | |
275 | ||
276 | return object_property_set_bool(OBJECT(dev), "realized", true, errp); | |
277 | } | |
278 | ||
279 | bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) | |
280 | { | |
281 | bool ret; | |
282 | ||
283 | ret = qdev_realize(dev, bus, errp); | |
284 | object_unref(OBJECT(dev)); | |
285 | return ret; | |
286 | } | |
287 | ||
288 | void qdev_unrealize(DeviceState *dev) | |
289 | { | |
290 | object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); | |
291 | } | |
292 | ||
293 | static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) | |
294 | { | |
295 | DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); | |
296 | DeviceClass *dc; | |
297 | ||
298 | if (dev) { | |
299 | dc = DEVICE_GET_CLASS(dev); | |
300 | assert(dev->realized); | |
301 | assert(dev->parent_bus || !dc->bus_type); | |
302 | } | |
303 | return 0; | |
304 | } | |
305 | ||
306 | void qdev_assert_realized_properly(void) | |
307 | { | |
308 | object_child_foreach_recursive(object_get_root(), | |
309 | qdev_assert_realized_properly_cb, NULL); | |
310 | } | |
311 | ||
312 | bool qdev_machine_modified(void) | |
313 | { | |
314 | return qdev_hot_added || qdev_hot_removed; | |
315 | } | |
316 | ||
317 | BusState *qdev_get_parent_bus(const DeviceState *dev) | |
318 | { | |
319 | return dev->parent_bus; | |
320 | } | |
321 | ||
322 | BusState *qdev_get_child_bus(DeviceState *dev, const char *name) | |
323 | { | |
324 | BusState *bus; | |
325 | Object *child = object_resolve_path_component(OBJECT(dev), name); | |
326 | ||
327 | bus = (BusState *)object_dynamic_cast(child, TYPE_BUS); | |
328 | if (bus) { | |
329 | return bus; | |
330 | } | |
331 | ||
332 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
333 | if (strcmp(name, bus->name) == 0) { | |
334 | return bus; | |
335 | } | |
336 | } | |
337 | return NULL; | |
338 | } | |
339 | ||
340 | int qdev_walk_children(DeviceState *dev, | |
341 | qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, | |
342 | qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, | |
343 | void *opaque) | |
344 | { | |
345 | BusState *bus; | |
346 | int err; | |
347 | ||
348 | if (pre_devfn) { | |
349 | err = pre_devfn(dev, opaque); | |
350 | if (err) { | |
351 | return err; | |
352 | } | |
353 | } | |
354 | ||
355 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
356 | err = qbus_walk_children(bus, pre_devfn, pre_busfn, | |
357 | post_devfn, post_busfn, opaque); | |
358 | if (err < 0) { | |
359 | return err; | |
360 | } | |
361 | } | |
362 | ||
363 | if (post_devfn) { | |
364 | err = post_devfn(dev, opaque); | |
365 | if (err) { | |
366 | return err; | |
367 | } | |
368 | } | |
369 | ||
370 | return 0; | |
371 | } | |
372 | ||
373 | DeviceState *qdev_find_recursive(BusState *bus, const char *id) | |
374 | { | |
375 | BusChild *kid; | |
376 | DeviceState *ret; | |
377 | BusState *child; | |
378 | ||
379 | WITH_RCU_READ_LOCK_GUARD() { | |
380 | QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { | |
381 | DeviceState *dev = kid->child; | |
382 | ||
383 | if (dev->id && strcmp(dev->id, id) == 0) { | |
384 | return dev; | |
385 | } | |
386 | ||
387 | QLIST_FOREACH(child, &dev->child_bus, sibling) { | |
388 | ret = qdev_find_recursive(child, id); | |
389 | if (ret) { | |
390 | return ret; | |
391 | } | |
392 | } | |
393 | } | |
394 | } | |
395 | return NULL; | |
396 | } | |
397 | ||
398 | char *qdev_get_dev_path(DeviceState *dev) | |
399 | { | |
400 | BusClass *bc; | |
401 | ||
402 | if (!dev || !dev->parent_bus) { | |
403 | return NULL; | |
404 | } | |
405 | ||
406 | bc = BUS_GET_CLASS(dev->parent_bus); | |
407 | if (bc->get_dev_path) { | |
408 | return bc->get_dev_path(dev); | |
409 | } | |
410 | ||
411 | return NULL; | |
412 | } | |
413 | ||
414 | void qdev_add_unplug_blocker(DeviceState *dev, Error *reason) | |
415 | { | |
416 | dev->unplug_blockers = g_slist_prepend(dev->unplug_blockers, reason); | |
417 | } | |
418 | ||
419 | void qdev_del_unplug_blocker(DeviceState *dev, Error *reason) | |
420 | { | |
421 | dev->unplug_blockers = g_slist_remove(dev->unplug_blockers, reason); | |
422 | } | |
423 | ||
424 | bool qdev_unplug_blocked(DeviceState *dev, Error **errp) | |
425 | { | |
426 | if (dev->unplug_blockers) { | |
427 | error_propagate(errp, error_copy(dev->unplug_blockers->data)); | |
428 | return true; | |
429 | } | |
430 | ||
431 | return false; | |
432 | } | |
433 | ||
434 | static bool device_get_realized(Object *obj, Error **errp) | |
435 | { | |
436 | DeviceState *dev = DEVICE(obj); | |
437 | return dev->realized; | |
438 | } | |
439 | ||
440 | static bool check_only_migratable(Object *obj, Error **errp) | |
441 | { | |
442 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
443 | ||
444 | if (!vmstate_check_only_migratable(dc->vmsd)) { | |
445 | error_setg(errp, "Device %s is not migratable, but " | |
446 | "--only-migratable was specified", | |
447 | object_get_typename(obj)); | |
448 | return false; | |
449 | } | |
450 | ||
451 | return true; | |
452 | } | |
453 | ||
454 | static void device_set_realized(Object *obj, bool value, Error **errp) | |
455 | { | |
456 | DeviceState *dev = DEVICE(obj); | |
457 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
458 | HotplugHandler *hotplug_ctrl; | |
459 | BusState *bus; | |
460 | NamedClockList *ncl; | |
461 | Error *local_err = NULL; | |
462 | bool unattached_parent = false; | |
463 | static int unattached_count; | |
464 | ||
465 | if (dev->hotplugged && !dc->hotpluggable) { | |
466 | error_setg(errp, "Device '%s' does not support hotplugging", | |
467 | object_get_typename(obj)); | |
468 | return; | |
469 | } | |
470 | ||
471 | if (value && !dev->realized) { | |
472 | if (!check_only_migratable(obj, errp)) { | |
473 | goto fail; | |
474 | } | |
475 | ||
476 | if (!obj->parent) { | |
477 | gchar *name = g_strdup_printf("device[%d]", unattached_count++); | |
478 | ||
479 | object_property_add_child(machine_get_container("unattached"), | |
480 | name, obj); | |
481 | unattached_parent = true; | |
482 | g_free(name); | |
483 | } | |
484 | ||
485 | hotplug_ctrl = qdev_get_hotplug_handler(dev); | |
486 | if (hotplug_ctrl) { | |
487 | hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); | |
488 | if (local_err != NULL) { | |
489 | goto fail; | |
490 | } | |
491 | } | |
492 | ||
493 | if (dc->realize) { | |
494 | dc->realize(dev, &local_err); | |
495 | if (local_err != NULL) { | |
496 | goto fail; | |
497 | } | |
498 | } | |
499 | ||
500 | DEVICE_LISTENER_CALL(realize, Forward, dev); | |
501 | ||
502 | /* | |
503 | * always free/re-initialize here since the value cannot be cleaned up | |
504 | * in device_unrealize due to its usage later on in the unplug path | |
505 | */ | |
506 | g_free(dev->canonical_path); | |
507 | dev->canonical_path = object_get_canonical_path(OBJECT(dev)); | |
508 | QLIST_FOREACH(ncl, &dev->clocks, node) { | |
509 | if (ncl->alias) { | |
510 | continue; | |
511 | } else { | |
512 | clock_setup_canonical_path(ncl->clock); | |
513 | } | |
514 | } | |
515 | ||
516 | if (qdev_get_vmsd(dev)) { | |
517 | if (vmstate_register_with_alias_id(VMSTATE_IF(dev), | |
518 | VMSTATE_INSTANCE_ID_ANY, | |
519 | qdev_get_vmsd(dev), dev, | |
520 | dev->instance_id_alias, | |
521 | dev->alias_required_for_version, | |
522 | &local_err) < 0) { | |
523 | goto post_realize_fail; | |
524 | } | |
525 | } | |
526 | ||
527 | /* | |
528 | * Clear the reset state, in case the object was previously unrealized | |
529 | * with a dirty state. | |
530 | */ | |
531 | resettable_state_clear(&dev->reset); | |
532 | ||
533 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
534 | if (!qbus_realize(bus, errp)) { | |
535 | goto child_realize_fail; | |
536 | } | |
537 | } | |
538 | if (dev->hotplugged) { | |
539 | /* | |
540 | * Reset the device, as well as its subtree which, at this point, | |
541 | * should be realized too. | |
542 | */ | |
543 | resettable_assert_reset(OBJECT(dev), RESET_TYPE_COLD); | |
544 | resettable_change_parent(OBJECT(dev), OBJECT(dev->parent_bus), | |
545 | NULL); | |
546 | resettable_release_reset(OBJECT(dev), RESET_TYPE_COLD); | |
547 | } | |
548 | dev->pending_deleted_event = false; | |
549 | ||
550 | if (hotplug_ctrl) { | |
551 | hotplug_handler_plug(hotplug_ctrl, dev, &local_err); | |
552 | if (local_err != NULL) { | |
553 | goto child_realize_fail; | |
554 | } | |
555 | } | |
556 | ||
557 | qatomic_store_release(&dev->realized, value); | |
558 | ||
559 | } else if (!value && dev->realized) { | |
560 | ||
561 | /* | |
562 | * Change the value so that any concurrent users are aware | |
563 | * that the device is going to be unrealized | |
564 | * | |
565 | * TODO: change .realized property to enum that states | |
566 | * each phase of the device realization/unrealization | |
567 | */ | |
568 | ||
569 | qatomic_set(&dev->realized, value); | |
570 | /* | |
571 | * Ensure that concurrent users see this update prior to | |
572 | * any other changes done by unrealize. | |
573 | */ | |
574 | smp_wmb(); | |
575 | ||
576 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
577 | qbus_unrealize(bus); | |
578 | } | |
579 | if (qdev_get_vmsd(dev)) { | |
580 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); | |
581 | } | |
582 | if (dc->unrealize) { | |
583 | dc->unrealize(dev); | |
584 | } | |
585 | dev->pending_deleted_event = true; | |
586 | DEVICE_LISTENER_CALL(unrealize, Reverse, dev); | |
587 | } | |
588 | ||
589 | assert(local_err == NULL); | |
590 | return; | |
591 | ||
592 | child_realize_fail: | |
593 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
594 | qbus_unrealize(bus); | |
595 | } | |
596 | ||
597 | if (qdev_get_vmsd(dev)) { | |
598 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); | |
599 | } | |
600 | ||
601 | post_realize_fail: | |
602 | g_free(dev->canonical_path); | |
603 | dev->canonical_path = NULL; | |
604 | if (dc->unrealize) { | |
605 | dc->unrealize(dev); | |
606 | } | |
607 | ||
608 | fail: | |
609 | error_propagate(errp, local_err); | |
610 | if (unattached_parent) { | |
611 | /* | |
612 | * Beware, this doesn't just revert | |
613 | * object_property_add_child(), it also runs bus_remove()! | |
614 | */ | |
615 | object_unparent(OBJECT(dev)); | |
616 | unattached_count--; | |
617 | } | |
618 | } | |
619 | ||
620 | static bool device_get_hotpluggable(Object *obj, Error **errp) | |
621 | { | |
622 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
623 | DeviceState *dev = DEVICE(obj); | |
624 | ||
625 | return dc->hotpluggable && (dev->parent_bus == NULL || | |
626 | qbus_is_hotpluggable(dev->parent_bus)); | |
627 | } | |
628 | ||
629 | static bool device_get_hotplugged(Object *obj, Error **errp) | |
630 | { | |
631 | DeviceState *dev = DEVICE(obj); | |
632 | ||
633 | return dev->hotplugged; | |
634 | } | |
635 | ||
636 | static void device_initfn(Object *obj) | |
637 | { | |
638 | DeviceState *dev = DEVICE(obj); | |
639 | ||
640 | if (phase_check(PHASE_MACHINE_READY)) { | |
641 | dev->hotplugged = 1; | |
642 | qdev_hot_added = true; | |
643 | } | |
644 | ||
645 | dev->instance_id_alias = -1; | |
646 | dev->realized = false; | |
647 | dev->allow_unplug_during_migration = false; | |
648 | ||
649 | QLIST_INIT(&dev->gpios); | |
650 | QLIST_INIT(&dev->clocks); | |
651 | } | |
652 | ||
653 | static void device_post_init(Object *obj) | |
654 | { | |
655 | /* | |
656 | * Note: ordered so that the user's global properties take | |
657 | * precedence. | |
658 | */ | |
659 | object_apply_compat_props(obj); | |
660 | qdev_prop_set_globals(DEVICE(obj)); | |
661 | } | |
662 | ||
663 | /* Unlink device from bus and free the structure. */ | |
664 | static void device_finalize(Object *obj) | |
665 | { | |
666 | NamedGPIOList *ngl, *next; | |
667 | ||
668 | DeviceState *dev = DEVICE(obj); | |
669 | ||
670 | g_assert(!dev->unplug_blockers); | |
671 | ||
672 | QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { | |
673 | QLIST_REMOVE(ngl, node); | |
674 | qemu_free_irqs(ngl->in, ngl->num_in); | |
675 | g_free(ngl->name); | |
676 | g_free(ngl); | |
677 | /* ngl->out irqs are owned by the other end and should not be freed | |
678 | * here | |
679 | */ | |
680 | } | |
681 | ||
682 | qdev_finalize_clocklist(dev); | |
683 | ||
684 | /* Only send event if the device had been completely realized */ | |
685 | if (dev->pending_deleted_event) { | |
686 | g_assert(dev->canonical_path); | |
687 | ||
688 | qapi_event_send_device_deleted(dev->id, dev->canonical_path); | |
689 | g_free(dev->canonical_path); | |
690 | dev->canonical_path = NULL; | |
691 | } | |
692 | ||
693 | g_free(dev->id); | |
694 | } | |
695 | ||
696 | static void device_class_base_init(ObjectClass *class, const void *data) | |
697 | { | |
698 | DeviceClass *klass = DEVICE_CLASS(class); | |
699 | ||
700 | /* We explicitly look up properties in the superclasses, | |
701 | * so do not propagate them to the subclasses. | |
702 | */ | |
703 | klass->props_ = NULL; | |
704 | klass->props_count_ = 0; | |
705 | } | |
706 | ||
707 | static void device_unparent(Object *obj) | |
708 | { | |
709 | DeviceState *dev = DEVICE(obj); | |
710 | BusState *bus; | |
711 | ||
712 | if (dev->realized) { | |
713 | qdev_unrealize(dev); | |
714 | } | |
715 | while (dev->num_child_bus) { | |
716 | bus = QLIST_FIRST(&dev->child_bus); | |
717 | object_unparent(OBJECT(bus)); | |
718 | } | |
719 | if (dev->parent_bus) { | |
720 | bus_remove_child(dev->parent_bus, dev); | |
721 | object_unref(OBJECT(dev->parent_bus)); | |
722 | dev->parent_bus = NULL; | |
723 | } | |
724 | } | |
725 | ||
726 | static char * | |
727 | device_vmstate_if_get_id(VMStateIf *obj) | |
728 | { | |
729 | DeviceState *dev = DEVICE(obj); | |
730 | ||
731 | return qdev_get_dev_path(dev); | |
732 | } | |
733 | ||
734 | static void device_class_init(ObjectClass *class, const void *data) | |
735 | { | |
736 | DeviceClass *dc = DEVICE_CLASS(class); | |
737 | VMStateIfClass *vc = VMSTATE_IF_CLASS(class); | |
738 | ResettableClass *rc = RESETTABLE_CLASS(class); | |
739 | ||
740 | class->unparent = device_unparent; | |
741 | ||
742 | /* by default all devices were considered as hotpluggable, | |
743 | * so with intent to check it in generic qdev_unplug() / | |
744 | * device_set_realized() functions make every device | |
745 | * hotpluggable. Devices that shouldn't be hotpluggable, | |
746 | * should override it in their class_init() | |
747 | */ | |
748 | dc->hotpluggable = true; | |
749 | dc->user_creatable = true; | |
750 | vc->get_id = device_vmstate_if_get_id; | |
751 | rc->get_state = device_get_reset_state; | |
752 | rc->child_foreach = device_reset_child_foreach; | |
753 | ||
754 | /* | |
755 | * A NULL legacy_reset implies a three-phase reset device. Devices can | |
756 | * only be reset using three-phase aware mechanisms, but we still support | |
757 | * for transitional purposes leaf classes which set the old legacy_reset | |
758 | * method via device_class_set_legacy_reset(). | |
759 | */ | |
760 | dc->legacy_reset = NULL; | |
761 | ||
762 | object_class_property_add_bool(class, "realized", | |
763 | device_get_realized, device_set_realized); | |
764 | object_class_property_add_bool(class, "hotpluggable", | |
765 | device_get_hotpluggable, NULL); | |
766 | object_class_property_add_bool(class, "hotplugged", | |
767 | device_get_hotplugged, NULL); | |
768 | object_class_property_add_link(class, "parent_bus", TYPE_BUS, | |
769 | offsetof(DeviceState, parent_bus), NULL, 0); | |
770 | } | |
771 | ||
772 | static void do_legacy_reset(Object *obj, ResetType type) | |
773 | { | |
774 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
775 | ||
776 | dc->legacy_reset(DEVICE(obj)); | |
777 | } | |
778 | ||
779 | void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset) | |
780 | { | |
781 | /* | |
782 | * A legacy DeviceClass::reset has identical semantics to the | |
783 | * three-phase "hold" method, with no "enter" or "exit" | |
784 | * behaviour. Classes that use this legacy function must be leaf | |
785 | * classes that do not chain up to their parent class reset. | |
786 | * There is no mechanism for resetting a device that does not | |
787 | * use the three-phase APIs, so the only place which calls | |
788 | * the legacy_reset hook is do_legacy_reset(). | |
789 | */ | |
790 | ResettableClass *rc = RESETTABLE_CLASS(dc); | |
791 | ||
792 | rc->phases.enter = NULL; | |
793 | rc->phases.hold = do_legacy_reset; | |
794 | rc->phases.exit = NULL; | |
795 | dc->legacy_reset = dev_reset; | |
796 | } | |
797 | ||
798 | void device_class_set_parent_realize(DeviceClass *dc, | |
799 | DeviceRealize dev_realize, | |
800 | DeviceRealize *parent_realize) | |
801 | { | |
802 | *parent_realize = dc->realize; | |
803 | dc->realize = dev_realize; | |
804 | } | |
805 | ||
806 | void device_class_set_parent_unrealize(DeviceClass *dc, | |
807 | DeviceUnrealize dev_unrealize, | |
808 | DeviceUnrealize *parent_unrealize) | |
809 | { | |
810 | *parent_unrealize = dc->unrealize; | |
811 | dc->unrealize = dev_unrealize; | |
812 | } | |
813 | ||
814 | Object *qdev_get_machine(void) | |
815 | { | |
816 | static Object *dev; | |
817 | ||
818 | if (dev == NULL) { | |
819 | dev = object_resolve_path_component(object_get_root(), "machine"); | |
820 | /* | |
821 | * Any call to this function before machine is created is treated | |
822 | * as a programming error as of now. | |
823 | */ | |
824 | assert(dev); | |
825 | } | |
826 | ||
827 | return dev; | |
828 | } | |
829 | ||
830 | Object *machine_get_container(const char *name) | |
831 | { | |
832 | Object *container, *machine; | |
833 | ||
834 | machine = qdev_get_machine(); | |
835 | container = object_resolve_path_component(machine, name); | |
836 | assert(object_dynamic_cast(container, TYPE_CONTAINER)); | |
837 | ||
838 | return container; | |
839 | } | |
840 | ||
841 | char *qdev_get_human_name(DeviceState *dev) | |
842 | { | |
843 | g_assert(dev != NULL); | |
844 | ||
845 | return dev->id ? | |
846 | g_strdup(dev->id) : object_get_canonical_path(OBJECT(dev)); | |
847 | } | |
848 | ||
849 | static MachineInitPhase machine_phase; | |
850 | ||
851 | bool phase_check(MachineInitPhase phase) | |
852 | { | |
853 | return machine_phase >= phase; | |
854 | } | |
855 | ||
856 | void phase_advance(MachineInitPhase phase) | |
857 | { | |
858 | assert(machine_phase == phase - 1); | |
859 | machine_phase = phase; | |
860 | } | |
861 | ||
862 | static const TypeInfo device_type_info = { | |
863 | .name = TYPE_DEVICE, | |
864 | .parent = TYPE_OBJECT, | |
865 | .instance_size = sizeof(DeviceState), | |
866 | .instance_init = device_initfn, | |
867 | .instance_post_init = device_post_init, | |
868 | .instance_finalize = device_finalize, | |
869 | .class_base_init = device_class_base_init, | |
870 | .class_init = device_class_init, | |
871 | .abstract = true, | |
872 | .class_size = sizeof(DeviceClass), | |
873 | .interfaces = (const InterfaceInfo[]) { | |
874 | { TYPE_VMSTATE_IF }, | |
875 | { TYPE_RESETTABLE_INTERFACE }, | |
876 | { } | |
877 | } | |
878 | }; | |
879 | ||
880 | static void qdev_register_types(void) | |
881 | { | |
882 | type_register_static(&device_type_info); | |
883 | } | |
884 | ||
885 | type_init(qdev_register_types) |