Statistics
| Branch: | Revision:

root / hw / qdev.c @ 7ed208c4

History | View | Annotate | Download (8.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 10c4c98a Gerd Hoffmann
extern struct BusInfo system_bus_info;
36 4d6ae674 Paul Brook
37 042f84d0 Gerd Hoffmann
static DeviceInfo *device_info_list;
38 aae9460e Paul Brook
39 aae9460e Paul Brook
/* Register a new device type.  */
40 074f2fff Gerd Hoffmann
void qdev_register(DeviceInfo *info)
41 aae9460e Paul Brook
{
42 074f2fff Gerd Hoffmann
    assert(info->size >= sizeof(DeviceState));
43 042f84d0 Gerd Hoffmann
    assert(!info->next);
44 aae9460e Paul Brook
45 042f84d0 Gerd Hoffmann
    info->next = device_info_list;
46 042f84d0 Gerd Hoffmann
    device_info_list = info;
47 aae9460e Paul Brook
}
48 aae9460e Paul Brook
49 81ebb98b Gerd Hoffmann
static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
50 81ebb98b Gerd Hoffmann
{
51 81ebb98b Gerd Hoffmann
    DeviceInfo *info;
52 81ebb98b Gerd Hoffmann
53 3320e56e Gerd Hoffmann
    /* first check device names */
54 81ebb98b Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
55 81ebb98b Gerd Hoffmann
        if (bus_info && info->bus_info != bus_info)
56 81ebb98b Gerd Hoffmann
            continue;
57 81ebb98b Gerd Hoffmann
        if (strcmp(info->name, name) != 0)
58 81ebb98b Gerd Hoffmann
            continue;
59 81ebb98b Gerd Hoffmann
        return info;
60 81ebb98b Gerd Hoffmann
    }
61 3320e56e Gerd Hoffmann
62 3320e56e Gerd Hoffmann
    /* failing that check the aliases */
63 3320e56e Gerd Hoffmann
    for (info = device_info_list; info != NULL; info = info->next) {
64 3320e56e Gerd Hoffmann
        if (bus_info && info->bus_info != bus_info)
65 3320e56e Gerd Hoffmann
            continue;
66 3320e56e Gerd Hoffmann
        if (!info->alias)
67 3320e56e Gerd Hoffmann
            continue;
68 3320e56e Gerd Hoffmann
        if (strcmp(info->alias, name) != 0)
69 3320e56e Gerd Hoffmann
            continue;
70 3320e56e Gerd Hoffmann
        return info;
71 3320e56e Gerd Hoffmann
    }
72 81ebb98b Gerd Hoffmann
    return NULL;
73 81ebb98b Gerd Hoffmann
}
74 81ebb98b Gerd Hoffmann
75 aae9460e Paul Brook
/* Create a new device.  This only initializes the device state structure
76 aae9460e Paul Brook
   and allows properties to be set.  qdev_init should be called to
77 aae9460e Paul Brook
   initialize the actual device emulation.  */
78 02e2da45 Paul Brook
DeviceState *qdev_create(BusState *bus, const char *name)
79 aae9460e Paul Brook
{
80 042f84d0 Gerd Hoffmann
    DeviceInfo *info;
81 aae9460e Paul Brook
    DeviceState *dev;
82 aae9460e Paul Brook
83 10c4c98a Gerd Hoffmann
    if (!bus) {
84 10c4c98a Gerd Hoffmann
        if (!main_system_bus) {
85 10c4c98a Gerd Hoffmann
            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
86 aae9460e Paul Brook
        }
87 10c4c98a Gerd Hoffmann
        bus = main_system_bus;
88 10c4c98a Gerd Hoffmann
    }
89 10c4c98a Gerd Hoffmann
90 81ebb98b Gerd Hoffmann
    info = qdev_find_info(bus->info, name);
91 042f84d0 Gerd Hoffmann
    if (!info) {
92 10c4c98a Gerd Hoffmann
        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
93 aae9460e Paul Brook
    }
94 aae9460e Paul Brook
95 042f84d0 Gerd Hoffmann
    dev = qemu_mallocz(info->size);
96 042f84d0 Gerd Hoffmann
    dev->info = info;
97 02e2da45 Paul Brook
    dev->parent_bus = bus;
98 ee6847d1 Gerd Hoffmann
    qdev_prop_set_defaults(dev, dev->info->props);
99 ee6847d1 Gerd Hoffmann
    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
100 b6b61144 Gerd Hoffmann
    qdev_prop_set_compat(dev);
101 02e2da45 Paul Brook
    LIST_INSERT_HEAD(&bus->children, dev, sibling);
102 aae9460e Paul Brook
    return dev;
103 aae9460e Paul Brook
}
104 aae9460e Paul Brook
105 aae9460e Paul Brook
/* Initialize a device.  Device properties should be set before calling
106 aae9460e Paul Brook
   this function.  IRQs and MMIO regions should be connected/mapped after
107 aae9460e Paul Brook
   calling this function.  */
