qdev.c 42.4 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 "monitor.h"
P
Paul Brook 已提交
32

33
static 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

41 42 43 44
static BusState *qbus_find_recursive(BusState *bus, const char *name,
                                     const BusInfo *info);
static BusState *qbus_find(const char *path);

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

BusInfo *qdev_get_bus_info(DeviceState *dev)
{
A
Anthony Liguori 已提交
54 55
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    return dc->bus_info;
A
Anthony Liguori 已提交
56 57 58 59
}

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

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
/*
 * Aliases were a bad idea from the start.  Let's keep them
 * from spreading further.
 */
typedef struct QDevAlias
{
    const char *typename;
    const char *alias;
} QDevAlias;

static const QDevAlias qdev_alias_table[] = {
    { "virtio-blk-pci", "virtio-blk" },
    { "virtio-net-pci", "virtio-net" },
    { "virtio-serial-pci", "virtio-serial" },
    { "virtio-balloon-pci", "virtio-balloon" },
    { "virtio-blk-s390", "virtio-blk" },
    { "virtio-net-s390", "virtio-net" },
    { "virtio-serial-s390", "virtio-serial" },
    { "lsi53c895a", "lsi" },
    { "ich9-ahci", "ahci" },
    { }
};

static const char *qdev_class_get_alias(DeviceClass *dc)
{
    const char *typename = object_class_get_name(OBJECT_CLASS(dc));
    int i;

    for (i = 0; qdev_alias_table[i].typename; i++) {
        if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
            return qdev_alias_table[i].alias;
        }
    }

    return NULL;
}

static bool qdev_class_has_alias(DeviceClass *dc)
{
    return (qdev_class_get_alias(dc) != NULL);
}

A
Anthony Liguori 已提交
106 107
const char *qdev_fw_name(DeviceState *dev)
{
A
Anthony Liguori 已提交
108
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
A
Anthony Liguori 已提交
109

A
Anthony Liguori 已提交
110 111
    if (dc->fw_name) {
        return dc->fw_name;
112 113
    } else if (qdev_class_has_alias(dc)) {
        return qdev_class_get_alias(dc);
A
Anthony Liguori 已提交
114 115 116 117 118
    }

    return object_get_typename(OBJECT(dev));
}

B
Blue Swirl 已提交
119 120
bool qdev_exists(const char *name)
{
A
Anthony Liguori 已提交
121
    return !!object_class_by_name(name);
B
Blue Swirl 已提交
122
}
123

124 125 126
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                     Error **errp);

127
static DeviceState *qdev_create_from_info(BusState *bus, const char *typename)
128 129
{
    DeviceState *dev;
130
    Property *prop;
131

132
    dev = DEVICE(object_new(typename));
133
    dev->parent_bus = bus;
A
Anthony Liguori 已提交
134
    qdev_prop_set_defaults(dev, qdev_get_props(dev));
135 136
    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
    qdev_prop_set_globals(dev);
137
    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
138 139 140
    if (qdev_hotplug) {
        assert(bus->allow_hotplug);
        dev->hotplugged = 1;
141
        qdev_hot_added = true;
142
    }
J
Jan Kiszka 已提交
143
    dev->instance_id_alias = -1;
144
    QTAILQ_INIT(&dev->properties);
145
    dev->state = DEV_STATE_CREATED;
146

A
Anthony Liguori 已提交
147
    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
148
        qdev_property_add_legacy(dev, prop, NULL);
149
        qdev_property_add_static(dev, prop, NULL);
150 151
    }

A
Anthony Liguori 已提交
152
    for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
153
        qdev_property_add_legacy(dev, prop, NULL);
154
        qdev_property_add_static(dev, prop, NULL);
155 156
    }

157 158
    qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);

159 160 161
    return dev;
}

