Statistics
| Branch: | Revision:

root / hw / qdev.c @ d29275f1

History | View | Annotate | Download (17.8 kB)

1 aae9460e Paul Brook
/*
2 aae9460e Paul Brook
 *  Dynamic device configuration and creation.
3 aae9460e Paul Brook
 *
4 aae9460e Paul Brook
 *  Copyright (c) 2009 CodeSourcery
5 aae9460e Paul Brook
 *
6 aae9460e Paul Brook
 * This library is free software; you can redistribute it and/or
7 aae9460e Paul Brook
 * modify it under the terms of the GNU Lesser General Public
8 aae9460e Paul Brook
 * License as published by the Free Software Foundation; either
9 aae9460e Paul Brook
 * version 2 of the License, or (at your option) any later version.
10 aae9460e Paul Brook
 *
11 aae9460e Paul Brook
 * This library is distributed in the hope that it will be useful,
12 aae9460e Paul Brook
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 aae9460e Paul Brook
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 aae9460e Paul Brook
 * Lesser General Public License for more details.
15 aae9460e Paul Brook
 *
16 aae9460e Paul Brook
 * You should have received a copy of the GNU Lesser General Public
17 8167ee88 Blue Swirl
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 aae9460e Paul Brook
 */
19 aae9460e Paul Brook
20 aae9460e Paul Brook
/* The theory here is that it should be possible to create a machine without
21 aae9460e Paul Brook
   knowledge of specific devices.  Historically board init routines have
22 aae9460e Paul Brook
   passed a bunch of arguments to each device, requiring the board know
23 aae9460e Paul Brook
   exactly which device it is dealing with.  This file provides an abstract
24 aae9460e Paul Brook
   API for device configuration and initialization.  Devices will generally
25 aae9460e Paul Brook
   inherit from a particular bus (e.g. PCI or I2C) rather than
26 aae9460e Paul Brook
   this API directly.  */
27 aae9460e Paul Brook
28 9d07d757 Paul Brook
#include "net.h"
29 aae9460e Paul Brook
#include "qdev.h"
30 aae9460e Paul Brook
#include "sysemu.h"
31 cae4956e Gerd Hoffmann
#include "monitor.h"
32 aae9460e Paul Brook
33 02e2da45 Paul Brook
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
34 b9aaf7f8 Blue Swirl
static BusState *main_system_bus;
35 4d6ae674 Paul Brook
36 042f84d0 Gerd Hoffmann
static DeviceInfo *device_info_list;
37 aae9460e Paul Brook
38 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find_recursive(BusState *bus, const char *name,
39 8ffb1bcf Gerd Hoffmann
                                     const BusInfo *info);
40 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find(const char *path);
41 8ffb1bcf Gerd Hoffmann
42 aae9460e Paul Brook
/* Register a new device type.  */
43 074f2fff Gerd Hoffmann
void qdev_register(DeviceInfo *info)
44 aae9460e Paul Brook
{
45 074f2fff Gerd Hoffmann
    assert(info->size >= sizeof(DeviceState));
46 042f84d0 Gerd Hoffmann
    assert(!info->next);
47 aae9460e Paul Brook
48 042f84d0 Gerd Hoffmann
    info->next = device_info_list;
49 042f84d0 Gerd Hoffmann
    device_info_list = info;
50 aae9460e Paul Brook
}
51 aae9460e Paul Brook
52 81ebb98b Gerd Hoffmann
static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
53 81ebb98b Gerd Hoffmann
{
54 81ebb98b Gerd Hoffmann
    DeviceInfo *info;
55 81ebb98b Gerd Hoffmann
56 3320e56e Gerd Hoffmann
    /* first check device names */
57 81ebb98b Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
58 81ebb98b Gerd Hoffmann
        if (bus_info && info->bus_info != bus_info)
59 81ebb98b Gerd Hoffmann
            continue;
60 81ebb98b Gerd Hoffmann
        if (strcmp(info->name, name) != 0)
61 81ebb98b Gerd Hoffmann
            continue;
62 81ebb98b Gerd Hoffmann
        return info;
63 81ebb98b Gerd Hoffmann
    }
64 3320e56e Gerd Hoffmann
65 3320e56e Gerd Hoffmann
    /* failing that check the aliases */
66 3320e56e Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
67 3320e56e Gerd Hoffmann
        if (bus_info && info->bus_info != bus_info)
68 3320e56e Gerd Hoffmann
            continue;
69 3320e56e Gerd Hoffmann
        if (!info->alias)
70 3320e56e Gerd Hoffmann
            continue;
71 3320e56e Gerd Hoffmann
        if (strcmp(info->alias, name) != 0)
72 3320e56e Gerd Hoffmann
            continue;
73 3320e56e Gerd Hoffmann
        return info;
74 3320e56e Gerd Hoffmann
    }
75 81ebb98b Gerd Hoffmann
    return NULL;
76 81ebb98b Gerd Hoffmann
}
77 81ebb98b Gerd Hoffmann
78 aae9460e Paul Brook
/* Create a new device.  This only initializes the device state structure
79 aae9460e Paul Brook
   and allows properties to be set.  qdev_init should be called to
80 aae9460e Paul Brook
   initialize the actual device emulation.  */
