qdev.c 18.0 KB
Newer Older
P
Paul Brook 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  Dynamic device configuration and creation.
 *
 *  Copyright (c) 2009 CodeSourcery
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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/>.
P
Paul Brook 已提交
18 19 20 21 22 23 24 25 26 27
 */

/* The theory here is that it should be possible to create a machine without
   knowledge of specific devices.  Historically board init routines have
   passed a bunch of arguments to each device, requiring the board know
   exactly which device it is dealing with.  This file provides an abstract
   API for device configuration and initialization.  Devices will generally
   inherit from a particular bus (e.g. PCI or I2C) rather than
   this API directly.  */

P
Paul Brook 已提交
28
#include "net.h"
P
Paul Brook 已提交
29 30
#include "qdev.h"
#include "sysemu.h"
31
#include "error.h"
P
Paul Brook 已提交
32

33
int qdev_hotplug = 0;
34 35
static bool qdev_hot_added = false;
static bool qdev_hot_removed = false;
36

G
Gerd Hoffmann 已提交
37
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
B
Blue Swirl 已提交
38
static BusState *main_system_bus;
I
Isaku Yamahata 已提交
39
static void main_system_bus_create(void);
P
Paul Brook 已提交
40

P
Paul Brook 已提交
41
/* Register a new device type.  */
A
Anthony Liguori 已提交
42 43
const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
A
Anthony Liguori 已提交
44 45
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    return dc->vmsd;
A
Anthony Liguori 已提交
46 47 48 49
}

BusInfo *qdev_get_bus_info(DeviceState *dev)
{
A
Anthony Liguori 已提交
50 51
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    return dc->bus_info;
A
Anthony Liguori 已提交
52 53 54 55
}

Property *qdev_get_props(DeviceState *dev)
{
A
Anthony Liguori 已提交
56 57
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    return dc->props;
A
Anthony Liguori 已提交
58 59 60 61
}

const char *qdev_fw_name(DeviceState *dev)
{
A
Anthony Liguori 已提交
62
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
A
Anthony Liguori 已提交
63

A
Anthony Liguori 已提交
64 65
    if (dc->fw_name) {
        return dc->fw_name;
A
Anthony Liguori 已提交
66 67 68 69 70
    }

    return object_get_typename(OBJECT(dev));
}

B
Blue Swirl 已提交
71 72
bool qdev_exists(const char *name)
{
A
Anthony Liguori 已提交
73
    return !!object_class_by_name(name);
B
Blue Swirl 已提交
74
}
75

76 77 78
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                     Error **errp);

79
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
80
{
81
    Property *prop;
82 83 84 85

    if (qdev_hotplug) {
        assert(bus->allow_hotplug);
    }
86

87
    dev->parent_bus = bus;
88
    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
89

A
Anthony Liguori 已提交
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
    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
95 96
}

P
Paul Brook 已提交
97 98 99
/* Create a new device.  This only initializes the device state structure
   and allows properties to be set.  qdev_init should be called to
   initialize the actual device emulation.  */
P
Paul Brook 已提交
100
DeviceState *qdev_create(BusState *bus, const char *name)
101 102 103 104 105
{
    DeviceState *dev;

    dev = qdev_try_create(bus, name);
    if (!dev) {
106 107 108 109 110 111
        if (bus) {
            hw_error("Unknown device '%s' for bus '%s'\n", name,
                     bus->info->name);
        } else {
            hw_error("Unknown device '%s' for default sysbus\n", name);
        }
112 113 114 115 116
    }

    return dev;
}

117
DeviceState *qdev_try_create(BusState *bus, const char *type)
P
Paul Brook 已提交
118
{
119 120
    DeviceState *dev;

121
    if (object_class_by_name(type) == NULL) {
122 123
        return NULL;
    }
124
    dev = DEVICE(object_new(type));
125 126 127 128
    if (!dev) {
        return NULL;
    }

129
    if (!bus) {
130
        bus = sysbus_get_default();
131 132
    }

133 134 135 136
    qdev_set_parent_bus(dev, bus);
    qdev_prop_set_globals(dev);

    return dev;
P
Paul Brook 已提交
137 138 139 140
}