P
Paul Brook 已提交
162 163 164
/* 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 已提交
165
DeviceState *qdev_create(BusState *bus, const char *name)
166 167 168 169 170
{
    DeviceState *dev;

    dev = qdev_try_create(bus, name);
    if (!dev) {
171 172 173 174 175 176
        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);
        }
177 178 179 180 181 182
    }

    return dev;
}

DeviceState *qdev_try_create(BusState *bus, const char *name)
P
Paul Brook 已提交
183
{
184
    if (!bus) {
185
        bus = sysbus_get_default();
186 187
    }

188
    return qdev_create_from_info(bus, name);
P
Paul Brook 已提交
189 190
}

A
Anthony Liguori 已提交
191
static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
192
{
A
Anthony Liguori 已提交
193 194 195 196 197 198 199
    DeviceClass *dc;
    bool *show_no_user = opaque;

    dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE);

    if (!dc || (show_no_user && !*show_no_user && dc->no_user)) {
        return;
G
Gerd Hoffmann 已提交
200
    }
A
Anthony Liguori 已提交
201 202 203 204

    error_printf("name \"%s\"", object_class_get_name(klass));
    if (dc->bus_info) {
        error_printf(", bus %s", dc->bus_info->name);
G
Gerd Hoffmann 已提交
205
    }
206 207
    if (qdev_class_has_alias(dc)) {
        error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
A
Anthony Liguori 已提交
208 209 210 211 212
    }
    if (dc->desc) {
        error_printf(", desc \"%s\"", dc->desc);
    }
    if (dc->no_user) {
213
        error_printf(", no-user");
G
Gerd Hoffmann 已提交
214
    }
215
    error_printf("\n");
216 217
}

G
Gerd Hoffmann 已提交
218
static int set_property(const char *name, const char *value, void *opaque)
219
{
G
Gerd Hoffmann 已提交
220 221 222 223 224 225 226
    DeviceState *dev = opaque;

    if (strcmp(name, "driver") == 0)
        return 0;
    if (strcmp(name, "bus") == 0)
        return 0;

M
Mark McLoughlin 已提交
227
    if (qdev_prop_parse(dev, name, value) == -1) {
G
Gerd Hoffmann 已提交
228 229 230 231 232
        return -1;
    }
    return 0;
}

233 234 235 236 237 238 239 240 241 242 243 244 245
static const char *find_typename_by_alias(const char *alias)
{
    int i;

    for (i = 0; qdev_alias_table[i].alias; i++) {
        if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
            return qdev_alias_table[i].typename;
        }
    }

    return NULL;
}

246 247 248
int qdev_device_help(QemuOpts *opts)
{
    const char *driver;
249
    Property *prop;
A
Anthony Liguori 已提交
250 251
    ObjectClass *klass;
    DeviceClass *info;
252 253 254

    driver = qemu_opt_get(opts, "driver");
    if (driver && !strcmp(driver, "?")) {
A
Anthony Liguori 已提交
255 256
        bool show_no_user = false;
        object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user);
257 258 259
        return 1;
    }

260
    if (!driver || !qemu_opt_get(opts, "?")) {
261 262 263
        return 0;
    }

A
Anthony Liguori 已提交
264
    klass = object_class_by_name(driver);
265 266 267 268 269 270 271 272 273
    if (!klass) {
        const char *typename = find_typename_by_alias(driver);

        if (typename) {
            driver = typename;
            klass = object_class_by_name(driver);
        }
    }

A
Anthony Liguori 已提交
274
    if (!klass) {
275 276
        return 0;
    }
A
Anthony Liguori 已提交
277
    info = DEVICE_CLASS(klass);
278 279

    for (prop = info->props; prop && prop->name; prop++) {
280 281 282 283 284 285 286 287 288
        /*
         * TODO Properties without a parser are just for dirty hacks.
         * qdev_prop_ptr is the only such PropertyInfo.  It's marked
         * for removal.  This conditional should be removed along with
         * it.
         */
        if (!prop->info->parse) {
            continue;           /* no way to set it, don't show */
        }
A
Anthony Liguori 已提交
289
        error_printf("%s.%s=%s\n", driver, prop->name,
290
                     prop->info->legacy_name ?: prop->info->name);
G
Gerd Hoffmann 已提交
291 292 293 294 295
    }
    for (prop = info->bus_info->props; prop && prop->name; prop++) {
        if (!prop->info->parse) {
            continue;           /* no way to set it, don't show */
        }
A
Anthony Liguori 已提交
296
        error_printf("%s.%s=%s\n", driver, prop->name,
297
                     prop->info->legacy_name ?: prop->info->name);
298 299
    }
    return 1;
300 301
}

302 303 304 305 306 307 308 309 310 311 312 313 314
static DeviceState *qdev_get_peripheral(void)
{
    static DeviceState *dev;

    if (dev == NULL) {
        dev = qdev_create(NULL, "container");
        qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
        qdev_init_nofail(dev);
    }

    return dev;
}

315 316 317 318 319 320 321 322 323 324 325 326 327
static DeviceState *qdev_get_peripheral_anon(void)
{
    static DeviceState *dev;

    if (dev == NULL) {
        dev = qdev_create(NULL, "container");
        qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
        qdev_init_nofail(dev);
    }

    return dev;
}

G
Gerd Hoffmann 已提交
328 329
DeviceState *qdev_device_add(QemuOpts *opts)
{
330
    ObjectClass *obj;
331
    DeviceClass *k;
G
Gerd Hoffmann 已提交
332
    const char *driver, *path, *id;
333 334 335
    DeviceState *qdev;
    BusState *bus;

G
Gerd Hoffmann 已提交
336 337
    driver = qemu_opt_get(opts, "driver");
    if (!driver) {
338
        qerror_report(QERR_MISSING_PARAMETER, "driver");
339 340
        return NULL;
    }
G
Gerd Hoffmann 已提交
341 342

    /* find driver */
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    obj = object_class_by_name(driver);
    if (!obj) {
        const char *typename = find_typename_by_alias(driver);

        if (typename) {
            driver = typename;
            obj = object_class_by_name(driver);
        }
    }

    if (!obj) {
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
        return NULL;
    }

    k = DEVICE_CLASS(obj);
359

G
Gerd Hoffmann 已提交
360 361 362
    /* find bus */
    path = qemu_opt_get(opts, "bus");
    if (path != NULL) {
363
        bus = qbus_find(path);
364 365 366
        if (!bus) {
            return NULL;
        }
367
        if (bus->info != k->bus_info) {
368 369
            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
                           driver, bus->info->name);
370 371
            return NULL;
        }
372
    } else {
373
        bus = qbus_find_recursive(main_system_bus, NULL, k->bus_info);
374
        if (!bus) {
375
            qerror_report(QERR_NO_BUS_FOR_DEVICE,
376
                          driver, k->bus_info->name);
377 378
            return NULL;
        }
379
    }
