Statistics
| Branch: | Revision:

root / qdev-monitor.c @ f4d85795

History | View | Annotate | Download (19.4 kB)

1
/*
2
 *  Dynamic device configuration and creation.
3
 *
4
 *  Copyright (c) 2009 CodeSourcery
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include "hw/qdev.h"
21
#include "hw/sysbus.h"
22
#include "monitor/monitor.h"
23
#include "monitor/qdev.h"
24
#include "qmp-commands.h"
25
#include "sysemu/arch_init.h"
26
#include "qemu/config-file.h"
27

    
28
/*
29
 * Aliases were a bad idea from the start.  Let's keep them
30
 * from spreading further.
31
 */
32
typedef struct QDevAlias
33
{
34
    const char *typename;
35
    const char *alias;
36
    uint32_t arch_mask;
37
} QDevAlias;
38

    
39
static const QDevAlias qdev_alias_table[] = {
40
    { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
41
    { "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
42
    { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
43
    { "virtio-balloon-pci", "virtio-balloon",
44
            QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
45
    { "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X },
46
    { "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X },
47
    { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
48
    { "lsi53c895a", "lsi" },
49
    { "ich9-ahci", "ahci" },
50
    { "kvm-pci-assign", "pci-assign" },
51
    { }
52
};
53

    
54
static const char *qdev_class_get_alias(DeviceClass *dc)
55
{
56
    const char *typename = object_class_get_name(OBJECT_CLASS(dc));
57
    int i;
58

    
59
    for (i = 0; qdev_alias_table[i].typename; i++) {
60
        if (qdev_alias_table[i].arch_mask &&
61
            !(qdev_alias_table[i].arch_mask & arch_type)) {
62
            continue;
63
        }
64

    
65
        if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
66
            return qdev_alias_table[i].alias;
67
        }
68
    }
69

    
70
    return NULL;
71
}
72

    
73
static bool qdev_class_has_alias(DeviceClass *dc)
74
{
75
    return (qdev_class_get_alias(dc) != NULL);
76
}
77

    
78
static void qdev_print_devinfo(DeviceClass *dc)
79
{
80
    error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
81
    if (dc->bus_type) {
82
        error_printf(", bus %s", dc->bus_type);
83
    }
84
    if (qdev_class_has_alias(dc)) {
85
        error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
86
    }
87
    if (dc->desc) {
88
        error_printf(", desc \"%s\"", dc->desc);
89
    }
90
    if (dc->no_user) {
91
        error_printf(", no-user");
92
    }
93
    error_printf("\n");
94
}
95

    
96
static gint devinfo_cmp(gconstpointer a, gconstpointer b)
97
{
98
    return strcasecmp(object_class_get_name((ObjectClass *)a),
99
                      object_class_get_name((ObjectClass *)b));
100
}
101

    
102
static void qdev_print_devinfos(bool show_no_user)
103
{
104
    static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = {
105
        [DEVICE_CATEGORY_BRIDGE]  = "Controller/Bridge/Hub",
106
        [DEVICE_CATEGORY_USB]     = "USB",
107
        [DEVICE_CATEGORY_STORAGE] = "Storage",
108
        [DEVICE_CATEGORY_NETWORK] = "Network",
109
        [DEVICE_CATEGORY_INPUT]   = "Input",
110
        [DEVICE_CATEGORY_DISPLAY] = "Display",
111
        [DEVICE_CATEGORY_SOUND]   = "Sound",
112
        [DEVICE_CATEGORY_MISC]    = "Misc",
113
        [DEVICE_CATEGORY_MAX]     = "Uncategorized",
114
    };
115
    GSList *list, *elt;
116
    int i;
117
    bool cat_printed;
118

    
119
    list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false),
120
                        devinfo_cmp);
121

    
122
    for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
123
        cat_printed = false;
124
        for (elt = list; elt; elt = elt->next) {
125
            DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
126
                                                 TYPE_DEVICE);
127
            if ((i < DEVICE_CATEGORY_MAX
128
                 ? !test_bit(i, dc->categories)
129
                 : !bitmap_empty(dc->categories, DEVICE_CATEGORY_MAX))
130
                || (!show_no_user && dc->no_user)) {
131
                continue;
132
            }
133
            if (!cat_printed) {
134
                error_printf("%s%s devices:\n", i ? "\n" : "",
135
                             cat_name[i]);
136
                cat_printed = true;
137
            }
138
            qdev_print_devinfo(dc);
139
        }
140
    }
141

    
142
    g_slist_free(list);
143
}
144

    
145
static int set_property(const char *name, const char *value, void *opaque)
146
{
147
    DeviceState *dev = opaque;
148
    Error *err = NULL;
149

    
150
    if (strcmp(name, "driver") == 0)
151
        return 0;
152
    if (strcmp(name, "bus") == 0)
153
        return 0;
154

    
155
    qdev_prop_parse(dev, name, value, &err);
156
    if (err != NULL) {
157
        qerror_report_err(err);
158
        error_free(err);
159
        return -1;
160
    }
161
    return 0;
162
}
163

    
164
static const char *find_typename_by_alias(const char *alias)
165
{
166
    int i;
167

    
168
    for (i = 0; qdev_alias_table[i].alias; i++) {
169
        if (qdev_alias_table[i].arch_mask &&
170
            !(qdev_alias_table[i].arch_mask & arch_type)) {
171
            continue;
172
        }
173

    
174
        if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
175
            return qdev_alias_table[i].typename;
176
        }
177
    }
178

    
179
    return NULL;
180
}
181

    
182
int qdev_device_help(QemuOpts *opts)
183
{
184
    const char *driver;
185
    Property *prop;
186
    ObjectClass *klass;
187

    
188
    driver = qemu_opt_get(opts, "driver");
189
    if (driver && is_help_option(driver)) {
190
        qdev_print_devinfos(false);
191
        return 1;
192
    }
193

    
194
    if (!driver || !qemu_opt_has_help_opt(opts)) {
195
        return 0;
196
    }
197

    
198
    klass = object_class_by_name(driver);
199
    if (!klass) {
200
        const char *typename = find_typename_by_alias(driver);
201

    
202
        if (typename) {
203
            driver = typename;
204
            klass = object_class_by_name(driver);
205
        }
206
    }
207

    
208
    if (!klass) {
209
        return 0;
210
    }
211
    do {
212
        for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
213
            /*
214
             * TODO Properties without a parser are just for dirty hacks.
215
             * qdev_prop_ptr is the only such PropertyInfo.  It's marked
216
             * for removal.  This conditional should be removed along with
217
             * it.
218
             */
219
            if (!prop->info->set) {
220
                continue;           /* no way to set it, don't show */
221
            }
222
            error_printf("%s.%s=%s\n", driver, prop->name,
223
                         prop->info->legacy_name ?: prop->info->name);
224
        }
225
        klass = object_class_get_parent(klass);
226
    } while (klass != object_class_by_name(TYPE_DEVICE));
227
    return 1;
228
}
229

    
230
static Object *qdev_get_peripheral(void)
231
{
232
    static Object *dev;
233

    
234
    if (dev == NULL) {
235
        dev = container_get(qdev_get_machine(), "/peripheral");
236
    }
237

    
238
    return dev;
239
}
240

    
241
static Object *qdev_get_peripheral_anon(void)
242
{
243
    static Object *dev;
244

    
245
    if (dev == NULL) {
246
        dev = container_get(qdev_get_machine(), "/peripheral-anon");
247
    }
248

    
249
    return dev;
250
}
251

    
252
static void qbus_list_bus(DeviceState *dev)
253
{
254
    BusState *child;
255
    const char *sep = " ";
256

    
257
    error_printf("child busses at \"%s\":",
258
                 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
259
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
260
        error_printf("%s\"%s\"", sep, child->name);
261
        sep = ", ";
262
    }
263
    error_printf("\n");
264
}
265

    
266
static void qbus_list_dev(BusState *bus)
267
{
268
    BusChild *kid;
269
    const char *sep = " ";
270

    
271
    error_printf("devices at \"%s\":", bus->name);
272
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
273
        DeviceState *dev = kid->child;
274
        error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
275
        if (dev->id)
276
            error_printf("/\"%s\"", dev->id);
277
        sep = ", ";
278
    }