/* Initialize a device.  Device properties should be set before calling
   this function.  IRQs and MMIO regions should be connected/mapped after
141 142 143
   calling this function.
   On failure, destroy the device and return negative value.
   Return 0 on success.  */
144
int qdev_init(DeviceState *dev)
P
Paul Brook 已提交
145
{
A
Anthony Liguori 已提交
146
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
147 148
    int rc;

G
Gerd Hoffmann 已提交
149
    assert(dev->state == DEV_STATE_CREATED);
A
Anthony Liguori 已提交
150

A
Anthony Liguori 已提交
151
    rc = dc->init(dev);
152 153
    if (rc < 0) {
        qdev_free(dev);
G
Gerd Hoffmann 已提交
154
        return rc;
155
    }
156 157 158 159 160

    if (!OBJECT(dev)->parent) {
        static int unattached_count = 0;
        gchar *name = g_strdup_printf("device[%d]", unattached_count++);

161 162 163
        object_property_add_child(container_get(qdev_get_machine(),
                                                "/unattached"),
                                  name, OBJECT(dev), NULL);
164 165 166
        g_free(name);
    }

A
Anthony Liguori 已提交
167 168
    if (qdev_get_vmsd(dev)) {
        vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
J
Jan Kiszka 已提交
169 170 171
                                       dev->instance_id_alias,
                                       dev->alias_required_for_version);
    }
G
Gerd Hoffmann 已提交
172
    dev->state = DEV_STATE_INITIALIZED;
173 174
    if (dev->hotplugged) {
        device_reset(dev);
J
Jan Kiszka 已提交
175
    }
G
Gerd Hoffmann 已提交
176
    return 0;
P
Paul Brook 已提交
177 178
}

J
Jan Kiszka 已提交
179 180 181 182 183 184 185 186
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                 int required_for_version)
{
    assert(dev->state == DEV_STATE_CREATED);
    dev->instance_id_alias = alias_id;
    dev->alias_required_for_version = required_for_version;
}

187
void qdev_unplug(DeviceState *dev, Error **errp)
188
{
A
Anthony Liguori 已提交
189 190
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

191
    if (!dev->parent_bus->allow_hotplug) {
192 193
        error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
        return;
194
    }
A
Anthony Liguori 已提交
195
    assert(dc->unplug != NULL);
196

197 198
    qdev_hot_removed = true;

199 200 201 202
    if (dc->unplug(dev) < 0) {
        error_set(errp, QERR_UNDEFINED_ERROR);
        return;
    }
203 204
}

205 206
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
207
    device_reset(dev);
208 209 210 211 212 213

    return 0;
}

BusState *sysbus_get_default(void)
{
214
    if (!main_system_bus) {
I
Isaku Yamahata 已提交
215
        main_system_bus_create();
216
    }
217 218 219
    return main_system_bus;
}

220 221 222 223 224 225 226 227
static int qbus_reset_one(BusState *bus, void *opaque)
{
    if (bus->info->reset) {
        return bus->info->reset(bus);
    }
    return 0;
}

228 229 230 231 232
void qdev_reset_all(DeviceState *dev)
{
    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
}

233 234 235
void qbus_reset_all_fn(void *opaque)
{
    BusState *bus = opaque;
236
    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
237 238
}

239 240 241 242
/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
    /* just zap it */
243
    object_unparent(OBJECT(dev));
244 245 246 247
    qdev_free(dev);
    return 0;
}

248 249

/* Like qdev_init(), but terminate program via error_report() instead of
M
Markus Armbruster 已提交
250 251 252 253 254 255 256 257
   returning an error value.  This is okay during machine creation.
   Don't use for hotplug, because there callers need to recover from
   failure.  Exception: if you know the device's init() callback can't
   fail, then qdev_init_nofail() can't fail either, and is therefore
   usable even then.  But relying on the device implementation that
   way is somewhat unclean, and best avoided.  */
void qdev_init_nofail(DeviceState *dev)
{
258
    if (qdev_init(dev) < 0) {
A
Anthony Liguori 已提交
259 260
        error_report("Initialization of device %s failed",
                     object_get_typename(OBJECT(dev)));
261 262
        exit(1);
    }
M
Markus Armbruster 已提交
263 264
}