380
    if (qdev_hotplug && !bus->allow_hotplug) {
381
        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
382 383
        return NULL;
    }
384

G
Gerd Hoffmann 已提交
385
    /* create device, set properties */
386
    qdev = qdev_create_from_info(bus, driver);
G
Gerd Hoffmann 已提交
387 388 389
    id = qemu_opts_id(opts);
    if (id) {
        qdev->id = id;
390
        qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
391 392 393 394 395 396 397
    } else {
        static int anon_count;
        gchar *name = g_strdup_printf("device[%d]", anon_count++);
        qdev_property_add_child(qdev_get_peripheral_anon(), name,
                                qdev, NULL);
        g_free(name);
    }        
G
Gerd Hoffmann 已提交
398 399 400
    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
        qdev_free(qdev);
        return NULL;
401
    }
402
    if (qdev_init(qdev) < 0) {
403
        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
404 405
        return NULL;
    }
406
    qdev->opts = opts;
407 408 409
    return qdev;
}

P
Paul Brook 已提交
410 411
/* Initialize a device.  Device properties should be set before calling
   this function.  IRQs and MMIO regions should be connected/mapped after
412 413 414
   calling this function.
   On failure, destroy the device and return negative value.
   Return 0 on success.  */
415
int qdev_init(DeviceState *dev)
P
Paul Brook 已提交
416
{
A
Anthony Liguori 已提交
417
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
418 419
    int rc;

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

A
Anthony Liguori 已提交
422
    rc = dc->init(dev);
423 424
    if (rc < 0) {
        qdev_free(dev);
G
Gerd Hoffmann 已提交
425
        return rc;
426
    }
A
Anthony Liguori 已提交
427 428
    if (qdev_get_vmsd(dev)) {
        vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
J
Jan Kiszka 已提交
429 430 431
                                       dev->instance_id_alias,
                                       dev->alias_required_for_version);
    }
G
Gerd Hoffmann 已提交
432
    dev->state = DEV_STATE_INITIALIZED;
433 434
    if (dev->hotplugged) {
        device_reset(dev);
J
Jan Kiszka 已提交
435
    }
G
Gerd Hoffmann 已提交
436
    return 0;
P
Paul Brook 已提交
437 438
}

J
Jan Kiszka 已提交
439 440 441 442 443 444 445 446
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;
}

447 448
int qdev_unplug(DeviceState *dev)
{
A
Anthony Liguori 已提交
449 450
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

451
    if (!dev->parent_bus->allow_hotplug) {
452
        qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
453 454
        return -1;
    }
A
Anthony Liguori 已提交
455
    assert(dc->unplug != NULL);
456

457 458
    qdev_hot_removed = true;

A
Anthony Liguori 已提交
459
    return dc->unplug(dev);
460 461
}

462 463
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
464
    device_reset(dev);
465 466 467 468 469 470

    return 0;
}

BusState *sysbus_get_default(void)
{
471
    if (!main_system_bus) {
I
Isaku Yamahata 已提交
472
        main_system_bus_create();
473
    }
474 475 476
    return main_system_bus;
}

477 478 479 480 481 482 483 484
static int qbus_reset_one(BusState *bus, void *opaque)
{
    if (bus->info->reset) {
        return bus->info->reset(bus);
    }
    return 0;
}

485 486 487 488 489
void qdev_reset_all(DeviceState *dev)
{
    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
}

490 491 492
void qbus_reset_all_fn(void *opaque)
{
    BusState *bus = opaque;
493
    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
494 495
}

496 497 498 499 500 501 502 503
/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
    /* just zap it */
    qdev_free(dev);
    return 0;
}

504 505

/* Like qdev_init(), but terminate program via error_report() instead of
M
Markus Armbruster 已提交
506 507 508 509 510 511 512 513
   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)
{
514
    if (qdev_init(dev) < 0) {
A
Anthony Liguori 已提交
515 516
        error_report("Initialization of device %s failed",
                     object_get_typename(OBJECT(dev)));
517 518
        exit(1);
    }
M
Markus Armbruster 已提交
519 520
}

521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
static void qdev_property_del_all(DeviceState *dev)
{
    while (!QTAILQ_EMPTY(&dev->properties)) {
        DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);

        QTAILQ_REMOVE(&dev->properties, prop, node);

        if (prop->release) {
            prop->release(dev, prop->name, prop->opaque);
        }

        g_free(prop->name);
        g_free(prop->type);
        g_free(prop);
    }
}

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
{
    DeviceProperty *prop;

    QTAILQ_FOREACH(prop, &dev->properties, node) {
        if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
            break;
        }
    }

    g_assert(prop != NULL);

    QTAILQ_REMOVE(&dev->properties, prop, node);

    if (prop->release) {
        prop->release(dev, prop->name, prop->opaque);
    }

    g_free(prop->name);
    g_free(prop->type);
    g_free(prop);
}

P
Paul Brook 已提交
561 562 563
/* Unlink device from bus and free the structure.  */
void qdev_free(DeviceState *dev)
{
G
Gerd Hoffmann 已提交
564
    BusState *bus;
565
    Property *prop;
A
Anthony Liguori 已提交
566
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
G
Gerd Hoffmann 已提交
567

568 569
    qdev_property_del_all(dev);

G
Gerd Hoffmann 已提交
570 571 572 573 574
    if (dev->state == DEV_STATE_INITIALIZED) {
        while (dev->num_child_bus) {
            bus = QLIST_FIRST(&dev->child_bus);
            qbus_free(bus);
        }
A
Anthony Liguori 已提交
575 576 577 578 579 580 581
        if (qdev_get_vmsd(dev)) {
            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
        }
        if (dc->exit) {
            dc->exit(dev);
        }
        if (dev->opts) {
582
            qemu_opts_del(dev->opts);
A
Anthony Liguori 已提交
583
        }
G
Gerd Hoffmann 已提交
584
    }
585
    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
A
Anthony Liguori 已提交
586
    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
587 588 589 590
        if (prop->info->free) {
            prop->info->free(dev, prop);
        }
    }