279
    error_printf("\n");
280
}
281

    
282
static BusState *qbus_find_bus(DeviceState *dev, char *elem)
283
{
284
    BusState *child;
285

    
286
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
287
        if (strcmp(child->name, elem) == 0) {
288
            return child;
289
        }
290
    }
291
    return NULL;
292
}
293

    
294
static DeviceState *qbus_find_dev(BusState *bus, char *elem)
295
{
296
    BusChild *kid;
297

    
298
    /*
299
     * try to match in order:
300
     *   (1) instance id, if present
301
     *   (2) driver name
302
     *   (3) driver alias, if present
303
     */
304
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
305
        DeviceState *dev = kid->child;
306
        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
307
            return dev;
308
        }
309
    }
310
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
311
        DeviceState *dev = kid->child;
312
        if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
313
            return dev;
314
        }
315
    }
316
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
317
        DeviceState *dev = kid->child;
318
        DeviceClass *dc = DEVICE_GET_CLASS(dev);
319

    
320
        if (qdev_class_has_alias(dc) &&
321
            strcmp(qdev_class_get_alias(dc), elem) == 0) {
322
            return dev;
323
        }
324
    }
325
    return NULL;
326
}
327

    
328
static BusState *qbus_find_recursive(BusState *bus, const char *name,
329
                                     const char *bus_typename)