P
Paul Brook 已提交
265 266 267
/* Unlink device from bus and free the structure.  */
void qdev_free(DeviceState *dev)
{
268
    object_delete(OBJECT(dev));
P
Paul Brook 已提交
269 270
}

271 272 273 274 275 276 277 278 279
void qdev_machine_creation_done(void)
{
    /*
     * ok, initial machine setup is done, starting from now we can
     * only create hotpluggable devices
     */
    qdev_hotplug = 1;
}

280 281 282 283 284
bool qdev_machine_modified(void)
{
    return qdev_hot_added || qdev_hot_removed;
}

P
Paul Brook 已提交
285
BusState *qdev_get_parent_bus(DeviceState *dev)
P
Paul Brook 已提交
286
{
P
Paul Brook 已提交
287
    return dev->parent_bus;
P
Paul Brook 已提交
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
}

void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
{
    assert(dev->num_gpio_in == 0);
    dev->num_gpio_in = n;
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
}

void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
{
    assert(dev->num_gpio_out == 0);
    dev->num_gpio_out = n;
    dev->gpio_out = pins;
}

qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
{
    assert(n >= 0 && n < dev->num_gpio_in);
    return dev->gpio_in[n];
}

void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
{
    assert(n >= 0 && n < dev->num_gpio_out);
    dev->gpio_out[n] = pin;
}

G
Gerd Hoffmann 已提交
316 317
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
{
318
    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
G
Gerd Hoffmann 已提交
319 320 321 322
    if (nd->vlan)
        qdev_prop_set_vlan(dev, "vlan", nd->vlan);
    if (nd->netdev)
        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
323
    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
324 325 326
        qdev_prop_exists(dev, "vectors")) {
        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
    }
327
    nd->instantiated = 1;
G
Gerd Hoffmann 已提交
328 329
}

P
Paul Brook 已提交
330
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
P
Paul Brook 已提交
331
{
P
Paul Brook 已提交
332
    BusState *bus;
P
Paul Brook 已提交
333

B
Blue Swirl 已提交
334
    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
P
Paul Brook 已提交
335
        if (strcmp(name, bus->name) == 0) {
P
Paul Brook 已提交
336
            return bus;
P
Paul Brook 已提交
337 338 339 340 341
        }
    }
    return NULL;
}

342 343 344 345 346 347 348 349 350 351 352 353 354
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
                       qbus_walkerfn *busfn, void *opaque)
{
    DeviceState *dev;
    int err;

    if (busfn) {
        err = busfn(bus, opaque);
        if (err) {
            return err;
        }
    }

355
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
        err = qdev_walk_children(dev, devfn, busfn, opaque);
        if (err < 0) {
            return err;
        }
    }

    return 0;
}

int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
                       qbus_walkerfn *busfn, void *opaque)
{
    BusState *bus;
    int err;

    if (devfn) {
        err = devfn(dev, opaque);
        if (err) {
            return err;
        }
    }

    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
        err = qbus_walk_children(bus, devfn, busfn, opaque);
        if (err < 0) {
            return err;
        }
    }

    return 0;
}

388
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
389 390 391 392
{
    DeviceState *dev, *ret;
    BusState *child;

393
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
394 395 396 397 398 399 400 401 402 403 404 405
        if (dev->id && strcmp(dev->id, id) == 0)
            return dev;
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
            ret = qdev_find_recursive(child, id);
            if (ret) {
                return ret;
            }
        }
    }
    return NULL;
}

406 407
void qbus_create_inplace(BusState *bus, BusInfo *info,
                         DeviceState *parent, const char *name)