591 592 593 594 595 596
    if (dev->parent) {
        qdev_property_del_child(dev->parent, dev, NULL);
    }
    if (dev->ref != 0) {
        qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
    }
597
    object_delete(OBJECT(dev));
P
Paul Brook 已提交
598 599
}

600 601 602 603 604 605 606 607 608
void qdev_machine_creation_done(void)
{
    /*
     * ok, initial machine setup is done, starting from now we can
     * only create hotpluggable devices
     */
    qdev_hotplug = 1;
}

609 610 611 612 613
bool qdev_machine_modified(void)
{
    return qdev_hot_added || qdev_hot_removed;
}

P
Paul Brook 已提交
614 615 616 617
/* Get a character (serial) device interface.  */
CharDriverState *qdev_init_chardev(DeviceState *dev)
{
    static int next_serial;
618 619 620

    /* FIXME: This function needs to go away: use chardev properties!  */
    return serial_hds[next_serial++];
P
Paul Brook 已提交
621 622
}

P
Paul Brook 已提交
623
BusState *qdev_get_parent_bus(DeviceState *dev)
P
Paul Brook 已提交
624
{
P
Paul Brook 已提交
625
    return dev->parent_bus;
P
Paul Brook 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
}

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 已提交
654 655
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
{
656
    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
G
Gerd Hoffmann 已提交
657 658 659 660
    if (nd->vlan)
        qdev_prop_set_vlan(dev, "vlan", nd->vlan);
    if (nd->netdev)
        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
661
    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
662 663 664
        qdev_prop_exists(dev, "vectors")) {
        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
    }
665
    nd->instantiated = 1;
G
Gerd Hoffmann 已提交
666 667
}

P
Paul Brook 已提交
668
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
P
Paul Brook 已提交
669
{
P
Paul Brook 已提交
670
    BusState *bus;
P
Paul Brook 已提交
671

B
Blue Swirl 已提交
672
    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
P
Paul Brook 已提交
673
        if (strcmp(name, bus->name) == 0) {
P
Paul Brook 已提交
674
            return bus;
P
Paul Brook 已提交
675 676 677 678 679
        }
    }
    return NULL;
}

680 681 682 683 684 685 686 687 688 689 690 691 692
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;
        }
    }

693
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
        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;
}

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
static BusState *qbus_find_recursive(BusState *bus, const char *name,
                                     const BusInfo *info)
{
    DeviceState *dev;
    BusState *child, *ret;
    int match = 1;

    if (name && (strcmp(bus->name, name) != 0)) {
        match = 0;
    }
    if (info && (bus->info != info)) {
        match = 0;
    }
    if (match) {
        return bus;
    }

743
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
B
Blue Swirl 已提交
744
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
745 746 747 748 749 750 751 752 753
            ret = qbus_find_recursive(child, name, info);
            if (ret) {
                return ret;
            }
        }
    }
    return NULL;
}

754
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
755 756 757 758
{
    DeviceState *dev, *ret;
    BusState *child;

759
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
760 761 762 763 764 765 766 767 768 769 770 771
        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;
}

772
static void qbus_list_bus(DeviceState *dev)
773 774 775 776
{
    BusState *child;
    const char *sep = " ";

777
    error_printf("child busses at \"%s\":",
778
                 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
B
Blue Swirl 已提交
779
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
780
        error_printf("%s\"%s\"", sep, child->name);
781 782
        sep = ", ";
    }
783
    error_printf("\n");
784 785
}

786
static void qbus_list_dev(BusState *bus)
787 788 789 790
{
    DeviceState *dev;
    const char *sep = " ";

791
    error_printf("devices at \"%s\":", bus->name);
792
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
793
        error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
794
        if (dev->id)
795
            error_printf("/\"%s\"", dev->id);
796 797
        sep = ", ";
    }
798
    error_printf("\n");
799 800 801 802 803 804
}

static BusState *qbus_find_bus(DeviceState *dev, char *elem)
{
    BusState *child;

B
Blue Swirl 已提交
805
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
        if (strcmp(child->name, elem) == 0) {
            return child;
        }
    }
    return NULL;
}

static DeviceState *qbus_find_dev(BusState *bus, char *elem)
{
    DeviceState *dev;

    /*
     * try to match in order:
     *   (1) instance id, if present
     *   (2) driver name
     *   (3) driver alias, if present
     */
823
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
824 825 826 827
        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
            return dev;
        }
    }
