Statistics
| Branch: | Revision:

root / hw / qdev.c @ a8a358bf

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