Statistics
| Branch: | Revision:

root / hw / qdev.c @ 86178a57

History | View | Annotate | Download (16.9 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 aae9460e Paul Brook
    return dev;
106 aae9460e Paul Brook
}
107 aae9460e Paul Brook
108 1b524b04 Gerd Hoffmann
static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
109 1b524b04 Gerd Hoffmann
{
110 1b524b04 Gerd Hoffmann
    int pos = 0;
111 22f2e344 Gerd Hoffmann
    int ret;
112 22f2e344 Gerd Hoffmann
113 22f2e344 Gerd Hoffmann
    ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
114 22f2e344 Gerd Hoffmann
                   info->name, info->bus_info->name);
115 22f2e344 Gerd Hoffmann
    pos += MIN(len-pos,ret);
116 22f2e344 Gerd Hoffmann
    if (info->alias) {
117 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
118 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
119 22f2e344 Gerd Hoffmann
    }
120 22f2e344 Gerd Hoffmann
    if (info->desc) {
121 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
122 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
123 22f2e344 Gerd Hoffmann
    }
124 22f2e344 Gerd Hoffmann
    if (info->no_user) {
125 22f2e344 Gerd Hoffmann
        ret = snprintf(dest+pos, len-pos, ", no-user");
126 22f2e344 Gerd Hoffmann
        pos += MIN(len-pos,ret);
127 22f2e344 Gerd Hoffmann
    }
128 1b524b04 Gerd Hoffmann
    return pos;
129 1b524b04 Gerd Hoffmann
}
130 1b524b04 Gerd Hoffmann
131 f31d07d1 Gerd Hoffmann
static int set_property(const char *name, const char *value, void *opaque)
132 8ffb1bcf Gerd Hoffmann
{
133 f31d07d1 Gerd Hoffmann
    DeviceState *dev = opaque;
134 f31d07d1 Gerd Hoffmann
135 f31d07d1 Gerd Hoffmann
    if (strcmp(name, "driver") == 0)
136 f31d07d1 Gerd Hoffmann
        return 0;
137 f31d07d1 Gerd Hoffmann
    if (strcmp(name, "bus") == 0)
138 f31d07d1 Gerd Hoffmann
        return 0;
139 f31d07d1 Gerd Hoffmann
140 f31d07d1 Gerd Hoffmann
    if (-1 == qdev_prop_parse(dev, name, value)) {
141 286c2321 Gerd Hoffmann
        qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
142 286c2321 Gerd Hoffmann
                   name, value, dev->info->name);
143 f31d07d1 Gerd Hoffmann
        return -1;
144 f31d07d1 Gerd Hoffmann
    }
145 f31d07d1 Gerd Hoffmann
    return 0;