81 02e2da45 Paul Brook
DeviceState *qdev_create(BusState *bus, const char *name)
82 aae9460e Paul Brook
{
83 042f84d0 Gerd Hoffmann
    DeviceInfo *info;
84 aae9460e Paul Brook
    DeviceState *dev;
85 aae9460e Paul Brook
86 10c4c98a Gerd Hoffmann
    if (!bus) {
87 10c4c98a Gerd Hoffmann
        if (!main_system_bus) {
88 10c4c98a Gerd Hoffmann
            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
89 aae9460e Paul Brook
        }
90 10c4c98a Gerd Hoffmann
        bus = main_system_bus;
91 10c4c98a Gerd Hoffmann
    }
92 10c4c98a Gerd Hoffmann
93 81ebb98b Gerd Hoffmann
    info = qdev_find_info(bus->info, name);
94 042f84d0 Gerd Hoffmann
    if (!info) {
95 10c4c98a Gerd Hoffmann
        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
96 aae9460e Paul Brook
    }
97 aae9460e Paul Brook
98 042f84d0 Gerd Hoffmann
    dev = qemu_mallocz(info->size);
99 042f84d0 Gerd Hoffmann
    dev->info = info;
100 02e2da45 Paul Brook
    dev->parent_bus = bus;
101 ee6847d1 Gerd Hoffmann
    qdev_prop_set_defaults(dev, dev->info->props);
102 ee6847d1 Gerd Hoffmann
    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
103 b6b61144 Gerd Hoffmann
    qdev_prop_set_compat(dev);
104 72cf2d4f Blue Swirl
    QLIST_INSERT_HEAD(&bus->children, dev, sibling);
105 131ec1bd Gerd Hoffmann
    dev->state = DEV_STATE_CREATED;
106 aae9460e Paul Brook
    return dev;
107 aae9460e Paul Brook
}
108 aae9460e Paul Brook
109 1b524b04 Gerd Hoffmann
static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
110 1b524b04 Gerd Hoffmann
{
111 1b524b04 Gerd Hoffmann
    int pos = 0;
112 22f2e344 Gerd Hoffmann
    int ret;
113 22f2e344 Gerd Hoffmann
114 22f2e344 Gerd Hoffmann
    ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
115 22f2e344 Gerd Hoffmann
                   info->name, info->bus_info->name);
116 22f2e344 Gerd Hoffmann
    pos += MIN(len-pos,ret);
117 22f2e344 Gerd Hoffmann
    if (info->alias) {
118 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
119 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
120 22f2e344 Gerd Hoffmann
    }
121 22f2e344 Gerd Hoffmann
    if (info->desc) {
122 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
123 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
124 22f2e344 Gerd Hoffmann
    }
125 22f2e344 Gerd Hoffmann
    if (info->no_user) {
126 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", no-user");
127 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
128 22f2e344 Gerd Hoffmann
    }
129 1b524b04 Gerd Hoffmann
    return pos;
130 1b524b04 Gerd Hoffmann
}
131 1b524b04 Gerd Hoffmann
132 f31d07d1 Gerd Hoffmann
static int set_property(const char *name, const char *value, void *opaque)
133 8ffb1bcf Gerd Hoffmann
{
134 f31d07d1 Gerd Hoffmann
    DeviceState *dev = opaque;
135 f31d07d1 Gerd Hoffmann
136 f31d07d1 Gerd Hoffmann
    if (strcmp(name, "driver") == 0)
137 f31d07d1 Gerd Hoffmann
        return 0;
138 f31d07d1 Gerd Hoffmann
    if (strcmp(name, "bus") == 0)
139 f31d07d1 Gerd Hoffmann
        return 0;
140 f31d07d1 Gerd Hoffmann
141 3df04ac3 Mark McLoughlin
    if (qdev_prop_parse(dev, name, value) == -1) {
142 286c2321 Gerd Hoffmann
        qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
143 286c2321 Gerd Hoffmann
                   name, value, dev->info->name);
144 f31d07d1 Gerd Hoffmann
        return -1;
145 f31d07d1 Gerd Hoffmann
    }
146 f31d07d1 Gerd Hoffmann
    return 0;