330
{
331
    BusClass *bus_class = BUS_GET_CLASS(bus);
332
    BusChild *kid;
333
    BusState *child, *ret;
334
    int match = 1;
335

    
336
    if (name && (strcmp(bus->name, name) != 0)) {
337
        match = 0;
338
    } else if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) {
339
        match = 0;
340
    } else if ((bus_class->max_dev != 0) && (bus_class->max_dev <= bus->max_index)) {
341
        if (name != NULL) {
342
            /* bus was explicitly specified: return an error. */
343
            qerror_report(ERROR_CLASS_GENERIC_ERROR, "Bus '%s' is full",
344
                          bus->name);
345
            return NULL;
346
        } else {
347
            /* bus was not specified: try to find another one. */
348
            match = 0;
349
        }
350
    }
351
    if (match) {
352
        return bus;
353
    }
354

    
355
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
356
        DeviceState *dev = kid->child;
357
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
358
            ret = qbus_find_recursive(child, name, bus_typename);
359
            if (ret) {
360
                return ret;
361
            }
362
        }
363
    }
364
    return NULL;
365
}
366

    
367
static BusState *qbus_find(const char *path)
368
{
369
    DeviceState *dev;
370
    BusState *bus;
371
    char elem[128];
372
    int pos, len;
373

    
374
    /* find start element */
375
    if (path[0] == '/') {
376
        bus = sysbus_get_default();
377
        pos = 0;
378
    } else {
379
        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
380
            assert(!path[0]);
381
            elem[0] = len = 0;
382
        }
383
        bus = qbus_find_recursive(sysbus_get_default(), elem, NULL);
384
        if (!bus) {
385
            qerror_report(QERR_BUS_NOT_FOUND, elem);
386
            return NULL;
387
        }
388
        pos = len;
389
    }
390

    
391
    for (;;) {
392
        assert(path[pos] == '/' || !path[pos]);
393
        while (path[pos] == '/') {
394
            pos++;
395
        }
396
        if (path[pos] == '\0') {
397
            return bus;
398
        }
399

    
400
        /* find device */
401
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
402
            g_assert_not_reached();
403
            elem[0] = len = 0;
404
        }
405
        pos += len;
406
        dev = qbus_find_dev(bus, elem);
407
        if (!dev) {
408
            qerror_report(QERR_DEVICE_NOT_FOUND, elem);
409
            if (!monitor_cur_is_qmp()) {
410
                qbus_list_dev(bus);
411
            }
412
            return NULL;
413
        }
414

    
415
        assert(path[pos] == '/' || !path[pos]);
416
        while (path[pos] == '/') {
417
            pos++;
418
        }
419
        if (path[pos] == '\0') {
420
            /* last specified element is a device.  If it has exactly
421
             * one child bus accept it nevertheless */
422
            switch (dev->num_child_bus) {
423
            case 0:
424
                qerror_report(QERR_DEVICE_NO_BUS, elem);
425
                return NULL;
426
            case 1:
427
                return QLIST_FIRST(&dev->child_bus);
428
            default:
429
                qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
430
                if (!monitor_cur_is_qmp()) {
431
                    qbus_list_bus(dev);
432
                }
433
                return NULL;
434
            }
435
        }