146 f31d07d1 Gerd Hoffmann
}
147 f31d07d1 Gerd Hoffmann
148 f31d07d1 Gerd Hoffmann
DeviceState *qdev_device_add(QemuOpts *opts)
149 f31d07d1 Gerd Hoffmann
{
150 f31d07d1 Gerd Hoffmann
    const char *driver, *path, *id;
151 8ffb1bcf Gerd Hoffmann
    DeviceInfo *info;
152 8ffb1bcf Gerd Hoffmann
    DeviceState *qdev;
153 8ffb1bcf Gerd Hoffmann
    BusState *bus;
154 8ffb1bcf Gerd Hoffmann
155 f31d07d1 Gerd Hoffmann
    driver = qemu_opt_get(opts, "driver");
156 f31d07d1 Gerd Hoffmann
    if (!driver) {
157 286c2321 Gerd Hoffmann
        qemu_error("-device: no driver specified\n");
158 8ffb1bcf Gerd Hoffmann
        return NULL;
159 8ffb1bcf Gerd Hoffmann
    }
160 8ffb1bcf Gerd Hoffmann
    if (strcmp(driver, "?") == 0) {
161 1b524b04 Gerd Hoffmann
        char msg[256];
162 8ffb1bcf Gerd Hoffmann
        for (info = device_info_list; info != NULL; info = info->next) {
163 1b524b04 Gerd Hoffmann
            qdev_print_devinfo(info, msg, sizeof(msg));
164 286c2321 Gerd Hoffmann
            qemu_error("%s\n", msg);
165 8ffb1bcf Gerd Hoffmann
        }
166 8ffb1bcf Gerd Hoffmann
        return NULL;
167 8ffb1bcf Gerd Hoffmann
    }
168 f31d07d1 Gerd Hoffmann
169 f31d07d1 Gerd Hoffmann
    /* find driver */
170 8ffb1bcf Gerd Hoffmann
    info = qdev_find_info(NULL, driver);
171 8ffb1bcf Gerd Hoffmann
    if (!info) {
172 286c2321 Gerd Hoffmann
        qemu_error("Device \"%s\" not found.  Try -device '?' for a list.\n",
173 286c2321 Gerd Hoffmann
                   driver);
174 8ffb1bcf Gerd Hoffmann
        return NULL;
175 8ffb1bcf Gerd Hoffmann
    }
176 8ffb1bcf Gerd Hoffmann
    if (info->no_user) {
177 286c2321 Gerd Hoffmann
        qemu_error("device \"%s\" can't be added via command line\n",
178 286c2321 Gerd Hoffmann
                   info->name);
179 8ffb1bcf Gerd Hoffmann
        return NULL;
180 8ffb1bcf Gerd Hoffmann
    }
181 8ffb1bcf Gerd Hoffmann
182 f31d07d1 Gerd Hoffmann
    /* find bus */
183 f31d07d1 Gerd Hoffmann
    path = qemu_opt_get(opts, "bus");
184 f31d07d1 Gerd Hoffmann
    if (path != NULL) {
185 8ffb1bcf Gerd Hoffmann
        bus = qbus_find(path);
186 8ffb1bcf Gerd Hoffmann
    } else {
187 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
188 8ffb1bcf Gerd Hoffmann
    }
189 75570088 Gerd Hoffmann
    if (!bus) {
190 75570088 Gerd Hoffmann
        qemu_error("Did not find %s bus for %s\n",
191 75570088 Gerd Hoffmann
                   path ? path : info->bus_info->name, info->name);
192 f31d07d1 Gerd Hoffmann
        return NULL;
193 75570088 Gerd Hoffmann
    }
194 8ffb1bcf Gerd Hoffmann
195 f31d07d1 Gerd Hoffmann
    /* create device, set properties */
196 f31d07d1 Gerd Hoffmann
    qdev = qdev_create(bus, driver);
197 f31d07d1 Gerd Hoffmann
    id = qemu_opts_id(opts);
198 f31d07d1 Gerd Hoffmann
    if (id) {
199 f31d07d1 Gerd Hoffmann
        qdev->id = id;
200 f31d07d1 Gerd Hoffmann
    }
201 f31d07d1 Gerd Hoffmann
    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
202 f31d07d1 Gerd Hoffmann
        qdev_free(qdev);
203 f31d07d1 Gerd Hoffmann
        return NULL;
204 8ffb1bcf Gerd Hoffmann
    }
205 81a322d4 Gerd Hoffmann
    if (qdev_init(qdev) != 0) {
206 81a322d4 Gerd Hoffmann
        qdev_free(qdev);
207 81a322d4 Gerd Hoffmann
        return NULL;
208 81a322d4 Gerd Hoffmann
    }
209 8ffb1bcf Gerd Hoffmann
    return qdev;
210 8ffb1bcf Gerd Hoffmann
}
211 8ffb1bcf Gerd Hoffmann
212 aae9460e Paul Brook
/* Initialize a device.  Device properties should be set before calling
213 aae9460e Paul Brook
   this function.  IRQs and MMIO regions should be connected/mapped after
214 aae9460e Paul Brook
   calling this function.  */