147 f31d07d1 Gerd Hoffmann
}
148 f31d07d1 Gerd Hoffmann
149 f31d07d1 Gerd Hoffmann
DeviceState *qdev_device_add(QemuOpts *opts)
150 f31d07d1 Gerd Hoffmann
{
151 f31d07d1 Gerd Hoffmann
    const char *driver, *path, *id;
152 8ffb1bcf Gerd Hoffmann
    DeviceInfo *info;
153 8ffb1bcf Gerd Hoffmann
    DeviceState *qdev;
154 8ffb1bcf Gerd Hoffmann
    BusState *bus;
155 8ffb1bcf Gerd Hoffmann
156 f31d07d1 Gerd Hoffmann
    driver = qemu_opt_get(opts, "driver");
157 f31d07d1 Gerd Hoffmann
    if (!driver) {
158 286c2321 Gerd Hoffmann
        qemu_error("-device: no driver specified\n");
159 8ffb1bcf Gerd Hoffmann
        return NULL;
160 8ffb1bcf Gerd Hoffmann
    }
161 8ffb1bcf Gerd Hoffmann
    if (strcmp(driver, "?") == 0) {
162 1b524b04 Gerd Hoffmann
        char msg[256];
163 8ffb1bcf Gerd Hoffmann
        for (info = device_info_list; info != NULL; info = info->next) {
164 1b524b04 Gerd Hoffmann
            qdev_print_devinfo(info, msg, sizeof(msg));
165 286c2321 Gerd Hoffmann
            qemu_error("%s\n", msg);
166 8ffb1bcf Gerd Hoffmann
        }
167 8ffb1bcf Gerd Hoffmann
        return NULL;
168 8ffb1bcf Gerd Hoffmann
    }
169 f31d07d1 Gerd Hoffmann
170 f31d07d1 Gerd Hoffmann
    /* find driver */
171 8ffb1bcf Gerd Hoffmann
    info = qdev_find_info(NULL, driver);
172 8ffb1bcf Gerd Hoffmann
    if (!info) {
173 286c2321 Gerd Hoffmann
        qemu_error("Device \"%s\" not found.  Try -device '?' for a list.\n",
174 286c2321 Gerd Hoffmann
                   driver);
175 8ffb1bcf Gerd Hoffmann
        return NULL;
176 8ffb1bcf Gerd Hoffmann
    }
177 8ffb1bcf Gerd Hoffmann
    if (info->no_user) {
178 286c2321 Gerd Hoffmann
        qemu_error("device \"%s\" can't be added via command line\n",
179 286c2321 Gerd Hoffmann
                   info->name);
180 8ffb1bcf Gerd Hoffmann
        return NULL;
181 8ffb1bcf Gerd Hoffmann
    }
182 8ffb1bcf Gerd Hoffmann
183 f31d07d1 Gerd Hoffmann
    /* find bus */
184 f31d07d1 Gerd Hoffmann
    path = qemu_opt_get(opts, "bus");
185 f31d07d1 Gerd Hoffmann
    if (path != NULL) {
186 8ffb1bcf Gerd Hoffmann
        bus = qbus_find(path);
187 8ffb1bcf Gerd Hoffmann
    } else {
188 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
189 8ffb1bcf Gerd Hoffmann
    }
190 75570088 Gerd Hoffmann
    if (!bus) {
191 75570088 Gerd Hoffmann
        qemu_error("Did not find %s bus for %s\n",
192 75570088 Gerd Hoffmann
                   path ? path : info->bus_info->name, info->name);
193 f31d07d1 Gerd Hoffmann
        return NULL;
194 75570088 Gerd Hoffmann
    }
195 8ffb1bcf Gerd Hoffmann
196 f31d07d1 Gerd Hoffmann
    /* create device, set properties */
197 f31d07d1 Gerd Hoffmann
    qdev = qdev_create(bus, driver);
198 f31d07d1 Gerd Hoffmann
    id = qemu_opts_id(opts);
199 f31d07d1 Gerd Hoffmann
    if (id) {
200 f31d07d1 Gerd Hoffmann
        qdev->id = id;
201 f31d07d1 Gerd Hoffmann
    }
202 f31d07d1 Gerd Hoffmann
    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
203 f31d07d1 Gerd Hoffmann
        qdev_free(qdev);
204 f31d07d1 Gerd Hoffmann
        return NULL;
205 8ffb1bcf Gerd Hoffmann
    }
206 81a322d4 Gerd Hoffmann
    if (qdev_init(qdev) != 0) {
207 81a322d4 Gerd Hoffmann
        qdev_free(qdev);
208 81a322d4 Gerd Hoffmann
        return NULL;
209 81a322d4 Gerd Hoffmann
    }
210 8ffb1bcf Gerd Hoffmann
    return qdev;
211 8ffb1bcf Gerd Hoffmann
}
212 8ffb1bcf Gerd Hoffmann
213 aae9460e Paul Brook
/* Initialize a device.  Device properties should be set before calling
214 aae9460e Paul Brook
   this function.  IRQs and MMIO regions should be connected/mapped after
215 aae9460e Paul Brook
   calling this function.  */
