Statistics
| Branch: | Revision:

root / hw / qdev.c @ ae50b274

History | View | Annotate | Download (10.2 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
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
45
static BusState *main_system_bus;
46
extern struct BusInfo system_bus_info;
47

    
48
static DeviceInfo *device_info_list;
49

    
50
/* Register a new device type.  */
51
void qdev_register(DeviceInfo *info)
52
{
53
    assert(info->size >= sizeof(DeviceState));
54
    assert(!info->next);
55

    
56
    info->next = device_info_list;
57
    device_info_list = info;
58
}
59

    
60
/* Create a new device.  This only initializes the device state structure
61
   and allows properties to be set.  qdev_init should be called to
62
   initialize the actual device emulation.  */
63
DeviceState *qdev_create(BusState *bus, const char *name)
64
{
65
    DeviceInfo *info;
66
    DeviceState *dev;
67

    
68
    if (!bus) {
69
        if (!main_system_bus) {
70
            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
71
        }
72
        bus = main_system_bus;
73
    }
74

    
75
    for (info = device_info_list; info != NULL; info = info->next) {
76
        if (info->bus_info != bus->info)
77
            continue;
78
        if (strcmp(info->name, name) != 0)
79
            continue;
80
        break;
81
    }
82
    if (!info) {
83
        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
84
    }
85

    
86
    dev = qemu_mallocz(info->size);
87
    dev->info = info;
88
    dev->parent_bus = bus;
89
    LIST_INSERT_HEAD(&bus->children, dev, sibling);
90
    return dev;
91
}
92

    
93
/* Initialize a device.  Device properties should be set before calling
94
   this function.  IRQs and MMIO regions should be connected/mapped after
95
   calling this function.  */
96
void qdev_init(DeviceState *dev)
97
{
98
    dev->info->init(dev, dev->info);
99
}
100

    
101
/* Unlink device from bus and free the structure.  */
102
void qdev_free(DeviceState *dev)
103
{
104
    LIST_REMOVE(dev, sibling);
105
    free(dev);
106
}
107

    
108
static DeviceProperty *create_prop(DeviceState *dev, const char *name,
109
                                   DevicePropType type)
110
{
111
    DeviceProperty *prop;
112

    
113
    /* TODO: Check for duplicate properties.  */
114
    prop = qemu_mallocz(sizeof(*prop));
115
    prop->name = qemu_strdup(name);
116
    prop->type = type;
117
    prop->next = dev->props;
118
    dev->props = prop;
119

    
120
    return prop;
121
}
122

    
123
void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
124
{
125
    DeviceProperty *prop;
126

    
127
    prop = create_prop(dev, name, PROP_TYPE_INT);
128
    prop->value.i = value;
129
}
130

    
131
void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
132
{
133
    DeviceProperty *prop;
134

    
135
    prop = create_prop(dev, name, PROP_TYPE_DEV);
136
    prop->value.ptr = value;
137
}
138

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

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

    
147
void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
148
{
149
    assert(!dev->nd);
150
    dev->nd = nd;
151
}
152

    
153

    
154
/* Get a character (serial) device interface.  */
155
CharDriverState *qdev_init_chardev(DeviceState *dev)
156
{
157
    static int next_serial;
158
    static int next_virtconsole;
159
    /* FIXME: This is a nasty hack that needs to go away.  */
160
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
161
        return virtcon_hds[next_virtconsole++];
162
    } else {
163
        return serial_hds[next_serial++];
164
    }
165
}
166

    
167
BusState *qdev_get_parent_bus(DeviceState *dev)
168
{
169
    return dev->parent_bus;
170
}
171

    
172
static DeviceProperty *find_prop(DeviceState *dev, const char *name,
173
                                 DevicePropType type)
174
{
175
    DeviceProperty *prop;
176

    
177
    for (prop = dev->props; prop; prop = prop->next) {
178
        if (strcmp(prop->name, name) == 0) {
179
            assert (prop->type == type);
180
            return prop;
181
        }
182
    }
183
    return NULL;
184
}
185

    
186
uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
187
{
188
    DeviceProperty *prop;
189

    
190
    prop = find_prop(dev, name, PROP_TYPE_INT);
191
    if (!prop) {
192
        return def;
193
    }
194

    
195
    return prop->value.i;
196
}
197

    
198
void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
199
{
200
    DeviceProperty *prop;
201

    
202
    prop = find_prop(dev, name, PROP_TYPE_PTR);
203
    assert(prop);
204
    return prop->value.ptr;
205
}
206

    
207
DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
208
{
209
    DeviceProperty *prop;
210

    
211
    prop = find_prop(dev, name, PROP_TYPE_DEV);
212
    if (!prop) {
213
        return NULL;
214
    }
215
    return prop->value.ptr;
216
}
217

    
218
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
219
{
220
    assert(dev->num_gpio_in == 0);
221
    dev->num_gpio_in = n;
222
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
223
}
224

    
225
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
226
{
227
    assert(dev->num_gpio_out == 0);
228
    dev->num_gpio_out = n;
229
    dev->gpio_out = pins;
230
}
231

    
232
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
233
{
234
    assert(n >= 0 && n < dev->num_gpio_in);
235
    return dev->gpio_in[n];
236
}
237

    
238
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
239
{
240
    assert(n >= 0 && n < dev->num_gpio_out);
241
    dev->gpio_out[n] = pin;
242
}
243

    
244
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
245
                                      NetCanReceive *can_receive,