215 81a322d4 Gerd Hoffmann
int qdev_init(DeviceState *dev)
216 aae9460e Paul Brook
{
217 959f733a Gerd Hoffmann
    int rc;
218 959f733a Gerd Hoffmann
219 959f733a Gerd Hoffmann
    rc = dev->info->init(dev, dev->info);
220 959f733a Gerd Hoffmann
    if (rc < 0)
221 959f733a Gerd Hoffmann
        return rc;
222 959f733a Gerd Hoffmann
    if (dev->info->reset)
223 959f733a Gerd Hoffmann
        qemu_register_reset(dev->info->reset, dev);
224 391a079e Gerd Hoffmann
    if (dev->info->vmsd)
225 391a079e Gerd Hoffmann
        vmstate_register(-1, dev->info->vmsd, dev);
226 959f733a Gerd Hoffmann
    return 0;
227 02e2da45 Paul Brook
}
228 02e2da45 Paul Brook
229 02e2da45 Paul Brook
/* Unlink device from bus and free the structure.  */
230 02e2da45 Paul Brook
void qdev_free(DeviceState *dev)
231 02e2da45 Paul Brook
{
232 391a079e Gerd Hoffmann
#if 0 /* FIXME: need sane vmstate_unregister function */
233 391a079e Gerd Hoffmann
    if (dev->info->vmsd)
234 391a079e Gerd Hoffmann
        vmstate_unregister(dev->info->vmsd, dev);
235 391a079e Gerd Hoffmann
#endif
236 959f733a Gerd Hoffmann
    if (dev->info->reset)
237 959f733a Gerd Hoffmann
        qemu_unregister_reset(dev->info->reset, dev);
238 72cf2d4f Blue Swirl
    QLIST_REMOVE(dev, sibling);
239 ccb63de3 Gerd Hoffmann
    qemu_free(dev);
240 aae9460e Paul Brook
}
241 aae9460e Paul Brook
242 aae9460e Paul Brook
/* Get a character (serial) device interface.  */
243 aae9460e Paul Brook
CharDriverState *qdev_init_chardev(DeviceState *dev)
244 aae9460e Paul Brook
{
245 aae9460e Paul Brook
    static int next_serial;
246 aae9460e Paul Brook
    static int next_virtconsole;
247 aae9460e Paul Brook
    /* FIXME: This is a nasty hack that needs to go away.  */
248 042f84d0 Gerd Hoffmann
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
249 aae9460e Paul Brook
        return virtcon_hds[next_virtconsole++];
250 aae9460e Paul Brook
    } else {
251 aae9460e Paul Brook
        return serial_hds[next_serial++];
252 aae9460e Paul Brook
    }
253 aae9460e Paul Brook
}
254 aae9460e Paul Brook
255 02e2da45 Paul Brook
BusState *qdev_get_parent_bus(DeviceState *dev)
256 aae9460e Paul Brook
{
257 02e2da45 Paul Brook
    return dev->parent_bus;
258 aae9460e Paul Brook
}
259 aae9460e Paul Brook
260 aae9460e Paul Brook
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
261 aae9460e Paul Brook
{
262 aae9460e Paul Brook
    assert(dev->num_gpio_in == 0);
263 aae9460e Paul Brook
    dev->num_gpio_in = n;
264 aae9460e Paul Brook
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
265 aae9460e Paul Brook
}
266 aae9460e Paul Brook
267 aae9460e Paul Brook
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
268 aae9460e Paul Brook
{
269 aae9460e Paul Brook
    assert(dev->num_gpio_out == 0);
270 aae9460e Paul Brook
    dev->num_gpio_out = n;
271 aae9460e Paul Brook
    dev->gpio_out = pins;
272 aae9460e Paul Brook
}
273 aae9460e Paul Brook
274 aae9460e Paul Brook
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
275 aae9460e Paul Brook
{
276 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_in);
277 aae9460e Paul Brook
    return dev->gpio_in[n];
278 aae9460e Paul Brook
}
279 aae9460e Paul Brook
280 aae9460e Paul Brook
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
281 aae9460e Paul Brook
{
282 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_out);
283 aae9460e Paul Brook
    dev->gpio_out[n] = pin;
284 aae9460e Paul Brook
}
285 aae9460e Paul Brook
286 9d07d757 Paul Brook
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
287 cda9046b Mark McLoughlin
                                      NetCanReceive *can_receive,
288 cda9046b Mark McLoughlin
                                      NetReceive *receive,
289 cda9046b Mark McLoughlin
                                      NetReceiveIOV *receive_iov,
290 9d07d757 Paul Brook
                                      NetCleanup *cleanup,
291 9d07d757 Paul Brook
                                      void *opaque)