216 81a322d4 Gerd Hoffmann
int qdev_init(DeviceState *dev)
217 aae9460e Paul Brook
{
218 959f733a Gerd Hoffmann
    int rc;
219 959f733a Gerd Hoffmann
220 131ec1bd Gerd Hoffmann
    assert(dev->state == DEV_STATE_CREATED);
221 959f733a Gerd Hoffmann
    rc = dev->info->init(dev, dev->info);
222 959f733a Gerd Hoffmann
    if (rc < 0)
223 959f733a Gerd Hoffmann
        return rc;
224 959f733a Gerd Hoffmann
    if (dev->info->reset)
225 959f733a Gerd Hoffmann
        qemu_register_reset(dev->info->reset, dev);
226 391a079e Gerd Hoffmann
    if (dev->info->vmsd)
227 391a079e Gerd Hoffmann
        vmstate_register(-1, dev->info->vmsd, dev);
228 131ec1bd Gerd Hoffmann
    dev->state = DEV_STATE_INITIALIZED;
229 959f733a Gerd Hoffmann
    return 0;
230 02e2da45 Paul Brook
}
231 02e2da45 Paul Brook
232 02e2da45 Paul Brook
/* Unlink device from bus and free the structure.  */
233 02e2da45 Paul Brook
void qdev_free(DeviceState *dev)
234 02e2da45 Paul Brook
{
235 131ec1bd Gerd Hoffmann
    BusState *bus;
236 131ec1bd Gerd Hoffmann
237 131ec1bd Gerd Hoffmann
    if (dev->state == DEV_STATE_INITIALIZED) {
238 131ec1bd Gerd Hoffmann
        while (dev->num_child_bus) {
239 131ec1bd Gerd Hoffmann
            bus = QLIST_FIRST(&dev->child_bus);
240 131ec1bd Gerd Hoffmann
            qbus_free(bus);
241 131ec1bd Gerd Hoffmann
        }
242 391a079e Gerd Hoffmann
#if 0 /* FIXME: need sane vmstate_unregister function */
243 131ec1bd Gerd Hoffmann
        if (dev->info->vmsd)
244 131ec1bd Gerd Hoffmann
            vmstate_unregister(dev->info->vmsd, dev);
245 391a079e Gerd Hoffmann
#endif
246 131ec1bd Gerd Hoffmann
        if (dev->info->reset)
247 131ec1bd Gerd Hoffmann
            qemu_unregister_reset(dev->info->reset, dev);
248 d29275f1 Gerd Hoffmann
        if (dev->info->exit)
249 d29275f1 Gerd Hoffmann
            dev->info->exit(dev);
250 131ec1bd Gerd Hoffmann
    }
251 72cf2d4f Blue Swirl
    QLIST_REMOVE(dev, sibling);
252 ccb63de3 Gerd Hoffmann
    qemu_free(dev);
253 aae9460e Paul Brook
}
254 aae9460e Paul Brook
255 aae9460e Paul Brook
/* Get a character (serial) device interface.  */
256 aae9460e Paul Brook
CharDriverState *qdev_init_chardev(DeviceState *dev)
257 aae9460e Paul Brook
{
258 aae9460e Paul Brook
    static int next_serial;
259 aae9460e Paul Brook
    static int next_virtconsole;
260 aae9460e Paul Brook
    /* FIXME: This is a nasty hack that needs to go away.  */
261 042f84d0 Gerd Hoffmann
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
262 aae9460e Paul Brook
        return virtcon_hds[next_virtconsole++];
263 aae9460e Paul Brook
    } else {
264 aae9460e Paul Brook
        return serial_hds[next_serial++];
265 aae9460e Paul Brook
    }
266 aae9460e Paul Brook
}
267 aae9460e Paul Brook
268 02e2da45 Paul Brook
BusState *qdev_get_parent_bus(DeviceState *dev)
269 aae9460e Paul Brook
{
270 02e2da45 Paul Brook
    return dev->parent_bus;
271 aae9460e Paul Brook
}
272 aae9460e Paul Brook
273 aae9460e Paul Brook
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
274 aae9460e Paul Brook
{
275 aae9460e Paul Brook
    assert(dev->num_gpio_in == 0);
276 aae9460e Paul Brook
    dev->num_gpio_in = n;
277 aae9460e Paul Brook
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
278 aae9460e Paul Brook
}
279 aae9460e Paul Brook
280 aae9460e Paul Brook
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
281 aae9460e Paul Brook
{
282 aae9460e Paul Brook
    assert(dev->num_gpio_out == 0);
283 aae9460e Paul Brook
    dev->num_gpio_out = n;
284 aae9460e Paul Brook
    dev->gpio_out = pins;
285 aae9460e Paul Brook
}
286 aae9460e Paul Brook
287 aae9460e Paul Brook
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
288 aae9460e Paul Brook
{
289 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_in);
290 aae9460e Paul Brook
    return dev->gpio_in[n];
291 aae9460e Paul Brook
}
292 aae9460e Paul Brook
293 aae9460e Paul Brook
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
294 aae9460e Paul Brook
{
295 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_out);
296 aae9460e Paul Brook
    dev->gpio_out[n] = pin;
297 aae9460e Paul Brook
}
298 aae9460e Paul Brook
299 9d07d757 Paul Brook
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
300 cda9046b Mark McLoughlin
                                      NetCanReceive *can_receive,
301 cda9046b Mark McLoughlin
                                      NetReceive *receive,
302 cda9046b Mark McLoughlin
                                      NetReceiveIOV *receive_iov,
303 9d07d757 Paul Brook
                                      NetCleanup *cleanup,
304 9d07d757 Paul Brook
                                      void *opaque)
305 9d07d757 Paul Brook
{
306 9d07d757 Paul Brook
    NICInfo *nd = dev->nd;
307 9d07d757 Paul Brook
    assert(nd);
308 ae50b274 Mark McLoughlin
    nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
309 ae50b274 Mark McLoughlin
                                  receive, receive_iov, cleanup, opaque);
310 ae50b274 Mark McLoughlin
    return nd->vc;
311 9d07d757 Paul Brook
}
312 9d07d757 Paul Brook
313 9d07d757 Paul Brook
314 9d07d757 Paul Brook
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
315 9d07d757 Paul Brook
{
316 9d07d757 Paul Brook
    memcpy(macaddr, dev->nd->macaddr, 6);
317 9d07d757 Paul Brook
}
318 9d07d757 Paul Brook
319 aae9460e Paul Brook
static int next_block_unit[IF_COUNT];
320 aae9460e Paul Brook
321 aae9460e Paul Brook
/* Get a block device.  This should only be used for single-drive devices
322 aae9460e Paul Brook
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
323 aae9460e Paul Brook
   appropriate bus.  */
