Statistics
| Branch: | Revision:

root / hw / qdev.c @ 8167ee88

History | View | Annotate | Download (10.1 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, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
/* The theory here is that it should be possible to create a machine without
21
   knowledge of specific devices.  Historically board init routines have
22
   passed a bunch of arguments to each device, requiring the board know
23
   exactly which device it is dealing with.  This file provides an abstract
24
   API for device configuration and initialization.  Devices will generally
25
   inherit from a particular bus (e.g. PCI or I2C) rather than
26
   this API directly.  */
27

    
28
#include "net.h"
29
#include "qdev.h"
30
#include "sysemu.h"
31
#include "monitor.h"
32

    
33
struct DeviceProperty {
34
    const char *name;
35
    DevicePropType type;
36
    union {
37
        uint64_t i;
38
        void *ptr;
39
    } value;
40
    DeviceProperty *next;
41
};
42

    
43
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
44
static BusState *main_system_bus;
45
extern struct BusInfo system_bus_info;
46

    
47
static DeviceInfo *device_info_list;
48

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

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

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

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

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

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

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

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

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

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

    
119
    return prop;
120
}
121

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

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

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

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

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

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

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

    
152

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
257

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

    
263
static int next_block_unit[IF_COUNT];
264

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

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

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

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

    
292
static int next_scsi_bus;
293

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

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

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

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

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

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

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

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

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