Statistics
| Branch: | Revision:

root / hw / qdev.c @ ee6847d1

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

    
37
static DeviceInfo *device_info_list;
38

    
39
/* Register a new device type.  */
40
void qdev_register(DeviceInfo *info)
41
{
42
    assert(info->size >= sizeof(DeviceState));
43
    assert(!info->next);
44

    
45
    info->next = device_info_list;
46
    device_info_list = info;
47
}
48

    
49
/* Create a new device.  This only initializes the device state structure
50
   and allows properties to be set.  qdev_init should be called to
51
   initialize the actual device emulation.  */
52
DeviceState *qdev_create(BusState *bus, const char *name)
53
{
54
    DeviceInfo *info;
55
    DeviceState *dev;
56

    
57
    if (!bus) {
58
        if (!main_system_bus) {
59
            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
60
        }
61
        bus = main_system_bus;
62
    }
63

    
64
    for (info = device_info_list; info != NULL; info = info->next) {
65
        if (info->bus_info != bus->info)
66
            continue;
67
        if (strcmp(info->name, name) != 0)
68
            continue;
69
        break;
70
    }
71
    if (!info) {
72
        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
73
    }
74

    
75
    dev = qemu_mallocz(info->size);
76
    dev->info = info;
77
    dev->parent_bus = bus;
78
    qdev_prop_set_defaults(dev, dev->info->props);
79
    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
80
    LIST_INSERT_HEAD(&bus->children, dev, sibling);
81
    return dev;
82
}
83

    
84
/* Initialize a device.  Device properties should be set before calling
85
   this function.  IRQs and MMIO regions should be connected/mapped after
86
   calling this function.  */
87
void qdev_init(DeviceState *dev)
88
{
89
    dev->info->init(dev, dev->info);
90
}
91

    
92
/* Unlink device from bus and free the structure.  */
93
void qdev_free(DeviceState *dev)
94
{
95
    LIST_REMOVE(dev, sibling);
96
    free(dev);
97
}
98

    
99
/* Get a character (serial) device interface.  */
100
CharDriverState *qdev_init_chardev(DeviceState *dev)
101
{
102
    static int next_serial;
103
    static int next_virtconsole;
104
    /* FIXME: This is a nasty hack that needs to go away.  */
105
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
106
        return virtcon_hds[next_virtconsole++];
107
    } else {
108
        return serial_hds[next_serial++];
109
    }
110
}
111

    
112
BusState *qdev_get_parent_bus(DeviceState *dev)
113
{
114
    return dev->parent_bus;
115
}
116

    
117
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
118
{
119
    assert(dev->num_gpio_in == 0);
120
    dev->num_gpio_in = n;
121
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
122
}
123

    
124
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
125
{
126
    assert(dev->num_gpio_out == 0);
127
    dev->num_gpio_out = n;
128
    dev->gpio_out = pins;
129
}
130

    
131
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
132
{
133
    assert(n >= 0 && n < dev->num_gpio_in);
134
    return dev->gpio_in[n];
135
}
136

    
137
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
138
{
139
    assert(n >= 0 && n < dev->num_gpio_out);
140
    dev->gpio_out[n] = pin;
141
}
142

    
143
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
144
                                      NetCanReceive *can_receive,
145
                                      NetReceive *receive,
146
                                      NetReceiveIOV *receive_iov,
147
                                      NetCleanup *cleanup,
148
                                      void *opaque)
149
{
150
    NICInfo *nd = dev->nd;
151
    assert(nd);
152
    nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
153
                                  receive, receive_iov, cleanup, opaque);
154
    return nd->vc;
155
}
156

    
157

    
158
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
159
{
160
    memcpy(macaddr, dev->nd->macaddr, 6);
161
}
162

    
163
static int next_block_unit[IF_COUNT];
164

    
165
/* Get a block device.  This should only be used for single-drive devices
166
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
167
   appropriate bus.  */
168
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
169
{
170
    int unit = next_block_unit[type]++;
171
    int index;
172

    
173
    index = drive_get_index(type, 0, unit);
174
    if (index == -1) {
175
        return NULL;
176
    }
177
    return drives_table[index].bdrv;
178
}
179

    
180
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
181
{
182
    BusState *bus;
183

    
184
    LIST_FOREACH(bus, &dev->child_bus, sibling) {
185
        if (strcmp(name, bus->name) == 0) {
186
            return bus;
187
        }
188
    }
189
    return NULL;
190
}
191

    
192
static int next_scsi_bus;
193

    
194
/* Create a scsi bus, and attach devices to it.  */
195
/* TODO: Actually create a scsi bus for hotplug to use.  */
196
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
197
{
198
   int bus = next_scsi_bus++;
199
   int unit;
200
   int index;
201

    
202
   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
203
       index = drive_get_index(IF_SCSI, bus, unit);
204
       if (index == -1) {
205
           continue;
206
       }
207
       attach(host, drives_table[index].bdrv, unit);
208
   }
209
}
210

    
211
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
212
{
213
    BusState *bus;
214

    
215
    bus = qemu_mallocz(info->size);
216
    bus->info = info;
217
    bus->parent = parent;
218
    bus->name = qemu_strdup(name);
219
    LIST_INIT(&bus->children);
220
    if (parent) {
221
        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
222
    }
223
    return bus;
224
}
225

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

    
229
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
230
                             const char *prefix, int indent)
231
{
232
    char buf[64];
233

    
234
    if (!props)
235
        return;
236
    while (props->name) {
237
        if (props->info->print) {
238
            props->info->print(dev, props, buf, sizeof(buf));
239
            qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
240
        }
241
        props++;
242
    }
243
}
244

    
245
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
246
{
247
    BusState *child;
248
    qdev_printf("dev: %s\n", dev->info->name);
249
    indent += 2;
250
    if (dev->num_gpio_in) {
251
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
252
    }
253
    if (dev->num_gpio_out) {
254
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
255
    }
256
    qdev_print_props(mon, dev, dev->info->props, "dev", indent);
257
    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
258
    if (dev->parent_bus->info->print_dev)
259
        dev->parent_bus->info->print_dev(mon, dev, indent);
260
    LIST_FOREACH(child, &dev->child_bus, sibling) {
261
        qbus_print(mon, child, indent);
262
    }
263
}
264

    
265
static void qbus_print(Monitor *mon, BusState *bus, int indent)
266
{
267
    struct DeviceState *dev;
268

    
269
    qdev_printf("bus: %s\n", bus->name);
270
    indent += 2;
271
    qdev_printf("type %s\n", bus->info->name);
272
    LIST_FOREACH(dev, &bus->children, sibling) {
273
        qdev_print(mon, dev, indent);
274
    }
275
}
276
#undef qdev_printf
277

    
278
void do_info_qtree(Monitor *mon)
279
{
280
    if (main_system_bus)
281
        qbus_print(mon, main_system_bus, 0);
282
}