324 aae9460e Paul Brook
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
325 aae9460e Paul Brook
{
326 aae9460e Paul Brook
    int unit = next_block_unit[type]++;
327 751c6a17 Gerd Hoffmann
    DriveInfo *dinfo;
328 aae9460e Paul Brook
329 751c6a17 Gerd Hoffmann
    dinfo = drive_get(type, 0, unit);
330 751c6a17 Gerd Hoffmann
    return dinfo ? dinfo->bdrv : NULL;
331 aae9460e Paul Brook
}
332 4d6ae674 Paul Brook
333 02e2da45 Paul Brook
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
334 4d6ae674 Paul Brook
{
335 02e2da45 Paul Brook
    BusState *bus;
336 4d6ae674 Paul Brook
337 72cf2d4f Blue Swirl
    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
338 4d6ae674 Paul Brook
        if (strcmp(name, bus->name) == 0) {
339 02e2da45 Paul Brook
            return bus;
340 4d6ae674 Paul Brook
        }
341 4d6ae674 Paul Brook
    }
342 4d6ae674 Paul Brook
    return NULL;
343 4d6ae674 Paul Brook
}
344 4d6ae674 Paul Brook
345 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find_recursive(BusState *bus, const char *name,
346 8ffb1bcf Gerd Hoffmann
                                     const BusInfo *info)
347 8ffb1bcf Gerd Hoffmann
{
348 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
349 8ffb1bcf Gerd Hoffmann
    BusState *child, *ret;
350 8ffb1bcf Gerd Hoffmann
    int match = 1;
351 8ffb1bcf Gerd Hoffmann
352 8ffb1bcf Gerd Hoffmann
    if (name && (strcmp(bus->name, name) != 0)) {
353 8ffb1bcf Gerd Hoffmann
        match = 0;
354 8ffb1bcf Gerd Hoffmann
    }
355 8ffb1bcf Gerd Hoffmann
    if (info && (bus->info != info)) {
356 8ffb1bcf Gerd Hoffmann
        match = 0;
357 8ffb1bcf Gerd Hoffmann
    }
358 8ffb1bcf Gerd Hoffmann
    if (match) {
359 8ffb1bcf Gerd Hoffmann
        return bus;
360 8ffb1bcf Gerd Hoffmann
    }
361 8ffb1bcf Gerd Hoffmann
362 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
363 72cf2d4f Blue Swirl
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
364 8ffb1bcf Gerd Hoffmann
            ret = qbus_find_recursive(child, name, info);
365 8ffb1bcf Gerd Hoffmann
            if (ret) {
366 8ffb1bcf Gerd Hoffmann
                return ret;
367 8ffb1bcf Gerd Hoffmann
            }
368 8ffb1bcf Gerd Hoffmann
        }
369 8ffb1bcf Gerd Hoffmann
    }
370 8ffb1bcf Gerd Hoffmann
    return NULL;
371 8ffb1bcf Gerd Hoffmann
}
372 8ffb1bcf Gerd Hoffmann
373 8ffb1bcf Gerd Hoffmann
static void qbus_list_bus(DeviceState *dev, char *dest, int len)
374 8ffb1bcf Gerd Hoffmann
{
375 8ffb1bcf Gerd Hoffmann
    BusState *child;
376 8ffb1bcf Gerd Hoffmann
    const char *sep = " ";
377 8ffb1bcf Gerd Hoffmann
    int pos = 0;
378 8ffb1bcf Gerd Hoffmann
379 8ffb1bcf Gerd Hoffmann
    pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
380 8ffb1bcf Gerd Hoffmann
                    dev->id ? dev->id : dev->info->name);
381 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
382 8ffb1bcf Gerd Hoffmann
        pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
383 8ffb1bcf Gerd Hoffmann
        sep = ", ";
384 8ffb1bcf Gerd Hoffmann
    }
385 8ffb1bcf Gerd Hoffmann
}
386 8ffb1bcf Gerd Hoffmann
387 8ffb1bcf Gerd Hoffmann
static void qbus_list_dev(BusState *bus, char *dest, int len)
388 8ffb1bcf Gerd Hoffmann
{
389 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
390 8ffb1bcf Gerd Hoffmann
    const char *sep = " ";
391 8ffb1bcf Gerd Hoffmann
    int pos = 0;
392 8ffb1bcf Gerd Hoffmann
393 8ffb1bcf Gerd Hoffmann
    pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
394 8ffb1bcf Gerd Hoffmann
                    bus->name);
395 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
396 8ffb1bcf Gerd Hoffmann
        pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
397 8ffb1bcf Gerd Hoffmann
                        sep, dev->info->name);
398 8ffb1bcf Gerd Hoffmann
        if (dev->id)
399 8ffb1bcf Gerd Hoffmann
            pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
400 8ffb1bcf Gerd Hoffmann
        sep = ", ";
401 8ffb1bcf Gerd Hoffmann
    }
402 8ffb1bcf Gerd Hoffmann
}
403 8ffb1bcf Gerd Hoffmann
404 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find_bus(DeviceState *dev, char *elem)
405 8ffb1bcf Gerd Hoffmann
{
406 8ffb1bcf Gerd Hoffmann
    BusState *child;
407 8ffb1bcf Gerd Hoffmann
408 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
409 8ffb1bcf Gerd Hoffmann
        if (strcmp(child->name, elem) == 0) {
410 8ffb1bcf Gerd Hoffmann
            return child;
411 8ffb1bcf Gerd Hoffmann
        }
412 8ffb1bcf Gerd Hoffmann
    }
