Statistics
| Branch: | Revision:

root / hw / qdev.c @ 81a322d4

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