108 aae9460e Paul Brook
void qdev_init(DeviceState *dev)
109 aae9460e Paul Brook
{
110 042f84d0 Gerd Hoffmann
    dev->info->init(dev, dev->info);
111 02e2da45 Paul Brook
}
112 02e2da45 Paul Brook
113 02e2da45 Paul Brook
/* Unlink device from bus and free the structure.  */
114 02e2da45 Paul Brook
void qdev_free(DeviceState *dev)
115 02e2da45 Paul Brook
{
116 02e2da45 Paul Brook
    LIST_REMOVE(dev, sibling);
117 ccb63de3 Gerd Hoffmann
    qemu_free(dev->id);
118 ccb63de3 Gerd Hoffmann
    qemu_free(dev);
119 aae9460e Paul Brook
}
120 aae9460e Paul Brook
121 aae9460e Paul Brook
/* Get a character (serial) device interface.  */
122 aae9460e Paul Brook
CharDriverState *qdev_init_chardev(DeviceState *dev)
123 aae9460e Paul Brook
{
124 aae9460e Paul Brook
    static int next_serial;
125 aae9460e Paul Brook
    static int next_virtconsole;
126 aae9460e Paul Brook
    /* FIXME: This is a nasty hack that needs to go away.  */
127 042f84d0 Gerd Hoffmann
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
128 aae9460e Paul Brook
        return virtcon_hds[next_virtconsole++];
129 aae9460e Paul Brook
    } else {
130 aae9460e Paul Brook
        return serial_hds[next_serial++];
131 aae9460e Paul Brook
    }
132 aae9460e Paul Brook
}
133 aae9460e Paul Brook
134 02e2da45 Paul Brook
BusState *qdev_get_parent_bus(DeviceState *dev)
135 aae9460e Paul Brook
{
136 02e2da45 Paul Brook
    return dev->parent_bus;
137 aae9460e Paul Brook
}
138 aae9460e Paul Brook
139 aae9460e Paul Brook
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
140 aae9460e Paul Brook
{
141 aae9460e Paul Brook
    assert(dev->num_gpio_in == 0);
142 aae9460e Paul Brook
    dev->num_gpio_in = n;
143 aae9460e Paul Brook
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
144 aae9460e Paul Brook
}
145 aae9460e Paul Brook
146 aae9460e Paul Brook
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
147 aae9460e Paul Brook
{
148 aae9460e Paul Brook
    assert(dev->num_gpio_out == 0);
149 aae9460e Paul Brook
    dev->num_gpio_out = n;
150 aae9460e Paul Brook
    dev->gpio_out = pins;
151 aae9460e Paul Brook
}
152 aae9460e Paul Brook
153 aae9460e Paul Brook
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
154 aae9460e Paul Brook
{
155 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_in);
156 aae9460e Paul Brook
    return dev->gpio_in[n];
157 aae9460e Paul Brook
}
158 aae9460e Paul Brook
159 aae9460e Paul Brook
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
160 aae9460e Paul Brook
{
161 aae9460e Paul Brook
    assert(n >= 0 && n < dev->num_gpio_out);
162 aae9460e Paul Brook
    dev->gpio_out[n] = pin;
163 aae9460e Paul Brook
}
164 aae9460e Paul Brook
165 9d07d757 Paul Brook
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
166 cda9046b Mark McLoughlin
                                      NetCanReceive *can_receive,
167 cda9046b Mark McLoughlin
                                      NetReceive *receive,
168 cda9046b Mark McLoughlin
                                      NetReceiveIOV *receive_iov,