413 8ffb1bcf Gerd Hoffmann
    return NULL;
414 8ffb1bcf Gerd Hoffmann
}
415 8ffb1bcf Gerd Hoffmann
416 8ffb1bcf Gerd Hoffmann
static DeviceState *qbus_find_dev(BusState *bus, char *elem)
417 8ffb1bcf Gerd Hoffmann
{
418 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
419 8ffb1bcf Gerd Hoffmann
420 8ffb1bcf Gerd Hoffmann
    /*
421 8ffb1bcf Gerd Hoffmann
     * try to match in order:
422 8ffb1bcf Gerd Hoffmann
     *   (1) instance id, if present
423 8ffb1bcf Gerd Hoffmann
     *   (2) driver name
424 8ffb1bcf Gerd Hoffmann
     *   (3) driver alias, if present
425 8ffb1bcf Gerd Hoffmann
     */
426 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
427 8ffb1bcf Gerd Hoffmann
        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
428 8ffb1bcf Gerd Hoffmann
            return dev;
429 8ffb1bcf Gerd Hoffmann
        }
430 8ffb1bcf Gerd Hoffmann
    }
431 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
432 8ffb1bcf Gerd Hoffmann
        if (strcmp(dev->info->name, elem) == 0) {
433 8ffb1bcf Gerd Hoffmann
            return dev;
434 8ffb1bcf Gerd Hoffmann
        }
435 8ffb1bcf Gerd Hoffmann
    }
436 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
437 8ffb1bcf Gerd Hoffmann
        if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
438 8ffb1bcf Gerd Hoffmann
            return dev;
439 8ffb1bcf Gerd Hoffmann
        }
440 8ffb1bcf Gerd Hoffmann
    }
441 8ffb1bcf Gerd Hoffmann
    return NULL;
442 8ffb1bcf Gerd Hoffmann
}
443 8ffb1bcf Gerd Hoffmann
444 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find(const char *path)
445 8ffb1bcf Gerd Hoffmann
{
446 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
447 8ffb1bcf Gerd Hoffmann
    BusState *bus;
448 8ffb1bcf Gerd Hoffmann
    char elem[128], msg[256];
449 8ffb1bcf Gerd Hoffmann
    int pos, len;
450 8ffb1bcf Gerd Hoffmann
451 8ffb1bcf Gerd Hoffmann
    /* find start element */
452 8ffb1bcf Gerd Hoffmann
    if (path[0] == '/') {
453 8ffb1bcf Gerd Hoffmann
        bus = main_system_bus;
454 8ffb1bcf Gerd Hoffmann
        pos = 0;
455 8ffb1bcf Gerd Hoffmann
    } else {
456 8ffb1bcf Gerd Hoffmann
        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
457 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\")\n", path);
458 8ffb1bcf Gerd Hoffmann
            return NULL;
459 8ffb1bcf Gerd Hoffmann
        }
460 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_recursive(main_system_bus, elem, NULL);
461 8ffb1bcf Gerd Hoffmann
        if (!bus) {
462 286c2321 Gerd Hoffmann
            qemu_error("bus \"%s\" not found\n", elem);
463 8ffb1bcf Gerd Hoffmann
            return NULL;
464 8ffb1bcf Gerd Hoffmann
        }
465 8ffb1bcf Gerd Hoffmann
        pos = len;
466 8ffb1bcf Gerd Hoffmann
    }
467 8ffb1bcf Gerd Hoffmann
468 8ffb1bcf Gerd Hoffmann
    for (;;) {
469 8ffb1bcf Gerd Hoffmann
        if (path[pos] == '\0') {
470 8ffb1bcf Gerd Hoffmann
            /* we are done */
471 8ffb1bcf Gerd Hoffmann
            return bus;
472 8ffb1bcf Gerd Hoffmann
        }
473 8ffb1bcf Gerd Hoffmann
474 8ffb1bcf Gerd Hoffmann
        /* find device */
475 8ffb1bcf Gerd Hoffmann
        if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
476 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
477 8ffb1bcf Gerd Hoffmann
            return NULL;
478 8ffb1bcf Gerd Hoffmann
        }
479 8ffb1bcf Gerd Hoffmann
        pos += len;
480 8ffb1bcf Gerd Hoffmann
        dev = qbus_find_dev(bus, elem);
481 8ffb1bcf Gerd Hoffmann
        if (!dev) {
482 8ffb1bcf Gerd Hoffmann
            qbus_list_dev(bus, msg, sizeof(msg));
483 286c2321 Gerd Hoffmann
            qemu_error("device \"%s\" not found\n%s\n", elem, msg);
484 8ffb1bcf Gerd Hoffmann
            return NULL;
485 8ffb1bcf Gerd Hoffmann
        }