828
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
829
        if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
830 831 832
            return dev;
        }
    }
833
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
A
Anthony Liguori 已提交
834 835
        DeviceClass *dc = DEVICE_GET_CLASS(dev);

836 837
        if (qdev_class_has_alias(dc) &&
            strcmp(qdev_class_get_alias(dc), elem) == 0) {
838 839 840 841 842 843 844 845 846 847
            return dev;
        }
    }
    return NULL;
}

static BusState *qbus_find(const char *path)
{
    DeviceState *dev;
    BusState *bus;
848
    char elem[128];
849 850 851 852 853 854 855 856
    int pos, len;

    /* find start element */
    if (path[0] == '/') {
        bus = main_system_bus;
        pos = 0;
    } else {
        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
857 858
            assert(!path[0]);
            elem[0] = len = 0;
859 860 861
        }
        bus = qbus_find_recursive(main_system_bus, elem, NULL);
        if (!bus) {
862
            qerror_report(QERR_BUS_NOT_FOUND, elem);
863 864 865 866 867 868
            return NULL;
        }
        pos = len;
    }

    for (;;) {
869 870 871 872
        assert(path[pos] == '/' || !path[pos]);
        while (path[pos] == '/') {
            pos++;
        }
873 874 875 876 877
        if (path[pos] == '\0') {
            return bus;
        }

        /* find device */
878 879 880
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
            assert(0);
            elem[0] = len = 0;
881 882 883 884
        }
        pos += len;
        dev = qbus_find_dev(bus, elem);
        if (!dev) {
885
            qerror_report(QERR_DEVICE_NOT_FOUND, elem);
886 887 888
            if (!monitor_cur_is_qmp()) {
                qbus_list_dev(bus);
            }
889 890
            return NULL;
        }
891 892 893 894 895

        assert(path[pos] == '/' || !path[pos]);
        while (path[pos] == '/') {
            pos++;
        }
896 897 898 899 900
        if (path[pos] == '\0') {
            /* last specified element is a device.  If it has exactly
             * one child bus accept it nevertheless */
            switch (dev->num_child_bus) {
            case 0:
901
                qerror_report(QERR_DEVICE_NO_BUS, elem);
902 903
                return NULL;
            case 1:
B
Blue Swirl 已提交
904
                return QLIST_FIRST(&dev->child_bus);
905
            default:
906
                qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
907 908 909
                if (!monitor_cur_is_qmp()) {
                    qbus_list_bus(dev);
                }
910 911 912 913 914
                return NULL;
            }
        }

        /* find bus */
915 916 917
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
            assert(0);
            elem[0] = len = 0;
918 919 920 921
        }
        pos += len;
        bus = qbus_find_bus(dev, elem);
        if (!bus) {
922
            qerror_report(QERR_BUS_NOT_FOUND, elem);
923 924 925
            if (!monitor_cur_is_qmp()) {
                qbus_list_bus(dev);
            }
926 927 928 929 930
            return NULL;
        }
    }
}

931 932
void qbus_create_inplace(BusState *bus, BusInfo *info,
                         DeviceState *parent, const char *name)
P
Paul Brook 已提交
933
{
G
Gerd Hoffmann 已提交
934 935
    char *buf;
    int i,len;
P
Paul Brook 已提交
936

937
    bus->info = info;
P
Paul Brook 已提交
938
    bus->parent = parent;
G
Gerd Hoffmann 已提交
939 940 941

    if (name) {
        /* use supplied name */
942
        bus->name = g_strdup(name);
G
Gerd Hoffmann 已提交
943 944 945
    } else if (parent && parent->id) {
        /* parent device has id -> use it for bus name */
        len = strlen(parent->id) + 16;
946
        buf = g_malloc(len);
G
Gerd Hoffmann 已提交
947 948 949 950 951
        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;
952
        buf = g_malloc(len);
G
Gerd Hoffmann 已提交
953 954 955
        len = snprintf(buf, len, "%s.%d", info->name,
                       parent ? parent->num_child_bus : 0);
        for (i = 0; i < len; i++)
C
Christoph Egger 已提交
956
            buf[i] = qemu_tolower(buf[i]);
G
Gerd Hoffmann 已提交
957 958 959
        bus->name = buf;
    }

960
    QTAILQ_INIT(&bus->children);
P
Paul Brook 已提交
961
    if (parent) {
B
Blue Swirl 已提交
962
        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
G
Gerd Hoffmann 已提交
963
        parent->num_child_bus++;
964 965 966 967
    } 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 已提交
968
    }
969 970 971 972 973 974
}

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

975
    bus = g_malloc0(info->size);
976 977
    bus->qdev_allocated = 1;
    qbus_create_inplace(bus, info, parent, name);
P
Paul Brook 已提交
978 979
    return bus;
}
980

I
Isaku Yamahata 已提交
981 982 983 984
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 */
985
    main_system_bus = g_malloc0(system_bus_info.size);
I
Isaku Yamahata 已提交
986 987 988 989 990
    main_system_bus->qdev_allocated = 1;
    qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
                        "main-system-bus");
}