169 9d07d757 Paul Brook
                                      NetCleanup *cleanup,
170 9d07d757 Paul Brook
                                      void *opaque)
171 9d07d757 Paul Brook
{
172 9d07d757 Paul Brook
    NICInfo *nd = dev->nd;
173 9d07d757 Paul Brook
    assert(nd);
174 ae50b274 Mark McLoughlin
    nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
175 ae50b274 Mark McLoughlin
                                  receive, receive_iov, cleanup, opaque);
176 ae50b274 Mark McLoughlin
    return nd->vc;
177 9d07d757 Paul Brook
}
178 9d07d757 Paul Brook
179 9d07d757 Paul Brook
180 9d07d757 Paul Brook
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
181 9d07d757 Paul Brook
{
182 9d07d757 Paul Brook
    memcpy(macaddr, dev->nd->macaddr, 6);
183 9d07d757 Paul Brook
}
184 9d07d757 Paul Brook
185 aae9460e Paul Brook
static int next_block_unit[IF_COUNT];
186 aae9460e Paul Brook
187 aae9460e Paul Brook
/* Get a block device.  This should only be used for single-drive devices
188 aae9460e Paul Brook
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
189 aae9460e Paul Brook
   appropriate bus.  */
190 aae9460e Paul Brook
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
191 aae9460e Paul Brook
{
192 aae9460e Paul Brook
    int unit = next_block_unit[type]++;
193 aae9460e Paul Brook
    int index;
194 aae9460e Paul Brook
195 aae9460e Paul Brook
    index = drive_get_index(type, 0, unit);
196 aae9460e Paul Brook
    if (index == -1) {
197 aae9460e Paul Brook
        return NULL;
198 aae9460e Paul Brook
    }
199 aae9460e Paul Brook
    return drives_table[index].bdrv;
200 aae9460e Paul Brook
}
201 4d6ae674 Paul Brook
202 02e2da45 Paul Brook
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
203 4d6ae674 Paul Brook
{
204 02e2da45 Paul Brook
    BusState *bus;
205 4d6ae674 Paul Brook
206 02e2da45 Paul Brook
    LIST_FOREACH(bus, &dev->child_bus, sibling) {
207 4d6ae674 Paul Brook
        if (strcmp(name, bus->name) == 0) {
208 02e2da45 Paul Brook
            return bus;
209 4d6ae674 Paul Brook
        }
210 4d6ae674 Paul Brook
    }
211 4d6ae674 Paul Brook
    return NULL;
212 4d6ae674 Paul Brook
}
213 4d6ae674 Paul Brook
214 6f68ecb2 Paul Brook
static int next_scsi_bus;
215 6f68ecb2 Paul Brook
216 6f68ecb2 Paul Brook
/* Create a scsi bus, and attach devices to it.  */
217 6f68ecb2 Paul Brook
/* TODO: Actually create a scsi bus for hotplug to use.  */
218 6f68ecb2 Paul Brook
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
219 6f68ecb2 Paul Brook
{
220 6f68ecb2 Paul Brook
   int bus = next_scsi_bus++;
221 6f68ecb2 Paul Brook
   int unit;
222 6f68ecb2 Paul Brook
   int index;
223 6f68ecb2 Paul Brook
224 6f68ecb2 Paul Brook
   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
225 6f68ecb2 Paul Brook
       index = drive_get_index(IF_SCSI, bus, unit);
226 6f68ecb2 Paul Brook
       if (index == -1) {
227 6f68ecb2 Paul Brook
           continue;
228 6f68ecb2 Paul Brook
       }
229 6f68ecb2 Paul Brook
       attach(host, drives_table[index].bdrv, unit);
230 6f68ecb2 Paul Brook
   }