486 8ffb1bcf Gerd Hoffmann
        if (path[pos] == '\0') {
487 8ffb1bcf Gerd Hoffmann
            /* last specified element is a device.  If it has exactly
488 8ffb1bcf Gerd Hoffmann
             * one child bus accept it nevertheless */
489 8ffb1bcf Gerd Hoffmann
            switch (dev->num_child_bus) {
490 8ffb1bcf Gerd Hoffmann
            case 0:
491 286c2321 Gerd Hoffmann
                qemu_error("device has no child bus (%s)\n", path);
492 8ffb1bcf Gerd Hoffmann
                return NULL;
493 8ffb1bcf Gerd Hoffmann
            case 1:
494 72cf2d4f Blue Swirl
                return QLIST_FIRST(&dev->child_bus);
495 8ffb1bcf Gerd Hoffmann
            default:
496 8ffb1bcf Gerd Hoffmann
                qbus_list_bus(dev, msg, sizeof(msg));
497 286c2321 Gerd Hoffmann
                qemu_error("device has multiple child busses (%s)\n%s\n",
498 286c2321 Gerd Hoffmann
                           path, msg);
499 8ffb1bcf Gerd Hoffmann
                return NULL;
500 8ffb1bcf Gerd Hoffmann
            }
501 8ffb1bcf Gerd Hoffmann
        }
502 8ffb1bcf Gerd Hoffmann
503 8ffb1bcf Gerd Hoffmann
        /* find bus */
504 8ffb1bcf Gerd Hoffmann
        if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
505 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
506 8ffb1bcf Gerd Hoffmann
            return NULL;
507 8ffb1bcf Gerd Hoffmann
        }
508 8ffb1bcf Gerd Hoffmann
        pos += len;
509 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_bus(dev, elem);
510 8ffb1bcf Gerd Hoffmann
        if (!bus) {
511 8ffb1bcf Gerd Hoffmann
            qbus_list_bus(dev, msg, sizeof(msg));
512 286c2321 Gerd Hoffmann
            qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
513 8ffb1bcf Gerd Hoffmann
            return NULL;
514 8ffb1bcf Gerd Hoffmann
        }
515 8ffb1bcf Gerd Hoffmann
    }
516 8ffb1bcf Gerd Hoffmann
}
517 8ffb1bcf Gerd Hoffmann
518 cd739fb6 Gerd Hoffmann
void qbus_create_inplace(BusState *bus, BusInfo *info,
519 cd739fb6 Gerd Hoffmann
                         DeviceState *parent, const char *name)
520 02e2da45 Paul Brook
{
521 d271de9f Gerd Hoffmann
    char *buf;
522 d271de9f Gerd Hoffmann
    int i,len;
523 02e2da45 Paul Brook
524 10c4c98a Gerd Hoffmann
    bus->info = info;
525 02e2da45 Paul Brook
    bus->parent = parent;
526 d271de9f Gerd Hoffmann
527 d271de9f Gerd Hoffmann
    if (name) {
528 d271de9f Gerd Hoffmann
        /* use supplied name */
529 d271de9f Gerd Hoffmann
        bus->name = qemu_strdup(name);
530 d271de9f Gerd Hoffmann
    } else if (parent && parent->id) {
531 d271de9f Gerd Hoffmann
        /* parent device has id -> use it for bus name */
532 d271de9f Gerd Hoffmann
        len = strlen(parent->id) + 16;
533 d271de9f Gerd Hoffmann
        buf = qemu_malloc(len);
534 d271de9f Gerd Hoffmann
        snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
535 d271de9f Gerd Hoffmann
        bus->name = buf;
536 d271de9f Gerd Hoffmann
    } else {
537 d271de9f Gerd Hoffmann
        /* no id -> use lowercase bus type for bus name */
538 d271de9f Gerd Hoffmann
        len = strlen(info->name) + 16;
539 d271de9f Gerd Hoffmann
        buf = qemu_malloc(len);
540 d271de9f Gerd Hoffmann
        len = snprintf(buf, len, "%s.%d", info->name,
541 d271de9f Gerd Hoffmann
                       parent ? parent->num_child_bus : 0);
542 d271de9f Gerd Hoffmann
        for (i = 0; i < len; i++)
543 bb87ece5 Christoph Egger
            buf[i] = qemu_tolower(buf[i]);
544 d271de9f Gerd Hoffmann
        bus->name = buf;
545 d271de9f Gerd Hoffmann
    }
546 d271de9f Gerd Hoffmann
547 72cf2d4f Blue Swirl
    QLIST_INIT(&bus->children);
548 02e2da45 Paul Brook
    if (parent) {
549 72cf2d4f Blue Swirl
        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
550 d271de9f Gerd Hoffmann
        parent->num_child_bus++;
551 02e2da45 Paul Brook
    }
552 cd739fb6 Gerd Hoffmann
553 cd739fb6 Gerd Hoffmann
}
554 cd739fb6 Gerd Hoffmann
555 cd739fb6 Gerd Hoffmann
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
556 cd739fb6 Gerd Hoffmann
{
557 cd739fb6 Gerd Hoffmann
    BusState *bus;
558 cd739fb6 Gerd Hoffmann
559 cd739fb6 Gerd Hoffmann
    bus = qemu_mallocz(info->size);
560 cd739fb6 Gerd Hoffmann
    bus->qdev_allocated = 1;
561 cd739fb6 Gerd Hoffmann
    qbus_create_inplace(bus, info, parent, name);
562 02e2da45 Paul Brook
    return bus;
563 02e2da45 Paul Brook
}
564 cae4956e Gerd Hoffmann
565 131ec1bd Gerd Hoffmann
void qbus_free(BusState *bus)
566 131ec1bd Gerd Hoffmann
{
567 131ec1bd Gerd Hoffmann
    DeviceState *dev;
568 131ec1bd Gerd Hoffmann
569 131ec1bd Gerd Hoffmann
    while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
570 131ec1bd Gerd Hoffmann
        qdev_free(dev);
571 131ec1bd Gerd Hoffmann
    }