436

    
437
        /* find bus */
438
        if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
439
            g_assert_not_reached();
440
            elem[0] = len = 0;
441
        }
442
        pos += len;
443
        bus = qbus_find_bus(dev, elem);
444
        if (!bus) {
445
            qerror_report(QERR_BUS_NOT_FOUND, elem);
446
            if (!monitor_cur_is_qmp()) {
447
                qbus_list_bus(dev);
448
            }
449
            return NULL;
450
        }
451
    }
452
}
453

    
454
DeviceState *qdev_device_add(QemuOpts *opts)
455
{
456
    ObjectClass *oc;
457
    DeviceClass *dc;
458
    const char *driver, *path, *id;
459
    DeviceState *qdev;
460
    BusState *bus = NULL;
461

    
462
    driver = qemu_opt_get(opts, "driver");
463
    if (!driver) {
464
        qerror_report(QERR_MISSING_PARAMETER, "driver");
465
        return NULL;
466
    }
467

    
468
    /* find driver */
469
    oc = object_class_by_name(driver);
470
    if (!oc) {
471
        const char *typename = find_typename_by_alias(driver);
472

    
473
        if (typename) {
474
            driver = typename;
475
            oc = object_class_by_name(driver);
476
        }
477
    }
478

    
479
    if (!oc) {
480
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
481
        return NULL;
482
    }
483

    
484
    dc = DEVICE_CLASS(oc);
485

    
486
    /* find bus */
487
    path = qemu_opt_get(opts, "bus");
488
    if (path != NULL) {
489
        bus = qbus_find(path);
490
        if (!bus) {
491
            return NULL;
492
        }
493
        if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) {
494
            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
495
                          driver, object_get_typename(OBJECT(bus)));
496
            return NULL;
497
        }
498
    } else if (dc->bus_type != NULL) {
499
        bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type);
500
        if (!bus) {
501
            qerror_report(QERR_NO_BUS_FOR_DEVICE,
502
                          dc->bus_type, driver);
503
            return NULL;
504
        }
505
    }
506
    if (qdev_hotplug && bus && !bus->allow_hotplug) {
507
        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
508
        return NULL;
509
    }
510

    
511
    /* create device, set properties */
512
    qdev = DEVICE(object_new(driver));
513

    
514
    if (bus) {
515
        qdev_set_parent_bus(qdev, bus);
516
    }
517

    
518
    id = qemu_opts_id(opts);
519
    if (id) {
520
        qdev->id = id;
521
    }
522
    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
523
        qdev_free(qdev);
524
        return NULL;
525
    }
526
    if (qdev->id) {
527
        object_property_add_child(qdev_get_peripheral(), qdev->id,
528
                                  OBJECT(qdev), NULL);
529
    } else {
530
        static int anon_count;
531
        gchar *name = g_strdup_printf("device[%d]", anon_count++);
532
        object_property_add_child(qdev_get_peripheral_anon(), name,
533
                                  OBJECT(qdev), NULL);
534
        g_free(name);
535
    }        
536
    if (qdev_init(qdev) < 0) {
537
        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
538
        return NULL;
539
    }
540
    qdev->opts = opts;
541
    return qdev;
542
}
543

    
544

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

    
548
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
549
                             int indent)
550
{
551
    if (!props)
552
        return;
553
    for (; props->name; props++) {
554
        Error *err = NULL;
555
        char *value;
556
        char *legacy_name = g_strdup_printf("legacy-%s", props->name);
557
        if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
558
            value = object_property_get_str(OBJECT(dev), legacy_name, &err);
559
        } else {
560
            value = object_property_print(OBJECT(dev), props->name, &err);
561
        }
562
        g_free(legacy_name);
563

    
564
        if (err) {
565
            error_free(err);
566
            continue;
567
        }
568
        qdev_printf("%s = %s\n", props->name,
569
                    value && *value ? value : "<null>");
570
        g_free(value);
571
    }