G
Gerd Hoffmann 已提交
991 992 993 994
void qbus_free(BusState *bus)
{
    DeviceState *dev;

995
    while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
G
Gerd Hoffmann 已提交
996 997 998 999 1000
        qdev_free(dev);
    }
    if (bus->parent) {
        QLIST_REMOVE(bus, sibling);
        bus->parent->num_child_bus--;
1001 1002 1003
    } else {
        assert(bus != main_system_bus); /* main_system_bus is never freed */
        qemu_unregister_reset(qbus_reset_all_fn, bus);
G
Gerd Hoffmann 已提交
1004
    }
1005
    g_free((void*)bus->name);
G
Gerd Hoffmann 已提交
1006
    if (bus->qdev_allocated) {
1007
        g_free(bus);
G
Gerd Hoffmann 已提交
1008 1009 1010
    }
}

1011 1012 1013
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
static void qbus_print(Monitor *mon, BusState *bus, int indent);

G
Gerd Hoffmann 已提交
1014 1015 1016 1017 1018 1019 1020 1021
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
                             const char *prefix, int indent)
{
    char buf[64];

    if (!props)
        return;
    while (props->name) {
1022 1023 1024 1025 1026 1027
        /*
         * TODO Properties without a print method are just for dirty
         * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
         * marked for removal.  The test props->info->print should be
         * removed along with it.
         */
G
Gerd Hoffmann 已提交
1028 1029 1030 1031 1032 1033 1034 1035
        if (props->info->print) {
            props->info->print(dev, props, buf, sizeof(buf));
            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
        }
        props++;
    }
}

1036 1037 1038
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
{
    BusState *child;
1039
    qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
1040
                dev->id ? dev->id : "");
1041 1042 1043 1044 1045 1046 1047
    indent += 2;
    if (dev->num_gpio_in) {
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
    }
    if (dev->num_gpio_out) {
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
    }
A
Anthony Liguori 已提交
1048
    qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent);
G
Gerd Hoffmann 已提交
1049
    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
1050 1051
    if (dev->parent_bus->info->print_dev)
        dev->parent_bus->info->print_dev(mon, dev, indent);
B
Blue Swirl 已提交
1052
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
        qbus_print(mon, child, indent);
    }
}

static void qbus_print(Monitor *mon, BusState *bus, int indent)
{
    struct DeviceState *dev;

    qdev_printf("bus: %s\n", bus->name);
    indent += 2;
1063
    qdev_printf("type %s\n", bus->info->name);
1064
    QTAILQ_FOREACH(dev, &bus->children, sibling) {
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
        qdev_print(mon, dev, indent);
    }
}
#undef qdev_printf

void do_info_qtree(Monitor *mon)
{
    if (main_system_bus)
        qbus_print(mon, main_system_bus, 0);
}
1075

G
Gerd Hoffmann 已提交
1076
void do_info_qdm(Monitor *mon)
1077
{
A
Anthony Liguori 已提交
1078
    object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
1079
}
1080

1081
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
1082 1083 1084
{
    QemuOpts *opts;

1085
    opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
1086 1087 1088 1089 1090 1091
    if (!opts) {
        return -1;
    }
    if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
        qemu_opts_del(opts);
        return 0;
1092
    }
1093 1094 1095 1096 1097
    if (!qdev_device_add(opts)) {
        qemu_opts_del(opts);
        return -1;
    }
    return 0;
1098 1099
}

1100
int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
1101 1102 1103 1104 1105 1106
{
    const char *id = qdict_get_str(qdict, "id");
    DeviceState *dev;

    dev = qdev_find_recursive(main_system_bus, id);
    if (NULL == dev) {
1107 1108
        qerror_report(QERR_DEVICE_NOT_FOUND, id);
        return -1;
1109
    }
1110
    return qdev_unplug(dev);
1111
}
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122

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);
1123
            g_free(d);
1124
        } else {
1125
            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
        }
    }
    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);
}
1144

1145 1146
char *qdev_get_type(DeviceState *dev, Error **errp)
{
1147
    return g_strdup(object_get_typename(OBJECT(dev)));
1148 1149
}

1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
void qdev_ref(DeviceState *dev)
{
    dev->ref++;
}

void qdev_unref(DeviceState *dev)
{
    g_assert(dev->ref > 0);
    dev->ref--;
}
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221

void qdev_property_add(DeviceState *dev, const char *name, const char *type,
                       DevicePropertyAccessor *get, DevicePropertyAccessor *set,
                       DevicePropertyRelease *release,
                       void *opaque, Error **errp)
{
    DeviceProperty *prop = g_malloc0(sizeof(*prop));

    prop->name = g_strdup(name);
    prop->type = g_strdup(type);

    prop->get = get;
    prop->set = set;
    prop->release = release;
    prop->opaque = opaque;

    QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
}

static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
{
    DeviceProperty *prop;

    QTAILQ_FOREACH(prop, &dev->properties, node) {
        if (strcmp(prop->name, name) == 0) {
            return prop;
        }
    }

    return NULL;
}

void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
                       Error **errp)
{
    DeviceProperty *prop = qdev_property_find(dev, name);

    if (prop == NULL) {
        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
        return;
    }

    if (!prop->get) {
        error_set(errp, QERR_PERMISSION_DENIED);
    } else {
        prop->get(dev, v, prop->opaque, name, errp);
    }
}