292 9d07d757 Paul Brook
{
293 9d07d757 Paul Brook
    NICInfo *nd = dev->nd;
294 9d07d757 Paul Brook
    assert(nd);
295 ae50b274 Mark McLoughlin
    nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
296 ae50b274 Mark McLoughlin
                                  receive, receive_iov, cleanup, opaque);
297 ae50b274 Mark McLoughlin
    return nd->vc;
298 9d07d757 Paul Brook
}
299 9d07d757 Paul Brook
300 9d07d757 Paul Brook
301 9d07d757 Paul Brook
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
302 9d07d757 Paul Brook
{
303 9d07d757 Paul Brook
    memcpy(macaddr, dev->nd->macaddr, 6);
304 9d07d757 Paul Brook
}
305 9d07d757 Paul Brook
306 aae9460e Paul Brook
static int next_block_unit[IF_COUNT];
307 aae9460e Paul Brook
308 aae9460e Paul Brook
/* Get a block device.  This should only be used for single-drive devices
309 aae9460e Paul Brook
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
310 aae9460e Paul Brook
   appropriate bus.  */
311 aae9460e Paul Brook
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
312 aae9460e Paul Brook
{
313 aae9460e Paul Brook
    int unit = next_block_unit[type]++;
314 751c6a17 Gerd Hoffmann
    DriveInfo *dinfo;
315 aae9460e Paul Brook
316 751c6a17 Gerd Hoffmann
    dinfo = drive_get(type, 0, unit);
317 751c6a17 Gerd Hoffmann
    return dinfo ? dinfo->bdrv : NULL;
318 aae9460e Paul Brook
}
319 4d6ae674 Paul Brook
320 02e2da45 Paul Brook
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
321 4d6ae674 Paul Brook
{
322 02e2da45 Paul Brook
    BusState *bus;
323 4d6ae674 Paul Brook
324 72cf2d4f Blue Swirl
    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
325 4d6ae674 Paul Brook
        if (strcmp(name, bus->name) == 0) {
326 02e2da45 Paul Brook
            return bus;
327 4d6ae674 Paul Brook
        }
328 4d6ae674 Paul Brook
    }
329 4d6ae674 Paul Brook
    return NULL;
330 4d6ae674 Paul Brook
}
331 4d6ae674 Paul Brook
332 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find_recursive(BusState *bus, const char *name,
333 8ffb1bcf Gerd Hoffmann
                                     const BusInfo *info)
334 8ffb1bcf Gerd Hoffmann
{
335 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
336 8ffb1bcf Gerd Hoffmann
    BusState *child, *ret;
337 8ffb1bcf Gerd Hoffmann
    int match = 1;
338 8ffb1bcf Gerd Hoffmann
339 8ffb1bcf Gerd Hoffmann
    if (name && (strcmp(bus->name, name) != 0)) {
340 8ffb1bcf Gerd Hoffmann
        match = 0;
341 8ffb1bcf Gerd Hoffmann
    }
342 8ffb1bcf Gerd Hoffmann
    if (info && (bus->info != info)) {
343 8ffb1bcf Gerd Hoffmann
        match = 0;
344 8ffb1bcf Gerd Hoffmann
    }
345 8ffb1bcf Gerd Hoffmann
    if (match) {
346 8ffb1bcf Gerd Hoffmann
        return bus;
347 8ffb1bcf Gerd Hoffmann
    }
348 8ffb1bcf Gerd Hoffmann
349 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
350 72cf2d4f Blue Swirl
        QLIST_FOREACH(child, &dev->child_bus, sibling) {
351 8ffb1bcf Gerd Hoffmann
            ret = qbus_find_recursive(child, name, info);
352 8ffb1bcf Gerd Hoffmann
            if (ret) {
353 8ffb1bcf Gerd Hoffmann
                return ret;
354 8ffb1bcf Gerd Hoffmann
            }
355 8ffb1bcf Gerd Hoffmann
        }
356 8ffb1bcf Gerd Hoffmann
    }
357 8ffb1bcf Gerd Hoffmann
    return NULL;
