• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Dynamic device configuration and creation.
3  *
4  *  Copyright (c) 2009 CodeSourcery
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19  */
20 
21 /* The theory here is that it should be possible to create a machine without
22    knowledge of specific devices.  Historically board init routines have
23    passed a bunch of arguments to each device, requiring the board know
24    exactly which device it is dealing with.  This file provides an abstract
25    API for device configuration and initialization.  Devices will generally
26    inherit from a particular bus (e.g. PCI or I2C) rather than
27    this API directly.  */
28 
29 #include "net.h"
30 #include "qdev.h"
31 #include "sysemu.h"
32 #include "monitor.h"
33 
34 struct DeviceProperty {
35     const char *name;
36     DevicePropType type;
37     union {
38         uint64_t i;
39         void *ptr;
40     } value;
41     DeviceProperty *next;
42 };
43 
44 struct DeviceType {
45     DeviceInfo *info;
46     DeviceType *next;
47 };
48 
49 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
50 static BusState *main_system_bus;
51 
52 static DeviceType *device_type_list;
53 
54 /* Register a new device type.  */
qdev_register(DeviceInfo * info)55 void qdev_register(DeviceInfo *info)
56 {
57     DeviceType *t;
58 
59     assert(info->size >= sizeof(DeviceState));
60 
61     t = qemu_mallocz(sizeof(DeviceType));
62     t->next = device_type_list;
63     device_type_list = t;
64     t->info = info;
65 }
66 
67 /* Create a new device.  This only initializes the device state structure
68    and allows properties to be set.  qdev_init should be called to
69    initialize the actual device emulation.  */
qdev_create(BusState * bus,const char * name)70 DeviceState *qdev_create(BusState *bus, const char *name)
71 {
72     DeviceType *t;
73     DeviceState *dev;
74 
75     for (t = device_type_list; t; t = t->next) {
76         if (strcmp(t->info->name, name) == 0) {
77             break;
78         }
79     }
80     if (!t) {
81         hw_error("Unknown device '%s'\n", name);
82     }
83 
84     dev = qemu_mallocz(t->info->size);
85     dev->type = t;
86 
87     if (!bus) {
88         /* ???: This assumes system busses have no additional state.  */
89         if (!main_system_bus) {
90             main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
91                                           NULL, "main-system-bus");
92         }
93         bus = main_system_bus;
94     }
95     if (t->info->bus_type != bus->type) {
96         /* TODO: Print bus type names.  */
97         hw_error("Device '%s' on wrong bus type (%d/%d)", name,
98                  t->info->bus_type, bus->type);
99     }
100     dev->parent_bus = bus;
101     QLIST_INSERT_HEAD(&bus->children, dev, sibling);
102     return dev;
103 }
104 
105 /* Initialize a device.  Device properties should be set before calling
106    this function.  IRQs and MMIO regions should be connected/mapped after
107    calling this function.  */
qdev_init(DeviceState * dev)108 void qdev_init(DeviceState *dev)
109 {
110     dev->type->info->init(dev, dev->type->info);
111 }
112 
113 /* Unlink device from bus and free the structure.  */
qdev_free(DeviceState * dev)114 void qdev_free(DeviceState *dev)
115 {
116     QLIST_REMOVE(dev, sibling);
117     qemu_free(dev);
118 }
119 
create_prop(DeviceState * dev,const char * name,DevicePropType type)120 static DeviceProperty *create_prop(DeviceState *dev, const char *name,
121                                    DevicePropType type)
122 {
123     DeviceProperty *prop;
124 
125     /* TODO: Check for duplicate properties.  */
126     prop = qemu_mallocz(sizeof(*prop));
127     prop->name = qemu_strdup(name);
128     prop->type = type;
129     prop->next = dev->props;
130     dev->props = prop;
131 
132     return prop;
133 }
134 
qdev_set_prop_int(DeviceState * dev,const char * name,uint64_t value)135 void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
136 {
137     DeviceProperty *prop;
138 
139     prop = create_prop(dev, name, PROP_TYPE_INT);
140     prop->value.i = value;
141 }
142 
qdev_set_prop_dev(DeviceState * dev,const char * name,DeviceState * value)143 void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
144 {
145     DeviceProperty *prop;
146 
147     prop = create_prop(dev, name, PROP_TYPE_DEV);
148     prop->value.ptr = value;
149 }
150 
qdev_set_prop_ptr(DeviceState * dev,const char * name,void * value)151 void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
152 {
153     DeviceProperty *prop;
154 
155     prop = create_prop(dev, name, PROP_TYPE_PTR);
156     prop->value.ptr = value;
157 }
158 
qdev_set_netdev(DeviceState * dev,NICInfo * nd)159 void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
160 {
161     assert(!dev->nd);
162     dev->nd = nd;
163 }
164 
165 
166 /* Get a character (serial) device interface.  */
qdev_init_chardev(DeviceState * dev)167 CharDriverState *qdev_init_chardev(DeviceState *dev)
168 {
169     static int next_serial;
170     static int next_virtconsole;
171     /* FIXME: This is a nasty hack that needs to go away.  */
172     if (strncmp(dev->type->info->name, "virtio", 6) == 0) {
173         return virtcon_hds[next_virtconsole++];
174     } else {
175         return serial_hds[next_serial++];
176     }
177 }
178 
qdev_get_parent_bus(DeviceState * dev)179 BusState *qdev_get_parent_bus(DeviceState *dev)
180 {
181     return dev->parent_bus;
182 }
183 
find_prop(DeviceState * dev,const char * name,DevicePropType type)184 static DeviceProperty *find_prop(DeviceState *dev, const char *name,
185                                  DevicePropType type)
186 {
187     DeviceProperty *prop;
188 
189     for (prop = dev->props; prop; prop = prop->next) {
190         if (strcmp(prop->name, name) == 0) {
191             assert (prop->type == type);
192             return prop;
193         }
194     }
195     return NULL;
196 }
197 
qdev_get_prop_int(DeviceState * dev,const char * name,uint64_t def)198 uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
199 {
200     DeviceProperty *prop;
201 
202     prop = find_prop(dev, name, PROP_TYPE_INT);
203     if (!prop) {
204         return def;
205     }
206 
207     return prop->value.i;
208 }
209 
qdev_get_prop_ptr(DeviceState * dev,const char * name)210 void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
211 {
212     DeviceProperty *prop;
213 
214     prop = find_prop(dev, name, PROP_TYPE_PTR);
215     assert(prop);
216     return prop->value.ptr;
217 }
218 
qdev_get_prop_dev(DeviceState * dev,const char * name)219 DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
220 {
221     DeviceProperty *prop;
222 
223     prop = find_prop(dev, name, PROP_TYPE_DEV);
224     if (!prop) {
225         return NULL;
226     }
227     return prop->value.ptr;
228 }
229 
qdev_init_gpio_in(DeviceState * dev,qemu_irq_handler handler,int n)230 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
231 {
232     assert(dev->num_gpio_in == 0);
233     dev->num_gpio_in = n;
234     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
235 }
236 
qdev_init_gpio_out(DeviceState * dev,qemu_irq * pins,int n)237 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
238 {
239     assert(dev->num_gpio_out == 0);
240     dev->num_gpio_out = n;
241     dev->gpio_out = pins;
242 }
243 
qdev_get_gpio_in(DeviceState * dev,int n)244 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
245 {
246     assert(n >= 0 && n < dev->num_gpio_in);
247     return dev->gpio_in[n];
248 }
249 
qdev_connect_gpio_out(DeviceState * dev,int n,qemu_irq pin)250 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
251 {
252     assert(n >= 0 && n < dev->num_gpio_out);
253     dev->gpio_out[n] = pin;
254 }
255 
qdev_get_vlan_client(DeviceState * dev,NetCanReceive * can_receive,NetReceive * receive,NetReceiveIOV * receive_iov,NetCleanup * cleanup,void * opaque)256 VLANClientState *qdev_get_vlan_client(DeviceState *dev,
257                                       NetCanReceive *can_receive,
258                                       NetReceive *receive,
259                                       NetReceiveIOV *receive_iov,
260                                       NetCleanup *cleanup,
261                                       void *opaque)
262 {
263     NICInfo *nd = dev->nd;
264     assert(nd);
265     return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
266                                 receive, receive_iov, cleanup, opaque);
267 }
268 
269 
qdev_get_macaddr(DeviceState * dev,uint8_t * macaddr)270 void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
271 {
272     memcpy(macaddr, dev->nd->macaddr, 6);
273 }
274 
275 static int next_block_unit[IF_COUNT];
276 
277 /* Get a block device.  This should only be used for single-drive devices
278    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
279    appropriate bus.  */
qdev_init_bdrv(DeviceState * dev,BlockInterfaceType type)280 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
281 {
282     int unit = next_block_unit[type]++;
283     int index;
284 
285     index = drive_get_index(type, 0, unit);
286     if (index == -1) {
287         return NULL;
288     }
289     return drives_table[index].bdrv;
290 }
291 
qdev_get_child_bus(DeviceState * dev,const char * name)292 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
293 {
294     BusState *bus;
295 
296     QLIST_FOREACH(bus, &dev->child_bus, sibling) {
297         if (strcmp(name, bus->name) == 0) {
298             return bus;
299         }
300     }
301     return NULL;
302 }
303 
304 static int next_scsi_bus;
305 
306 /* Create a scsi bus, and attach devices to it.  */
307 /* TODO: Actually create a scsi bus for hotplug to use.  */
scsi_bus_new(DeviceState * host,SCSIAttachFn attach)308 void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
309 {
310    int bus = next_scsi_bus++;
311    int unit;
312    int index;
313 
314    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
315        index = drive_get_index(IF_SCSI, bus, unit);
316        if (index == -1) {
317            continue;
318        }
319        attach(host, drives_table[index].bdrv, unit);
320    }
321 }
322 
qbus_create(BusType type,size_t size,DeviceState * parent,const char * name)323 BusState *qbus_create(BusType type, size_t size,
324                       DeviceState *parent, const char *name)
325 {
326     BusState *bus;
327 
328     bus = qemu_mallocz(size);
329     bus->type = type;
330     bus->parent = parent;
331     bus->name = qemu_strdup(name);
332     QLIST_INIT(&bus->children);
333     if (parent) {
334         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
335     }
336     return bus;
337 }
338 
339 static const char *bus_type_names[] = {
340     [ BUS_TYPE_SYSTEM ] = "System",
341     [ BUS_TYPE_PCI ]    = "PCI",
342     [ BUS_TYPE_SCSI ]   = "SCSI",
343     [ BUS_TYPE_I2C ]    = "I2C",
344     [ BUS_TYPE_SSI ]    = "SSI",
345 };
346 
347 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
348 static void qbus_print(Monitor *mon, BusState *bus, int indent);
349 
qdev_print(Monitor * mon,DeviceState * dev,int indent)350 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
351 {
352     DeviceProperty *prop;
353     BusState *child;
354     qdev_printf("dev: %s\n", dev->type->info->name);
355     indent += 2;
356     if (dev->num_gpio_in) {
357         qdev_printf("gpio-in %d\n", dev->num_gpio_in);
358     }
359     if (dev->num_gpio_out) {
360         qdev_printf("gpio-out %d\n", dev->num_gpio_out);
361     }
362     for (prop = dev->props; prop; prop = prop->next) {
363         switch (prop->type) {
364         case PROP_TYPE_INT:
365             qdev_printf("prop-int %s 0x%" PRIx64 "\n", prop->name,
366                         prop->value.i);
367             break;
368         case PROP_TYPE_PTR:
369             qdev_printf("prop-ptr %s\n", prop->name);
370             break;
371         case PROP_TYPE_DEV:
372             qdev_printf("prop-dev %s %s\n", prop->name,
373                         ((DeviceState *)prop->value.ptr)->type->info->name);
374             break;
375         default:
376             qdev_printf("prop-unknown%d %s\n", prop->type, prop->name);
377             break;
378         }
379     }
380     switch (dev->parent_bus->type) {
381     case BUS_TYPE_SYSTEM:
382         sysbus_dev_print(mon, dev, indent);
383         break;
384     default:
385         break;
386     }
387     QLIST_FOREACH(child, &dev->child_bus, sibling) {
388         qbus_print(mon, child, indent);
389     }
390 }
391 
qbus_print(Monitor * mon,BusState * bus,int indent)392 static void qbus_print(Monitor *mon, BusState *bus, int indent)
393 {
394     struct DeviceState *dev;
395 
396     qdev_printf("bus: %s\n", bus->name);
397     indent += 2;
398     qdev_printf("type %s\n", bus_type_names[bus->type]);
399     QLIST_FOREACH(dev, &bus->children, sibling) {
400         qdev_print(mon, dev, indent);
401     }
402 }
403 #undef qdev_printf
404 
do_info_qtree(Monitor * mon)405 void do_info_qtree(Monitor *mon)
406 {
407     if (main_system_bus)
408         qbus_print(mon, main_system_bus, 0);
409 }
410