231 6f68ecb2 Paul Brook
}
232 02e2da45 Paul Brook
233 10c4c98a Gerd Hoffmann
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
234 02e2da45 Paul Brook
{
235 02e2da45 Paul Brook
    BusState *bus;
236 02e2da45 Paul Brook
237 10c4c98a Gerd Hoffmann
    bus = qemu_mallocz(info->size);
238 10c4c98a Gerd Hoffmann
    bus->info = info;
239 02e2da45 Paul Brook
    bus->parent = parent;
240 02e2da45 Paul Brook
    bus->name = qemu_strdup(name);
241 02e2da45 Paul Brook
    LIST_INIT(&bus->children);
242 02e2da45 Paul Brook
    if (parent) {
243 02e2da45 Paul Brook
        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
244 02e2da45 Paul Brook
    }
245 02e2da45 Paul Brook
    return bus;
246 02e2da45 Paul Brook
}
247 cae4956e Gerd Hoffmann
248 cae4956e Gerd Hoffmann
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
249 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent);
250 cae4956e Gerd Hoffmann
251 ee6847d1 Gerd Hoffmann
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
252 ee6847d1 Gerd Hoffmann
                             const char *prefix, int indent)
253 ee6847d1 Gerd Hoffmann
{
254 ee6847d1 Gerd Hoffmann
    char buf[64];
255 ee6847d1 Gerd Hoffmann
256 ee6847d1 Gerd Hoffmann
    if (!props)
257 ee6847d1 Gerd Hoffmann
        return;
258 ee6847d1 Gerd Hoffmann
    while (props->name) {
259 ee6847d1 Gerd Hoffmann
        if (props->info->print) {
260 ee6847d1 Gerd Hoffmann
            props->info->print(dev, props, buf, sizeof(buf));
261 ee6847d1 Gerd Hoffmann
            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
262 ee6847d1 Gerd Hoffmann
        }
263 ee6847d1 Gerd Hoffmann
        props++;
264 ee6847d1 Gerd Hoffmann
    }
265 ee6847d1 Gerd Hoffmann
}
266 ee6847d1 Gerd Hoffmann
267 cae4956e Gerd Hoffmann
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
268 cae4956e Gerd Hoffmann
{
269 cae4956e Gerd Hoffmann
    BusState *child;
270 ccb63de3 Gerd Hoffmann
    qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
271 ccb63de3 Gerd Hoffmann
                dev->id ? dev->id : "");
272 cae4956e Gerd Hoffmann
    indent += 2;
273 cae4956e Gerd Hoffmann
    if (dev->num_gpio_in) {
274 cae4956e Gerd Hoffmann
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
275 cae4956e Gerd Hoffmann
    }
276 cae4956e Gerd Hoffmann
    if (dev->num_gpio_out) {
277 cae4956e Gerd Hoffmann
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
278 cae4956e Gerd Hoffmann
    }
279 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->info->props, "dev", indent);
280 ee6847d1 Gerd Hoffmann
    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
281 10c4c98a Gerd Hoffmann
    if (dev->parent_bus->info->print_dev)
282 10c4c98a Gerd Hoffmann
        dev->parent_bus->info->print_dev(mon, dev, indent);
283 cae4956e Gerd Hoffmann
    LIST_FOREACH(child, &dev->child_bus, sibling) {
284 cae4956e Gerd Hoffmann
        qbus_print(mon, child, indent);
285 cae4956e Gerd Hoffmann
    }
286 cae4956e Gerd Hoffmann
}
287 cae4956e Gerd Hoffmann
288 cae4956e Gerd Hoffmann
static void qbus_print(Monitor *mon, BusState *bus, int indent)
289 cae4956e Gerd Hoffmann
{
290 cae4956e Gerd Hoffmann
    struct DeviceState *dev;
291 cae4956e Gerd Hoffmann
292 cae4956e Gerd Hoffmann
    qdev_printf("bus: %s\n", bus->name);
293 cae4956e Gerd Hoffmann
    indent += 2;
294 10c4c98a Gerd Hoffmann
    qdev_printf("type %s\n", bus->info->name);
295 cae4956e Gerd Hoffmann
    LIST_FOREACH(dev, &bus->children, sibling) {
296 cae4956e Gerd Hoffmann
        qdev_print(mon, dev, indent);
297 cae4956e Gerd Hoffmann
    }
298 cae4956e Gerd Hoffmann
}
299 cae4956e Gerd Hoffmann
#undef qdev_printf
300 cae4956e Gerd Hoffmann
301 cae4956e Gerd Hoffmann
void do_info_qtree(Monitor *mon)
302 cae4956e Gerd Hoffmann
{
303 cae4956e Gerd Hoffmann
    if (main_system_bus)
304 cae4956e Gerd Hoffmann
        qbus_print(mon, main_system_bus, 0);
305 cae4956e Gerd Hoffmann
}