358 8ffb1bcf Gerd Hoffmann
}
359 8ffb1bcf Gerd Hoffmann
360 8ffb1bcf Gerd Hoffmann
static void qbus_list_bus(DeviceState *dev, char *dest, int len)
361 8ffb1bcf Gerd Hoffmann
{
362 8ffb1bcf Gerd Hoffmann
    BusState *child;
363 8ffb1bcf Gerd Hoffmann
    const char *sep = " ";
364 8ffb1bcf Gerd Hoffmann
    int pos = 0;
365 8ffb1bcf Gerd Hoffmann
366 8ffb1bcf Gerd Hoffmann
    pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
367 8ffb1bcf Gerd Hoffmann
                    dev->id ? dev->id : dev->info->name);
368 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
369 8ffb1bcf Gerd Hoffmann
        pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
370 8ffb1bcf Gerd Hoffmann
        sep = ", ";
371 8ffb1bcf Gerd Hoffmann
    }
372 8ffb1bcf Gerd Hoffmann
}
373 8ffb1bcf Gerd Hoffmann
374 8ffb1bcf Gerd Hoffmann
static void qbus_list_dev(BusState *bus, char *dest, int len)
375 8ffb1bcf Gerd Hoffmann
{
376 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
377 8ffb1bcf Gerd Hoffmann
    const char *sep = " ";
378 8ffb1bcf Gerd Hoffmann
    int pos = 0;
379 8ffb1bcf Gerd Hoffmann
380 8ffb1bcf Gerd Hoffmann
    pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
381 8ffb1bcf Gerd Hoffmann
                    bus->name);
382 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
383 8ffb1bcf Gerd Hoffmann
        pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
384 8ffb1bcf Gerd Hoffmann
                        sep, dev->info->name);
385 8ffb1bcf Gerd Hoffmann
        if (dev->id)
386 8ffb1bcf Gerd Hoffmann
            pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
387 8ffb1bcf Gerd Hoffmann
        sep = ", ";
388 8ffb1bcf Gerd Hoffmann
    }
389 8ffb1bcf Gerd Hoffmann
}
390 8ffb1bcf Gerd Hoffmann
391 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find_bus(DeviceState *dev, char *elem)
392 8ffb1bcf Gerd Hoffmann
{
393 8ffb1bcf Gerd Hoffmann
    BusState *child;
394 8ffb1bcf Gerd Hoffmann
395 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
396 8ffb1bcf Gerd Hoffmann
        if (strcmp(child->name, elem) == 0) {
397 8ffb1bcf Gerd Hoffmann
            return child;
398 8ffb1bcf Gerd Hoffmann
        }
399 8ffb1bcf Gerd Hoffmann
    }
400 8ffb1bcf Gerd Hoffmann
    return NULL;
401 8ffb1bcf Gerd Hoffmann
}
402 8ffb1bcf Gerd Hoffmann
403 8ffb1bcf Gerd Hoffmann
static DeviceState *qbus_find_dev(BusState *bus, char *elem)
404 8ffb1bcf Gerd Hoffmann
{
405 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
406 8ffb1bcf Gerd Hoffmann
407 8ffb1bcf Gerd Hoffmann
    /*
408 8ffb1bcf Gerd Hoffmann
     * try to match in order:
409 8ffb1bcf Gerd Hoffmann
     *   (1) instance id, if present
410 8ffb1bcf Gerd Hoffmann
     *   (2) driver name
411 8ffb1bcf Gerd Hoffmann
     *   (3) driver alias, if present
412 8ffb1bcf Gerd Hoffmann
     */
413 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
414 8ffb1bcf Gerd Hoffmann
        if (dev->id  &&  strcmp(dev->id, elem) == 0) {
415 8ffb1bcf Gerd Hoffmann
            return dev;
416 8ffb1bcf Gerd Hoffmann
        }
417 8ffb1bcf Gerd Hoffmann
    }
418 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
419 8ffb1bcf Gerd Hoffmann
        if (strcmp(dev->info->name, elem) == 0) {
420 8ffb1bcf Gerd Hoffmann
            return dev;
421 8ffb1bcf Gerd Hoffmann
        }
422 8ffb1bcf Gerd Hoffmann
    }
423 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
424 8ffb1bcf Gerd Hoffmann
        if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
425 8ffb1bcf Gerd Hoffmann
            return dev;
426 8ffb1bcf Gerd Hoffmann
        }
427 8ffb1bcf Gerd Hoffmann
    }
428 8ffb1bcf Gerd Hoffmann
    return NULL;