246
                                      NetReceive *receive,
247
                                      NetReceiveIOV *receive_iov,
248
                                      NetCleanup *cleanup,
249
                                      void *opaque)
250
{
251
    NICInfo *nd = dev->nd;
252
    assert(nd);
253
    nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
254
                                  receive, receive_iov, cleanup, opaque);
255
    return nd->vc;
256
}
257

    
258

    
259
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
260
{
261
    memcpy(macaddr, dev->nd->macaddr, 6);
262
}
263

    
264
static int next_block_unit[IF_COUNT];
265

    
266
/* Get a block device.  This should only be used for single-drive devices
267
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
268
   appropriate bus.  */
269
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
270
{
271
    int unit = next_block_unit[type]++;
272
    int index;
273

    
274
    index = drive_get_index(type, 0, unit);
275
    if (index == -1) {
276
        return NULL;
277
    }
278
    return drives_table[index].bdrv;
279
}
280

    
281
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
282
{
283
    BusState *bus;
284

    
285
    LIST_FOREACH(bus, &dev->child_bus, sibling) {
286
        if (strcmp(name, bus->name) == 0) {
287
            return bus;
288
        }
289
    }
290
    return NULL;
291
}
292

    
293
static int next_scsi_bus;
294

    
295
/* Create a scsi bus, and attach devices to it.  */
296
/* TODO: Actually create a scsi bus for hotplug to use.  */
297
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
298
{
299
   int bus = next_scsi_bus++;
300
   int unit;
301
   int index;
302

    
303
   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
304
       index = drive_get_index(IF_SCSI, bus, unit);
305
       if (index == -1) {
306
           continue;
307
       }
308
       attach(host, drives_table[index].bdrv, unit);
309
   }
310
}
311

    
312
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
313
{
314
    BusState *bus;
315

    
316
    bus = qemu_mallocz(info->size);
317
    bus->info = info;
318
    bus->parent = parent;
319
    bus->name = qemu_strdup(name);
320
    LIST_INIT(&bus->children);
321
    if (parent) {
322
        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
323
    }
324
    return bus;
325
}
326

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

    
330
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
331
{
332
    DeviceProperty *prop;
333
    BusState *child;
334
    qdev_printf("dev: %s\n", dev->info->name);
335
    indent += 2;
336
    if (dev->num_gpio_in) {
337
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
338
    }
339
    if (dev->num_gpio_out) {
340
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
341
    }
342
    for (prop = dev->props; prop; prop = prop->next) {
343
        switch (prop->type) {
344
        case PROP_TYPE_INT:
345
            qdev_printf("prop-int %s 0x%" PRIx64 "\n", prop->name,
346
                        prop->value.i);
347
            break;
348
        case PROP_TYPE_PTR:
349
            qdev_printf("prop-ptr %s\n", prop->name);
350
            break;
351
        case PROP_TYPE_DEV:
352
            qdev_printf("prop-dev %s %s\n", prop->name,
353
                        ((DeviceState *)prop->value.ptr)->info->name);
354
            break;
355
        default:
356
            qdev_printf("prop-unknown%d %s\n", prop->type, prop->name);
357
            break;
358
        }
359
    }
360
    if (dev->parent_bus->info->print_dev)
361
        dev->parent_bus->info->print_dev(mon, dev, indent);
362
    LIST_FOREACH(child, &dev->child_bus, sibling) {
363
        qbus_print(mon, child, indent);
364
    }
365
}
366

    
367
static void qbus_print(Monitor *mon, BusState *bus, int indent)
368
{
369
    struct DeviceState *dev;
370

    
371
    qdev_printf("bus: %s\n", bus->name);
372
    indent += 2;
373
    qdev_printf("type %s\n", bus->info->name);
374
    LIST_FOREACH(dev, &bus->children, sibling) {
375
        qdev_print(mon, dev, indent);
376
    }
377
}
378
#undef qdev_printf
379

    
380
void do_info_qtree(Monitor *mon)
381
{
382
    if (main_system_bus)
383
        qbus_print(mon, main_system_bus, 0);
384
}