void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
                       Error **errp)
{
    DeviceProperty *prop = qdev_property_find(dev, name);

    if (prop == NULL) {
        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
        return;
    }

    if (!prop->set) {
        error_set(errp, QERR_PERMISSION_DENIED);
    } else {
P
Paolo Bonzini 已提交
1222
        prop->set(dev, v, prop->opaque, name, errp);
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
    }
}

const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
{
    DeviceProperty *prop = qdev_property_find(dev, name);

    if (prop == NULL) {
        error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
        return NULL;
    }

    return prop->type;
}
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246

/**
 * Legacy property handling
 */

static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
                                     const char *name, Error **errp)
{
    Property *prop = opaque;

1247 1248
    char buffer[1024];
    char *ptr = buffer;
1249

1250 1251
    prop->info->print(dev, prop, buffer, sizeof(buffer));
    visit_type_str(v, &ptr, name, errp);
1252 1253 1254 1255 1256 1257
}

static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
                                     const char *name, Error **errp)
{
    Property *prop = opaque;
1258 1259 1260
    Error *local_err = NULL;
    char *ptr = NULL;
    int ret;
1261 1262 1263 1264 1265 1266

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

1267 1268 1269 1270 1271
    visit_type_str(v, &ptr, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
1272

1273
    ret = prop->info->parse(dev, prop, ptr);
1274
    error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
1275
    g_free(ptr);
1276 1277 1278 1279 1280 1281
}

/**
 * @qdev_add_legacy_property - adds a legacy property
 *
 * Do not use this is new code!  Properties added through this interface will
1282
 * be given names and types in the "legacy" namespace.
1283 1284 1285 1286 1287 1288 1289
 *
 * Legacy properties are always processed as strings.  The format of the string
 * depends on the property type.
 */
void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                              Error **errp)
{
1290
    gchar *name, *type;
1291

1292
    name = g_strdup_printf("legacy-%s", prop->name);
1293 1294
    type = g_strdup_printf("legacy<%s>",
                           prop->info->legacy_name ?: prop->info->name);
1295

1296
    qdev_property_add(dev, name, type,
1297 1298
                      prop->info->print ? qdev_get_legacy_property : NULL,
                      prop->info->parse ? qdev_set_legacy_property : NULL,
1299 1300 1301 1302
                      NULL,
                      prop, errp);

    g_free(type);
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
    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)
{
    qdev_property_add(dev, prop->name, prop->info->name,
                      prop->info->get, prop->info->set,
                      NULL,
                      prop, errp);
1319
}
A
Anthony Liguori 已提交
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331

DeviceState *qdev_get_root(void)
{
    static DeviceState *qdev_root;

    if (!qdev_root) {
        qdev_root = qdev_create(NULL, "container");
        qdev_init_nofail(qdev_root);
    }

    return qdev_root;
}
1332

1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
                                    const char *name, Error **errp)
{
    DeviceState *child = opaque;
    gchar *path;

    path = qdev_get_canonical_path(child);
    visit_type_str(v, &path, name, errp);
    g_free(path);
}

1344 1345 1346 1347 1348 1349 1350 1351
static void qdev_release_child_property(DeviceState *dev, const char *name,
                                        void *opaque)
{
    DeviceState *child = opaque;

    qdev_unref(child);
}

1352 1353 1354 1355 1356
void qdev_property_add_child(DeviceState *dev, const char *name,
                             DeviceState *child, Error **errp)
{
    gchar *type;

1357
    type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
1358 1359

    qdev_property_add(dev, name, type, qdev_get_child_property,
1360 1361
                      NULL, qdev_release_child_property,
                      child, errp);
1362 1363

    qdev_ref(child);
1364 1365
    g_assert(child->parent == NULL);
    child->parent = dev;
1366 1367 1368 1369

    g_free(type);
}

A
Anthony Liguori 已提交
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
                                   const char *name, Error **errp)
{
    DeviceState **child = opaque;
    gchar *path;

    if (*child) {
        path = qdev_get_canonical_path(*child);
        visit_type_str(v, &path, name, errp);
        g_free(path);
    } else {
        path = (gchar *)"";
        visit_type_str(v, &path, name, errp);
    }
}

static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
                                   const char *name, Error **errp)
{
    DeviceState **child = opaque;
    bool ambiguous = false;
    const char *type;
    char *path;

    type = qdev_property_get_type(dev, name, NULL);

    visit_type_str(v, &path, name, errp);

    if (*child) {
        qdev_unref(*child);
    }

    if (strcmp(path, "") != 0) {
        DeviceState *target;

        target = qdev_resolve_path(path, &ambiguous);
        if (target) {
            gchar *target_type;

1409
            target_type = g_strdup_printf("link<%s>", object_get_typename(OBJECT(target)));
A
Anthony Liguori 已提交
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
            if (strcmp(target_type, type) == 0) {
                *child = target;
                qdev_ref(target);
            } else {
                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
            }

            g_free(target_type);
        } else {
            error_set(errp, QERR_DEVICE_NOT_FOUND, path);
        }
    } else {
        *child = NULL;
    }

    g_free(path);
}