429 8ffb1bcf Gerd Hoffmann
}
430 8ffb1bcf Gerd Hoffmann
431 8ffb1bcf Gerd Hoffmann
static BusState *qbus_find(const char *path)
432 8ffb1bcf Gerd Hoffmann
{
433 8ffb1bcf Gerd Hoffmann
    DeviceState *dev;
434 8ffb1bcf Gerd Hoffmann
    BusState *bus;
435 8ffb1bcf Gerd Hoffmann
    char elem[128], msg[256];
436 8ffb1bcf Gerd Hoffmann
    int pos, len;
437 8ffb1bcf Gerd Hoffmann
438 8ffb1bcf Gerd Hoffmann
    /* find start element */
439 8ffb1bcf Gerd Hoffmann
    if (path[0] == '/') {
440 8ffb1bcf Gerd Hoffmann
        bus = main_system_bus;
441 8ffb1bcf Gerd Hoffmann
        pos = 0;
442 8ffb1bcf Gerd Hoffmann
    } else {
443 8ffb1bcf Gerd Hoffmann
        if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
444 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\")\n", path);
445 8ffb1bcf Gerd Hoffmann
            return NULL;
446 8ffb1bcf Gerd Hoffmann
        }
447 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_recursive(main_system_bus, elem, NULL);
448 8ffb1bcf Gerd Hoffmann
        if (!bus) {
449 286c2321 Gerd Hoffmann
            qemu_error("bus \"%s\" not found\n", elem);
450 8ffb1bcf Gerd Hoffmann
            return NULL;
451 8ffb1bcf Gerd Hoffmann
        }
452 8ffb1bcf Gerd Hoffmann
        pos = len;
453 8ffb1bcf Gerd Hoffmann
    }
454 8ffb1bcf Gerd Hoffmann
455 8ffb1bcf Gerd Hoffmann
    for (;;) {
456 8ffb1bcf Gerd Hoffmann
        if (path[pos] == '\0') {
457 8ffb1bcf Gerd Hoffmann
            /* we are done */
458 8ffb1bcf Gerd Hoffmann
            return bus;
459 8ffb1bcf Gerd Hoffmann
        }
460 8ffb1bcf Gerd Hoffmann
461 8ffb1bcf Gerd Hoffmann
        /* find device */
462 8ffb1bcf Gerd Hoffmann
        if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
463 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
464 8ffb1bcf Gerd Hoffmann
            return NULL;
465 8ffb1bcf Gerd Hoffmann
        }
466 8ffb1bcf Gerd Hoffmann
        pos += len;
467 8ffb1bcf Gerd Hoffmann
        dev = qbus_find_dev(bus, elem);
468 8ffb1bcf Gerd Hoffmann
        if (!dev) {
469 8ffb1bcf Gerd Hoffmann
            qbus_list_dev(bus, msg, sizeof(msg));
470 286c2321 Gerd Hoffmann
            qemu_error("device \"%s\" not found\n%s\n", elem, msg);
471 8ffb1bcf Gerd Hoffmann
            return NULL;
472 8ffb1bcf Gerd Hoffmann
        }
473 8ffb1bcf Gerd Hoffmann
        if (path[pos] == '\0') {
474 8ffb1bcf Gerd Hoffmann
            /* last specified element is a device.  If it has exactly
475 8ffb1bcf Gerd Hoffmann
             * one child bus accept it nevertheless */
476 8ffb1bcf Gerd Hoffmann
            switch (dev->num_child_bus) {
477 8ffb1bcf Gerd Hoffmann
            case 0:
478 286c2321 Gerd Hoffmann
                qemu_error("device has no child bus (%s)\n", path);
479 8ffb1bcf Gerd Hoffmann
                return NULL;
480 8ffb1bcf Gerd Hoffmann
            case 1:
481 72cf2d4f Blue Swirl
                return QLIST_FIRST(&dev->child_bus);
482 8ffb1bcf Gerd Hoffmann
            default:
483 8ffb1bcf Gerd Hoffmann
                qbus_list_bus(dev, msg, sizeof(msg));
484 286c2321 Gerd Hoffmann
                qemu_error("device has multiple child busses (%s)\n%s\n",
485 286c2321 Gerd Hoffmann
                           path, msg);
486 8ffb1bcf Gerd Hoffmann
                return NULL;
487 8ffb1bcf Gerd Hoffmann
            }
488 8ffb1bcf Gerd Hoffmann
        }