572
}
573

    
574
static void bus_print_dev(BusState *bus, Monitor *mon, DeviceState *dev, int indent)
575
{
576
    BusClass *bc = BUS_GET_CLASS(bus);
577

    
578
    if (bc->print_dev) {
579
        bc->print_dev(mon, dev, indent);
580
    }
581
}
582

    
583
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
584
{
585
    ObjectClass *class;
586
    BusState *child;
587
    qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
588
                dev->id ? dev->id : "");
589
    indent += 2;
590
    if (dev->num_gpio_in) {
591
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
592
    }
593
    if (dev->num_gpio_out) {
594
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
595
    }
596
    class = object_get_class(OBJECT(dev));
597
    do {
598
        qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
599
        class = object_class_get_parent(class);
600
    } while (class != object_class_by_name(TYPE_DEVICE));
601
    bus_print_dev(dev->parent_bus, mon, dev, indent);
602
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
603
        qbus_print(mon, child, indent);
604
    }
605
}
606

    
607
static void qbus_print(Monitor *mon, BusState *bus, int indent)
608
{
609
    BusChild *kid;
610

    
611
    qdev_printf("bus: %s\n", bus->name);
612
    indent += 2;
613
    qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
614
    QTAILQ_FOREACH(kid, &bus->children, sibling) {
615
        DeviceState *dev = kid->child;
616
        qdev_print(mon, dev, indent);
617
    }
618
}
619
#undef qdev_printf
620

    
621
void do_info_qtree(Monitor *mon, const QDict *qdict)
622
{
623
    if (sysbus_get_default())
624
        qbus_print(mon, sysbus_get_default(), 0);
625
}
626

    
627
void do_info_qdm(Monitor *mon, const QDict *qdict)
628
{
629
    qdev_print_devinfos(true);
630
}
631

    
632
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
633
{
634
    Error *local_err = NULL;
635
    QemuOpts *opts;
636
    DeviceState *dev;
637

    
638
    opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
639
    if (error_is_set(&local_err)) {
640
        qerror_report_err(local_err);
641
        error_free(local_err);
642
        return -1;
643
    }
644
    if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
645
        qemu_opts_del(opts);
646
        return 0;
647
    }
648
    dev = qdev_device_add(opts);
649
    if (!dev) {
650
        qemu_opts_del(opts);
651
        return -1;
652
    }
653
    object_unref(OBJECT(dev));
654
    return 0;
655
}
656

    
657
void qmp_device_del(const char *id, Error **errp)
658
{
659
    DeviceState *dev;
660

    
661
    dev = qdev_find_recursive(sysbus_get_default(), id);
662
    if (NULL == dev) {
663
        error_set(errp, QERR_DEVICE_NOT_FOUND, id);
664
        return;
665
    }
666

    
667
    qdev_unplug(dev, errp);
668
}
669

    
670
void qdev_machine_init(void)
671
{
672
    qdev_get_peripheral_anon();
673
    qdev_get_peripheral();
674
}
675

    
676
QemuOptsList qemu_device_opts = {
677
    .name = "device",
678
    .implied_opt_name = "driver",
679
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
680
    .desc = {
681
        /*
682
         * no elements => accept any
683
         * sanity checking will happen later
684
         * when setting device properties
685
         */
686
        { /* end of list */ }
687
    },
688
};
689

    
690
QemuOptsList qemu_global_opts = {
691
    .name = "global",
692
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
693
    .desc = {
694
        {
695
            .name = "driver",
696
            .type = QEMU_OPT_STRING,
697
        },{
698
            .name = "property",
699
            .type = QEMU_OPT_STRING,
700
        },{
701
            .name = "value",
702
            .type = QEMU_OPT_STRING,
703
        },
704
        { /* end of list */ }
705
    },
706
};
707

    
708
int qemu_global_option(const char *str)
709
{
710
    char driver[64], property[64];
711
    QemuOpts *opts;
712
    int rc, offset;
713

    
714
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
715
    if (rc < 2 || str[offset] != '=') {
716
        error_report("can't parse: \"%s\"", str);
717
        return -1;
718
    }
719

    
720
    opts = qemu_opts_create_nofail(&qemu_global_opts);
721
    qemu_opt_set(opts, "driver", driver);
722
    qemu_opt_set(opts, "property", property);
723
    qemu_opt_set(opts, "value", str+offset+1);
724
    return 0;
725
}