Statistics
| Branch: | Revision:

root / hw / qdev.c @ 463af534

History | View | Annotate | Download (10.8 kB)

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
    const char *name;
46
    DeviceInfo *info;
47
    int size;
48
    DeviceType *next;
49
};
50

    
51
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
52
BusState *main_system_bus;
53

    
54
static DeviceType *device_type_list;
55

    
56
/* Register a new device type.  */
57
void qdev_register(const char *name, int size, DeviceInfo *info)
58
{
59
    DeviceType *t;
60

    
61
    assert(size >= sizeof(DeviceState));
62

    
63
    t = qemu_mallocz(sizeof(DeviceType));
64
    t->next = device_type_list;
65
    device_type_list = t;
66
    t->name = qemu_strdup(name);
67
    t->size = size;
68
    t->info = info;
69
}
70

    
71
/* Create a new device.  This only initializes the device state structure
72
   and allows properties to be set.  qdev_init should be called to
73
   initialize the actual device emulation.  */
74
DeviceState *qdev_create(BusState *bus, const char *name)
75
{
76
    DeviceType *t;
77
    DeviceState *dev;
78

    
79
    for (t = device_type_list; t; t = t->next) {
80
        if (strcmp(t->name, name) == 0) {
81
            break;
82
        }
83
    }
84
    if (!t) {
85
        hw_error("Unknown device '%s'\n", name);
86
    }
87

    
88
    dev = qemu_mallocz(t->size);
89
    dev->type = t;
90

    
91
    if (!bus) {
92
        /* ???: This assumes system busses have no additional state.  */
93
        if (!main_system_bus) {
94
            main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
95
                                          NULL, "main-system-bus");
96
        }
97
        bus = main_system_bus;
98
    }
99
    if (t->info->bus_type != bus->type) {
100
        /* TODO: Print bus type names.  */
101
        hw_error("Device '%s' on wrong bus type (%d/%d)", name,
102
                 t->info->bus_type, bus->type);
103
    }
104
    dev->parent_bus = bus;
105
    LIST_INSERT_HEAD(&bus->children, dev, sibling);
106
    return dev;
107
}
108

    
109
/* Initialize a device.  Device properties should be set before calling
110
   this function.  IRQs and MMIO regions should be connected/mapped after
111
   calling this function.  */
112
void qdev_init(DeviceState *dev)
113
{
114
    dev->type->info->init(dev, dev->type->info);
115
}
116

    
117
/* Unlink device from bus and free the structure.  */
118
void qdev_free(DeviceState *dev)
119
{
120
    LIST_REMOVE(dev, sibling);
121
    free(dev);
122
}
123

    
124
static DeviceProperty *create_prop(DeviceState *dev, const char *name,
125
                                   DevicePropType type)
126
{
127
    DeviceProperty *prop;
128

    
129
    /* TODO: Check for duplicate properties.  */
130
    prop = qemu_mallocz(sizeof(*prop));
131
    prop->name = qemu_strdup(name);
132
    prop->type = type;
133
    prop->next = dev->props;
134
    dev->props = prop;
135

    
136
    return prop;
137
}
138

    
139
void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
140
{
141
    DeviceProperty *prop;
142

    
143
    prop = create_prop(dev, name, PROP_TYPE_INT);
144
    prop->value.i = value;
145
}
146

    
147
void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
148
{
149
    DeviceProperty *prop;
150

    
151
    prop = create_prop(dev, name, PROP_TYPE_DEV);
152
    prop->value.ptr = value;
153
}
154

    
155
void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
156
{
157
    DeviceProperty *prop;
158

    
159
    prop = create_prop(dev, name, PROP_TYPE_PTR);
160
    prop->value.ptr = value;
161
}
162

    
163
void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
164
{
165
    assert(!dev->nd);
166
    dev->nd = nd;
167
}
168

    
169

    
170
/* Get a character (serial) device interface.  */
171
CharDriverState *qdev_init_chardev(DeviceState *dev)
172
{
173
    static int next_serial;
174
    static int next_virtconsole;
175
    /* FIXME: This is a nasty hack that needs to go away.  */
176
    if (strncmp(dev->type->name, "virtio", 6) == 0) {
177
        return virtcon_hds[next_virtconsole++];
178
    } else {
179
        return serial_hds[next_serial++];
180
    }
181
}
182

    
183
BusState *qdev_get_parent_bus(DeviceState *dev)
184
{
185
    return dev->parent_bus;
186
}
187

    
188
static DeviceProperty *find_prop(DeviceState *dev, const char *name,
189
                                 DevicePropType type)
190
{
191
    DeviceProperty *prop;
192

    
193
    for (prop = dev->props; prop; prop = prop->next) {
194
        if (strcmp(prop->name, name) == 0) {
195
            assert (prop->type == type);
196
            return prop;
197
        }
198
    }
199
    return NULL;
200
}
201

    
202
uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
203
{
204
    DeviceProperty *prop;
205

    
206
    prop = find_prop(dev, name, PROP_TYPE_INT);
207
    if (!prop) {
208
        return def;
209
    }
210

    
211
    return prop->value.i;
212
}
213

    
214
void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
215
{
216
    DeviceProperty *prop;
217

    
218
    prop = find_prop(dev, name, PROP_TYPE_PTR);
219
    assert(prop);
220
    return prop->value.ptr;
221
}
222

    
223
DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
224
{
225
    DeviceProperty *prop;
226

    
227
    prop = find_prop(dev, name, PROP_TYPE_DEV);
228
    if (!prop) {
229
        return NULL;
230
    }
231
    return prop->value.ptr;
232
}
233

    
234
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
235
{
236
    assert(dev->num_gpio_in == 0);
237
    dev->num_gpio_in = n;
238
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
239
}
240

    
241
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
242
{
243
    assert(dev->num_gpio_out == 0);
244
    dev->num_gpio_out = n;
245
    dev->gpio_out = pins;
246
}
247

    
248
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
249
{
250
    assert(n >= 0 && n < dev->num_gpio_in);
251
    return dev->gpio_in[n];
252
}
253

    
254
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
255
{
256
    assert(n >= 0 && n < dev->num_gpio_out);
257
    dev->gpio_out[n] = pin;
258
}
259

    
260
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
261
                                      IOCanRWHandler *fd_can_read,