489 8ffb1bcf Gerd Hoffmann
490 8ffb1bcf Gerd Hoffmann
        /* find bus */
491 8ffb1bcf Gerd Hoffmann
        if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
492 286c2321 Gerd Hoffmann
            qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
493 8ffb1bcf Gerd Hoffmann
            return NULL;
494 8ffb1bcf Gerd Hoffmann
        }
495 8ffb1bcf Gerd Hoffmann
        pos += len;
496 8ffb1bcf Gerd Hoffmann
        bus = qbus_find_bus(dev, elem);
497 8ffb1bcf Gerd Hoffmann
        if (!bus) {
498 8ffb1bcf Gerd Hoffmann
            qbus_list_bus(dev, msg, sizeof(msg));
499 286c2321 Gerd Hoffmann
            qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
500 8ffb1bcf Gerd Hoffmann
            return NULL;
501 8ffb1bcf Gerd Hoffmann
        }
502 8ffb1bcf Gerd Hoffmann
    }
503 8ffb1bcf Gerd Hoffmann
}
504 8ffb1bcf Gerd Hoffmann
505 10c4c98a Gerd Hoffmann
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
506 02e2da45 Paul Brook
{
507 02e2da45 Paul Brook
    BusState *bus;
508 d271de9f Gerd Hoffmann
    char *buf;
509 d271de9f Gerd Hoffmann
    int i,len;
510 02e2da45 Paul Brook
511 10c4c98a Gerd Hoffmann
    bus = qemu_mallocz(info->size);
512 10c4c98a Gerd Hoffmann
    bus->info = info;
513 02e2da45 Paul Brook
    bus->parent = parent;
514 d271de9f Gerd Hoffmann
515 d271de9f Gerd Hoffmann
    if (name) {
516 d271de9f Gerd Hoffmann
        /* use supplied name */
517 d271de9f Gerd Hoffmann
        bus->name = qemu_strdup(name);
518 d271de9f Gerd Hoffmann
    } else if (parent && parent->id) {
519 d271de9f Gerd Hoffmann
        /* parent device has id -> use it for bus name */
520 d271de9f Gerd Hoffmann
        len = strlen(parent->id) + 16;
521 d271de9f Gerd Hoffmann
        buf = qemu_malloc(len);
522 d271de9f Gerd Hoffmann
        snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
523 d271de9f Gerd Hoffmann
        bus->name = buf;
524 d271de9f Gerd Hoffmann
    } else {
525 d271de9f Gerd Hoffmann
        /* no id -> use lowercase bus type for bus name */
526 d271de9f Gerd Hoffmann
        len = strlen(info->name) + 16;
527 d271de9f Gerd Hoffmann
        buf = qemu_malloc(len);
528 d271de9f Gerd Hoffmann
        len = snprintf(buf, len, "%s.%d", info->name,
529 d271de9f Gerd Hoffmann
                       parent ? parent->num_child_bus : 0);
530 d271de9f Gerd Hoffmann
        for (i = 0; i < len; i++)
531 bb87ece5 Christoph Egger
            buf[i] = qemu_tolower(buf[i]);
532 d271de9f Gerd Hoffmann
        bus->name = buf;
533 d271de9f Gerd Hoffmann
    }
534 d271de9f Gerd Hoffmann
535 72cf2d4f Blue Swirl
    QLIST_INIT(&bus->children);
536 02e2da45 Paul Brook
    if (parent) {
537 72cf2d4f Blue Swirl
        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
538 d271de9f Gerd Hoffmann
        parent->num_child_bus++;
539 02e2da45 Paul Brook
    }
540 02e2da45 Paul Brook
    return bus;
541 02e2da45 Paul Brook
}
542 cae4956e Gerd Hoffmann
543 cae4956e Gerd Hoffmann
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
544 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent);
545 cae4956e Gerd Hoffmann
546 ee6847d1 Gerd Hoffmann
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
547 ee6847d1 Gerd Hoffmann
                             const char *prefix, int indent)