P
Paul Brook 已提交
408
{
G
Gerd Hoffmann 已提交
409 410
    char *buf;
    int i,len;
P
Paul Brook 已提交
411

412
    bus->info = info;
P
Paul Brook 已提交
413
    bus->parent = parent;
G
Gerd Hoffmann 已提交
414 415 416

    if (name) {
        /* use supplied name */
417
        bus->name = g_strdup(name);
G
Gerd Hoffmann 已提交
418 419 420
    } else if (parent && parent->id) {
        /* parent device has id -> use it for bus name */
        len = strlen(parent->id) + 16;
421
        buf = g_malloc(len);
G
Gerd Hoffmann 已提交
422 423 424 425 426
        snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
        bus->name = buf;
    } else {
        /* no id -> use lowercase bus type for bus name */
        len = strlen(info->name) + 16;
427
        buf = g_malloc(len);
G
Gerd Hoffmann 已提交
428 429 430
        len = snprintf(buf, len, "%s.%d", info->name,
                       parent ? parent->num_child_bus : 0);
        for (i = 0; i < len; i++)
C
Christoph Egger 已提交
431
            buf[i] = qemu_tolower(buf[i]);
G
Gerd Hoffmann 已提交
432 433 434
        bus->name = buf;
    }

435
    QTAILQ_INIT(&bus->children);
P
Paul Brook 已提交
436
    if (parent) {
B
Blue Swirl 已提交
437
        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
G
Gerd Hoffmann 已提交
438
        parent->num_child_bus++;
439 440 441 442
    } else if (bus != main_system_bus) {
        /* TODO: once all bus devices are qdevified,
           only reset handler for main_system_bus should be registered here. */
        qemu_register_reset(qbus_reset_all_fn, bus);
P
Paul Brook 已提交
443
    }
444 445 446 447 448 449
}

BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
{
    BusState *bus;

450
    bus = g_malloc0(info->size);
451 452
    bus->qdev_allocated = 1;
    qbus_create_inplace(bus, info, parent, name);
P
Paul Brook 已提交
453 454
    return bus;
}
455

I
Isaku Yamahata 已提交
456 457 458 459
static void main_system_bus_create(void)
{
    /* assign main_system_bus before qbus_create_inplace()
     * in order to make "if (bus != main_system_bus)" work */
460
    main_system_bus = g_malloc0(system_bus_info.size);
I
Isaku Yamahata 已提交
461 462 463 464 465
    main_system_bus->qdev_allocated = 1;
    qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
                        "main-system-bus");
}

G
Gerd Hoffmann 已提交
466 467 468 469
void qbus_free(BusState *bus)
{
    DeviceState *dev;

470
    while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
G
Gerd Hoffmann 已提交
471 472 473 474 475
        qdev_free(dev);
    }
    if (bus->parent) {
        QLIST_REMOVE(bus, sibling);
        bus->parent->num_child_bus--;
476 477 478
    } else {
        assert(bus != main_system_bus); /* main_system_bus is never freed */
        qemu_unregister_reset(qbus_reset_all_fn, bus);
G
Gerd Hoffmann 已提交
479
    }
480
    g_free((void*)bus->name);
G
Gerd Hoffmann 已提交
481
    if (bus->qdev_allocated) {
482
        g_free(bus);
G
Gerd Hoffmann 已提交
483 484 485
    }
}

486 487 488 489 490 491 492 493 494 495
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
    int l = 0;

    if (dev && dev->parent_bus) {
        char *d;
        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
        if (dev->parent_bus->info->get_fw_dev_path) {
            d = dev->parent_bus->info->get_fw_dev_path(dev);
            l += snprintf(p + l, size - l, "%s", d);
496
            g_free(d);
497
        } else {
498
            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
        }
    }
    l += snprintf(p + l , size - l, "/");

    return l;
}

char* qdev_get_fw_dev_path(DeviceState *dev)
{
    char path[128];
    int l;

    l = qdev_get_fw_dev_path_helper(dev, path, 128);

    path[l-1] = '\0';

    return strdup(path);
}
517

518 519 520 521
/**
 * Legacy property handling
 */

522
static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
523 524
                                     const char *name, Error **errp)
{
525
    DeviceState *dev = DEVICE(obj);
526 527
    Property *prop = opaque;

528 529
    char buffer[1024];
    char *ptr = buffer;
530

531 532
    prop->info->print(dev, prop, buffer, sizeof(buffer));
    visit_type_str(v, &ptr, name, errp);
533 534
}