262
                                      IOReadHandler *fd_read,
263
                                      IOReadvHandler *fd_readv,
264
                                      NetCleanup *cleanup,
265
                                      void *opaque)
266
{
267
    NICInfo *nd = dev->nd;
268
    assert(nd);
269
    return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, fd_can_read,
270
                                fd_read, fd_readv, cleanup, opaque);
271
}
272

    
273

    
274
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
275
{
276
    memcpy(macaddr, dev->nd->macaddr, 6);
277
}
278

    
279
static int next_block_unit[IF_COUNT];
280

    
281
/* Get a block device.  This should only be used for single-drive devices
282
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
283
   appropriate bus.  */
284
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
285
{
286
    int unit = next_block_unit[type]++;
287
    int index;
288

    
289
    index = drive_get_index(type, 0, unit);
290
    if (index == -1) {
291
        return NULL;
292
    }
293
    return drives_table[index].bdrv;
294
}
295

    
296
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
297
{
298
    BusState *bus;
299

    
300
    LIST_FOREACH(bus, &dev->child_bus, sibling) {
301
        if (strcmp(name, bus->name) == 0) {
302
            return bus;
303
        }
304
    }
305
    return NULL;
306
}
307

    
308
static int next_scsi_bus;
309

    
310
/* Create a scsi bus, and attach devices to it.  */
311
/* TODO: Actually create a scsi bus for hotplug to use.  */
312
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
313
{
314
   int bus = next_scsi_bus++;
315
   int unit;
316
   int index;
317

    
318
   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
319
       index = drive_get_index(IF_SCSI, bus, unit);
320
       if (index == -1) {
321
           continue;
322
       }
323
       attach(host, drives_table[index].bdrv, unit);
324
   }
325
}
326

    
327
BusState *qbus_create(BusType type, size_t size,
328
                      DeviceState *parent, const char *name)
329
{
330
    BusState *bus;
331

    
332
    bus = qemu_mallocz(size);
333
    bus->type = type;
334
    bus->parent = parent;
335
    bus->name = qemu_strdup(name);
336
    LIST_INIT(&bus->children);
337
    if (parent) {
338
        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
339
    }
340
    return bus;
341
}
342

    
343
static const char *bus_type_names[] = {
344
    [ BUS_TYPE_SYSTEM ] = "System",
345
    [ BUS_TYPE_PCI ]    = "PCI",
346
    [ BUS_TYPE_SCSI ]   = "SCSI",
347
    [ BUS_TYPE_I2C ]    = "I2C",
348
    [ BUS_TYPE_SSI ]    = "SSI",
349
};
350

    
351
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
352
static void qbus_print(Monitor *mon, BusState *bus, int indent);
353

    
354
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
355
{
356
    DeviceProperty *prop;
357
    BusState *child;
358
    qdev_printf("dev: %s\n", dev->type->name);
359
    indent += 2;
360
    if (dev->num_gpio_in) {
361
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
362
    }
363
    if (dev->num_gpio_out) {
364
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
365
    }
366
    for (prop = dev->props; prop; prop = prop->next) {
367
        switch (prop->type) {
368
        case PROP_TYPE_INT:
369
            qdev_printf("prop-int %s 0x%" PRIx64 "\n", prop->name,
370
                        prop->value.i);
371
            break;
372
        case PROP_TYPE_PTR:
373
            qdev_printf("prop-ptr %s\n", prop->name);
374
            break;
375
        case PROP_TYPE_DEV:
376
            qdev_printf("prop-dev %s %s\n", prop->name,
377
                        ((DeviceState *)prop->value.ptr)->type->name);
378
            break;
379
        default:
380
            qdev_printf("prop-unknown%d %s\n", prop->type, prop->name);
381
            break;
382
        }
383
    }
384
    switch (dev->parent_bus->type) {
385
    case BUS_TYPE_SYSTEM:
386
        sysbus_dev_print(mon, dev, indent);
387
        break;
388
    default:
389
        break;
390
    }
391
    LIST_FOREACH(child, &dev->child_bus, sibling) {
392
        qbus_print(mon, child, indent);
393
    }
394
}
395

    
396
static void qbus_print(Monitor *mon, BusState *bus, int indent)
397
{
398
    struct DeviceState *dev;
399

    
400
    qdev_printf("bus: %s\n", bus->name);
401
    indent += 2;
402
    qdev_printf("type %s\n", bus_type_names[bus->type]);
403
    LIST_FOREACH(dev, &bus->children, sibling) {
404
        qdev_print(mon, dev, indent);
405
    }
406
}
407
#undef qdev_printf
408

    
409
void do_info_qtree(Monitor *mon)
410
{
411
    if (main_system_bus)
412
        qbus_print(mon, main_system_bus, 0);
413
}