572 131ec1bd Gerd Hoffmann
    if (bus->parent) {
573 131ec1bd Gerd Hoffmann
        QLIST_REMOVE(bus, sibling);
574 131ec1bd Gerd Hoffmann
        bus->parent->num_child_bus--;
575 131ec1bd Gerd Hoffmann
    }
576 131ec1bd Gerd Hoffmann
    if (bus->qdev_allocated) {
577 131ec1bd Gerd Hoffmann
        qemu_free(bus);
578 131ec1bd Gerd Hoffmann
    }
579 131ec1bd Gerd Hoffmann
}
580 131ec1bd Gerd Hoffmann
581 cae4956e Gerd Hoffmann
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
582 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent);
583 cae4956e Gerd Hoffmann
584 ee6847d1 Gerd Hoffmann
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
585 ee6847d1 Gerd Hoffmann
                             const char *prefix, int indent)
586 ee6847d1 Gerd Hoffmann
{
587 ee6847d1 Gerd Hoffmann
    char buf[64];
588 ee6847d1 Gerd Hoffmann
589 ee6847d1 Gerd Hoffmann
    if (!props)
590 ee6847d1 Gerd Hoffmann
        return;
591 ee6847d1 Gerd Hoffmann
    while (props->name) {
592 ee6847d1 Gerd Hoffmann
        if (props->info->print) {
593 ee6847d1 Gerd Hoffmann
            props->info->print(dev, props, buf, sizeof(buf));
594 ee6847d1 Gerd Hoffmann
            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
595 ee6847d1 Gerd Hoffmann
        }
596 ee6847d1 Gerd Hoffmann
        props++;
597 ee6847d1 Gerd Hoffmann
    }
598 ee6847d1 Gerd Hoffmann
}
599 ee6847d1 Gerd Hoffmann
600 cae4956e Gerd Hoffmann
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
601 cae4956e Gerd Hoffmann
{
602 cae4956e Gerd Hoffmann
    BusState *child;
603 ccb63de3 Gerd Hoffmann
    qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
604 ccb63de3 Gerd Hoffmann
                dev->id ? dev->id : "");
605 cae4956e Gerd Hoffmann
    indent += 2;
606 cae4956e Gerd Hoffmann
    if (dev->num_gpio_in) {
607 cae4956e Gerd Hoffmann
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
608 cae4956e Gerd Hoffmann
    }
609 cae4956e Gerd Hoffmann
    if (dev->num_gpio_out) {
610 cae4956e Gerd Hoffmann
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
611 cae4956e Gerd Hoffmann
    }
612 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->info->props, "dev", indent);
613 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
614 10c4c98a Gerd Hoffmann
    if (dev->parent_bus->info->print_dev)
615 10c4c98a Gerd Hoffmann
        dev->parent_bus->info->print_dev(mon, dev, indent);
616 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
617 cae4956e Gerd Hoffmann
        qbus_print(mon, child, indent);
618 cae4956e Gerd Hoffmann
    }
619 cae4956e Gerd Hoffmann
}
620 cae4956e Gerd Hoffmann
621 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent)
622 cae4956e Gerd Hoffmann
{
623 cae4956e Gerd Hoffmann
    struct DeviceState *dev;
624 cae4956e Gerd Hoffmann
625 cae4956e Gerd Hoffmann
    qdev_printf("bus: %s\n", bus->name);
626 cae4956e Gerd Hoffmann
    indent += 2;
627 10c4c98a Gerd Hoffmann
    qdev_printf("type %s\n", bus->info->name);
628 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
629 cae4956e Gerd Hoffmann
        qdev_print(mon, dev, indent);
630 cae4956e Gerd Hoffmann
    }
631 cae4956e Gerd Hoffmann
}
632 cae4956e Gerd Hoffmann
#undef qdev_printf
633 cae4956e Gerd Hoffmann
634 cae4956e Gerd Hoffmann
void do_info_qtree(Monitor *mon)
635 cae4956e Gerd Hoffmann
{
636 cae4956e Gerd Hoffmann
    if (main_system_bus)
637 cae4956e Gerd Hoffmann
        qbus_print(mon, main_system_bus, 0);
638 cae4956e Gerd Hoffmann
}
639 9316d30f Gerd Hoffmann
640 f6c64e0e Gerd Hoffmann
void do_info_qdm(Monitor *mon)
641 9316d30f Gerd Hoffmann
{
642 9316d30f Gerd Hoffmann
    DeviceInfo *info;
643 9316d30f Gerd Hoffmann
    char msg[256];
644 9316d30f Gerd Hoffmann
645 9316d30f Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
646 9316d30f Gerd Hoffmann
        qdev_print_devinfo(info, msg, sizeof(msg));
647 9316d30f Gerd Hoffmann
        monitor_printf(mon, "%s\n", msg);
648 9316d30f Gerd Hoffmann
    }
649 9316d30f Gerd Hoffmann
}