535
static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
536 537
                                     const char *name, Error **errp)
{
538
    DeviceState *dev = DEVICE(obj);
539
    Property *prop = opaque;
540 541 542
    Error *local_err = NULL;
    char *ptr = NULL;
    int ret;
543 544 545 546 547 548

    if (dev->state != DEV_STATE_CREATED) {
        error_set(errp, QERR_PERMISSION_DENIED);
        return;
    }

549 550 551 552 553
    visit_type_str(v, &ptr, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
554

555
    ret = prop->info->parse(dev, prop, ptr);
556
    error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
557
    g_free(ptr);
558 559 560 561 562 563
}

/**
 * @qdev_add_legacy_property - adds a legacy property
 *
 * Do not use this is new code!  Properties added through this interface will
564
 * be given names and types in the "legacy" namespace.
565
 *
566 567
 * Legacy properties are string versions of other OOM properties.  The format
 * of the string depends on the property type.
568 569 570 571
 */
void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                              Error **errp)
{
572
    gchar *name, *type;
573

574 575 576
    /* Register pointer properties as legacy properties */
    if (!prop->info->print && !prop->info->parse &&
        (prop->info->set || prop->info->get)) {
577 578
        return;
    }
579

580
    name = g_strdup_printf("legacy-%s", prop->name);
581 582
    type = g_strdup_printf("legacy<%s>",
                           prop->info->legacy_name ?: prop->info->name);
583

584
    object_property_add(OBJECT(dev), name, type,
585 586
                        prop->info->print ? qdev_get_legacy_property : prop->info->get,
                        prop->info->parse ? qdev_set_legacy_property : prop->info->set,
587 588
                        NULL,
                        prop, errp);
589 590

    g_free(type);
591 592 593 594 595 596 597 598 599 600 601 602
    g_free(name);
}

/**
 * @qdev_property_add_static - add a @Property to a device.
 *
 * Static properties access data in a struct.  The actual type of the
 * property and the field depends on the property type.
 */
void qdev_property_add_static(DeviceState *dev, Property *prop,
                              Error **errp)
{
603 604 605 606 607 608 609 610 611
    /*
     * TODO qdev_prop_ptr does not have getters or setters.  It must
     * go now that it can be replaced with links.  The test should be
     * removed along with it: all static properties are read/write.
     */
    if (!prop->info->get && !prop->info->set) {
        return;
    }

612 613
    object_property_add(OBJECT(dev), prop->name, prop->info->name,
                        prop->info->get, prop->info->set,
P
Paolo Bonzini 已提交
614
                        prop->info->release,
615
                        prop, errp);
A
Anthony Liguori 已提交
616
}
617

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
static void device_initfn(Object *obj)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop;

    if (qdev_hotplug) {
        dev->hotplugged = 1;
        qdev_hot_added = true;
    }

    dev->instance_id_alias = -1;
    dev->state = DEV_STATE_CREATED;

    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
        qdev_property_add_legacy(dev, prop, NULL);
        qdev_property_add_static(dev, prop, NULL);
    }

636
    qdev_prop_set_defaults(dev, qdev_get_props(dev));
637 638
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
/* Unlink device from bus and free the structure.  */
static void device_finalize(Object *obj)
{
    DeviceState *dev = DEVICE(obj);
    BusState *bus;
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

    if (dev->state == DEV_STATE_INITIALIZED) {
        while (dev->num_child_bus) {
            bus = QLIST_FIRST(&dev->child_bus);
            qbus_free(bus);
        }
        if (qdev_get_vmsd(dev)) {
            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
        }
        if (dc->exit) {
            dc->exit(dev);
        }
        if (dev->opts) {
            qemu_opts_del(dev->opts);
        }
    }
    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
}

664 665 666 667 668 669 670 671 672
void device_reset(DeviceState *dev)
{
    DeviceClass *klass = DEVICE_GET_CLASS(dev);

    if (klass->reset) {
        klass->reset(dev);
    }
}

673 674 675 676 677
Object *qdev_get_machine(void)
{
    static Object *dev;

    if (dev == NULL) {
678
        dev = container_get(object_get_root(), "/machine");
679 680 681 682 683
    }

    return dev;
}

684 685 686 687
static TypeInfo device_type_info = {
    .name = TYPE_DEVICE,
    .parent = TYPE_OBJECT,
    .instance_size = sizeof(DeviceState),
688
    .instance_init = device_initfn,
689
    .instance_finalize = device_finalize,
690 691 692 693
    .abstract = true,
    .class_size = sizeof(DeviceClass),
};

A
Andreas Färber 已提交
694
static void qdev_register_types(void)
695 696 697 698
{
    type_register_static(&device_type_info);
}

A
Andreas Färber 已提交
699
type_init(qdev_register_types)