548 ee6847d1 Gerd Hoffmann
{
549 ee6847d1 Gerd Hoffmann
    char buf[64];
550 ee6847d1 Gerd Hoffmann
551 ee6847d1 Gerd Hoffmann
    if (!props)
552 ee6847d1 Gerd Hoffmann
        return;
553 ee6847d1 Gerd Hoffmann
    while (props->name) {
554 ee6847d1 Gerd Hoffmann
        if (props->info->print) {
555 ee6847d1 Gerd Hoffmann
            props->info->print(dev, props, buf, sizeof(buf));
556 ee6847d1 Gerd Hoffmann
            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
557 ee6847d1 Gerd Hoffmann
        }
558 ee6847d1 Gerd Hoffmann
        props++;
559 ee6847d1 Gerd Hoffmann
    }
560 ee6847d1 Gerd Hoffmann
}
561 ee6847d1 Gerd Hoffmann
562 cae4956e Gerd Hoffmann
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
563 cae4956e Gerd Hoffmann
{
564 cae4956e Gerd Hoffmann
    BusState *child;
565 ccb63de3 Gerd Hoffmann
    qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
566 ccb63de3 Gerd Hoffmann
                dev->id ? dev->id : "");
567 cae4956e Gerd Hoffmann
    indent += 2;
568 cae4956e Gerd Hoffmann
    if (dev->num_gpio_in) {
569 cae4956e Gerd Hoffmann
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
570 cae4956e Gerd Hoffmann
    }
571 cae4956e Gerd Hoffmann
    if (dev->num_gpio_out) {
572 cae4956e Gerd Hoffmann
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
573 cae4956e Gerd Hoffmann
    }
574 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->info->props, "dev", indent);
575 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
576 10c4c98a Gerd Hoffmann
    if (dev->parent_bus->info->print_dev)
577 10c4c98a Gerd Hoffmann
        dev->parent_bus->info->print_dev(mon, dev, indent);
578 72cf2d4f Blue Swirl
    QLIST_FOREACH(child, &dev->child_bus, sibling) {
579 cae4956e Gerd Hoffmann
        qbus_print(mon, child, indent);
580 cae4956e Gerd Hoffmann
    }
581 cae4956e Gerd Hoffmann
}
582 cae4956e Gerd Hoffmann
583 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent)
584 cae4956e Gerd Hoffmann
{
585 cae4956e Gerd Hoffmann
    struct DeviceState *dev;
586 cae4956e Gerd Hoffmann
587 cae4956e Gerd Hoffmann
    qdev_printf("bus: %s\n", bus->name);
588 cae4956e Gerd Hoffmann
    indent += 2;
589 10c4c98a Gerd Hoffmann
    qdev_printf("type %s\n", bus->info->name);
590 72cf2d4f Blue Swirl
    QLIST_FOREACH(dev, &bus->children, sibling) {
591 cae4956e Gerd Hoffmann
        qdev_print(mon, dev, indent);
592 cae4956e Gerd Hoffmann
    }
593 cae4956e Gerd Hoffmann
}
594 cae4956e Gerd Hoffmann
#undef qdev_printf
595 cae4956e Gerd Hoffmann
596 cae4956e Gerd Hoffmann
void do_info_qtree(Monitor *mon)
597 cae4956e Gerd Hoffmann
{
598 cae4956e Gerd Hoffmann
    if (main_system_bus)
599 cae4956e Gerd Hoffmann
        qbus_print(mon, main_system_bus, 0);
600 cae4956e Gerd Hoffmann
}
601 9316d30f Gerd Hoffmann
602 f6c64e0e Gerd Hoffmann
void do_info_qdm(Monitor *mon)
603 9316d30f Gerd Hoffmann
{
604 9316d30f Gerd Hoffmann
    DeviceInfo *info;
605 9316d30f Gerd Hoffmann
    char msg[256];
606 9316d30f Gerd Hoffmann
607 9316d30f Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
608 9316d30f Gerd Hoffmann
        qdev_print_devinfo(info, msg, sizeof(msg));
609 9316d30f Gerd Hoffmann
        monitor_printf(mon, "%s\n", msg);
610 9316d30f Gerd Hoffmann
    }
611 9316d30f Gerd Hoffmann
}