void qdev_property_add_link(DeviceState *dev, const char *name,
                            const char *type, DeviceState **child,
                            Error **errp)
{
    gchar *full_type;

    full_type = g_strdup_printf("link<%s>", type);

    qdev_property_add(dev, name, full_type,
                      qdev_get_link_property,
                      qdev_set_link_property,
                      NULL, child, errp);

    g_free(full_type);
}

1444
gchar *qdev_get_canonical_path(DeviceState *dev)
1445
{
1446 1447
    DeviceState *root = qdev_get_root();
    char *newpath = NULL, *path = NULL;
1448

1449 1450
    while (dev != root) {
        DeviceProperty *prop = NULL;
1451

1452
        g_assert(dev->parent != NULL);
1453

1454 1455 1456 1457
        QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
            if (!strstart(prop->type, "child<", NULL)) {
                continue;
            }
1458

1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
            if (prop->opaque == dev) {
                if (path) {
                    newpath = g_strdup_printf("%s/%s", prop->name, path);
                    g_free(path);
                    path = newpath;
                } else {
                    path = g_strdup(prop->name);
                }
                break;
            }
1469 1470
        }

1471
        g_assert(prop != NULL);
1472

1473
        dev = dev->parent;
1474 1475 1476 1477 1478 1479 1480
    }

    newpath = g_strdup_printf("/%s", path);
    g_free(path);

    return newpath;
}
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583

static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
                                          gchar **parts,
                                          int index)
{
    DeviceProperty *prop;
    DeviceState *child;

    if (parts[index] == NULL) {
        return parent;
    }

    if (strcmp(parts[index], "") == 0) {
        return qdev_resolve_abs_path(parent, parts, index + 1);
    }

    prop = qdev_property_find(parent, parts[index]);
    if (prop == NULL) {
        return NULL;
    }

    child = NULL;
    if (strstart(prop->type, "link<", NULL)) {
        DeviceState **pchild = prop->opaque;
        if (*pchild) {
            child = *pchild;
        }
    } else if (strstart(prop->type, "child<", NULL)) {
        child = prop->opaque;
    }

    if (!child) {
        return NULL;
    }

    return qdev_resolve_abs_path(child, parts, index + 1);
}

static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
                                              gchar **parts,
                                              bool *ambiguous)
{
    DeviceState *dev;
    DeviceProperty *prop;

    dev = qdev_resolve_abs_path(parent, parts, 0);

    QTAILQ_FOREACH(prop, &parent->properties, node) {
        DeviceState *found;

        if (!strstart(prop->type, "child<", NULL)) {
            continue;
        }

        found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
        if (found) {
            if (dev) {
                if (ambiguous) {
                    *ambiguous = true;
                }
                return NULL;
            }
            dev = found;
        }

        if (ambiguous && *ambiguous) {
            return NULL;
        }
    }

    return dev;
}

DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
{
    bool partial_path = true;
    DeviceState *dev;
    gchar **parts;

    parts = g_strsplit(path, "/", 0);
    if (parts == NULL || parts[0] == NULL) {
        g_strfreev(parts);
        return qdev_get_root();
    }

    if (strcmp(parts[0], "") == 0) {
        partial_path = false;
    }

    if (partial_path) {
        if (ambiguous) {
            *ambiguous = false;
        }
        dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
    } else {
        dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
    }

    g_strfreev(parts);

    return dev;
}

A
Anthony Liguori 已提交
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
typedef struct StringProperty
{
    char *(*get)(DeviceState *, Error **);
    void (*set)(DeviceState *, const char *, Error **);
} StringProperty;

static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
{
    StringProperty *prop = opaque;
    char *value;

    value = prop->get(dev, errp);
    if (value) {
        visit_type_str(v, &value, name, errp);
        g_free(value);
    }
}

static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
{
    StringProperty *prop = opaque;
    char *value;
    Error *local_err = NULL;

    visit_type_str(v, &value, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    prop->set(dev, value, errp);
    g_free(value);
}

static void qdev_property_release_str(DeviceState *dev, const char *name,
                                      void *opaque)
{
    StringProperty *prop = opaque;
    g_free(prop);
}

void qdev_property_add_str(DeviceState *dev, const char *name,
                           char *(*get)(DeviceState *, Error **),
                           void (*set)(DeviceState *, const char *, Error **),
                           Error **errp)
{
    StringProperty *prop = g_malloc0(sizeof(*prop));

    prop->get = get;
    prop->set = set;

    qdev_property_add(dev, name, "string",
                      get ? qdev_property_get_str : NULL,
                      set ? qdev_property_set_str : NULL,
                      qdev_property_release_str,
                      prop, errp);
}
1643 1644 1645 1646 1647 1648

void qdev_machine_init(void)
{
    qdev_get_peripheral_anon();
    qdev_get_peripheral();
}
1649

1650 1651 1652 1653 1654 1655 1656 1657 1658
void device_reset(DeviceState *dev)
{
    DeviceClass *klass = DEVICE_GET_CLASS(dev);

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

1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
static TypeInfo device_type_info = {
    .name = TYPE_DEVICE,
    .parent = TYPE_OBJECT,
    .instance_size = sizeof(DeviceState),
    .abstract = true,
    .class_size = sizeof(DeviceClass),
};

static void init_qdev(void)
{
    type_register_static(&device_type_info);
}

device_init(init_qdev);