Statistics
| Branch: | Revision:

root / hw / qdev.c @ c4470b25

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