root / hw / qdev.c @ cafe5bdb
History | View | Annotate | Download (38.5 kB)
1 | aae9460e | Paul Brook | /*
|
---|---|---|---|
2 | aae9460e | Paul Brook | * Dynamic device configuration and creation.
|
3 | aae9460e | Paul Brook | *
|
4 | aae9460e | Paul Brook | * Copyright (c) 2009 CodeSourcery
|
5 | aae9460e | Paul Brook | *
|
6 | aae9460e | Paul Brook | * This library is free software; you can redistribute it and/or
|
7 | aae9460e | Paul Brook | * modify it under the terms of the GNU Lesser General Public
|
8 | aae9460e | Paul Brook | * License as published by the Free Software Foundation; either
|
9 | aae9460e | Paul Brook | * version 2 of the License, or (at your option) any later version.
|
10 | aae9460e | Paul Brook | *
|
11 | aae9460e | Paul Brook | * This library is distributed in the hope that it will be useful,
|
12 | aae9460e | Paul Brook | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | aae9460e | Paul Brook | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | aae9460e | Paul Brook | * Lesser General Public License for more details.
|
15 | aae9460e | Paul Brook | *
|
16 | aae9460e | Paul Brook | * You should have received a copy of the GNU Lesser General Public
|
17 | 8167ee88 | Blue Swirl | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
18 | aae9460e | Paul Brook | */
|
19 | aae9460e | Paul Brook | |
20 | aae9460e | Paul Brook | /* The theory here is that it should be possible to create a machine without
|
21 | aae9460e | Paul Brook | knowledge of specific devices. Historically board init routines have
|
22 | aae9460e | Paul Brook | passed a bunch of arguments to each device, requiring the board know
|
23 | aae9460e | Paul Brook | exactly which device it is dealing with. This file provides an abstract
|
24 | aae9460e | Paul Brook | API for device configuration and initialization. Devices will generally
|
25 | aae9460e | Paul Brook | inherit from a particular bus (e.g. PCI or I2C) rather than
|
26 | aae9460e | Paul Brook | this API directly. */
|
27 | aae9460e | Paul Brook | |
28 | 9d07d757 | Paul Brook | #include "net.h" |
29 | aae9460e | Paul Brook | #include "qdev.h" |
30 | aae9460e | Paul Brook | #include "sysemu.h" |
31 | cae4956e | Gerd Hoffmann | #include "monitor.h" |
32 | aae9460e | Paul Brook | |
33 | 3418bd25 | Gerd Hoffmann | static int qdev_hotplug = 0; |
34 | 0ac8ef71 | Alex Williamson | static bool qdev_hot_added = false; |
35 | 0ac8ef71 | Alex Williamson | static bool qdev_hot_removed = false; |
36 | 3418bd25 | Gerd Hoffmann | |
37 | cdaed7c7 | Gerd Hoffmann | /* This is a nasty hack to allow passing a NULL bus to qdev_create. */
|
38 | b9aaf7f8 | Blue Swirl | static BusState *main_system_bus;
|
39 | 2da8bb92 | Isaku Yamahata | static void main_system_bus_create(void); |
40 | 4d6ae674 | Paul Brook | |
41 | 0958b4cc | Gerd Hoffmann | DeviceInfo *device_info_list; |
42 | aae9460e | Paul Brook | |
43 | 8ffb1bcf | Gerd Hoffmann | static BusState *qbus_find_recursive(BusState *bus, const char *name, |
44 | 8ffb1bcf | Gerd Hoffmann | const BusInfo *info);
|
45 | 8ffb1bcf | Gerd Hoffmann | static BusState *qbus_find(const char *path); |
46 | 8ffb1bcf | Gerd Hoffmann | |
47 | aae9460e | Paul Brook | /* Register a new device type. */
|
48 | 074f2fff | Gerd Hoffmann | void qdev_register(DeviceInfo *info)
|
49 | aae9460e | Paul Brook | { |
50 | 074f2fff | Gerd Hoffmann | assert(info->size >= sizeof(DeviceState));
|
51 | 042f84d0 | Gerd Hoffmann | assert(!info->next); |
52 | aae9460e | Paul Brook | |
53 | 042f84d0 | Gerd Hoffmann | info->next = device_info_list; |
54 | 042f84d0 | Gerd Hoffmann | device_info_list = info; |
55 | aae9460e | Paul Brook | } |
56 | aae9460e | Paul Brook | |
57 | 81ebb98b | Gerd Hoffmann | static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name) |
58 | 81ebb98b | Gerd Hoffmann | { |
59 | 81ebb98b | Gerd Hoffmann | DeviceInfo *info; |
60 | 81ebb98b | Gerd Hoffmann | |
61 | 3320e56e | Gerd Hoffmann | /* first check device names */
|
62 | 81ebb98b | Gerd Hoffmann | for (info = device_info_list; info != NULL; info = info->next) { |
63 | 81ebb98b | Gerd Hoffmann | if (bus_info && info->bus_info != bus_info)
|
64 | 81ebb98b | Gerd Hoffmann | continue;
|
65 | 81ebb98b | Gerd Hoffmann | if (strcmp(info->name, name) != 0) |
66 | 81ebb98b | Gerd Hoffmann | continue;
|
67 | 81ebb98b | Gerd Hoffmann | return info;
|
68 | 81ebb98b | Gerd Hoffmann | } |
69 | 3320e56e | Gerd Hoffmann | |
70 | 3320e56e | Gerd Hoffmann | /* failing that check the aliases */
|
71 | 3320e56e | Gerd Hoffmann | for (info = device_info_list; info != NULL; info = info->next) { |
72 | 3320e56e | Gerd Hoffmann | if (bus_info && info->bus_info != bus_info)
|
73 | 3320e56e | Gerd Hoffmann | continue;
|
74 | 3320e56e | Gerd Hoffmann | if (!info->alias)
|
75 | 3320e56e | Gerd Hoffmann | continue;
|
76 | 3320e56e | Gerd Hoffmann | if (strcmp(info->alias, name) != 0) |
77 | 3320e56e | Gerd Hoffmann | continue;
|
78 | 3320e56e | Gerd Hoffmann | return info;
|
79 | 3320e56e | Gerd Hoffmann | } |
80 | 81ebb98b | Gerd Hoffmann | return NULL; |
81 | 81ebb98b | Gerd Hoffmann | } |
82 | 81ebb98b | Gerd Hoffmann | |
83 | 0c17542d | Markus Armbruster | static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
|
84 | 0c17542d | Markus Armbruster | { |
85 | 0c17542d | Markus Armbruster | DeviceState *dev; |
86 | a5296ca9 | Anthony Liguori | Property *prop; |
87 | 0c17542d | Markus Armbruster | |
88 | 0c17542d | Markus Armbruster | assert(bus->info == info->bus_info); |
89 | 7267c094 | Anthony Liguori | dev = g_malloc0(info->size); |
90 | 0c17542d | Markus Armbruster | dev->info = info; |
91 | 0c17542d | Markus Armbruster | dev->parent_bus = bus; |
92 | 0c17542d | Markus Armbruster | qdev_prop_set_defaults(dev, dev->info->props); |
93 | 0c17542d | Markus Armbruster | qdev_prop_set_defaults(dev, dev->parent_bus->info->props); |
94 | 0c17542d | Markus Armbruster | qdev_prop_set_globals(dev); |
95 | d8bb00d6 | Paolo Bonzini | QTAILQ_INSERT_HEAD(&bus->children, dev, sibling); |
96 | 0c17542d | Markus Armbruster | if (qdev_hotplug) {
|
97 | 0c17542d | Markus Armbruster | assert(bus->allow_hotplug); |
98 | 0c17542d | Markus Armbruster | dev->hotplugged = 1;
|
99 | 0ac8ef71 | Alex Williamson | qdev_hot_added = true;
|
100 | 0c17542d | Markus Armbruster | } |
101 | 4d2ffa08 | Jan Kiszka | dev->instance_id_alias = -1;
|
102 | 44677ded | Anthony Liguori | QTAILQ_INIT(&dev->properties); |
103 | 0c17542d | Markus Armbruster | dev->state = DEV_STATE_CREATED; |
104 | a5296ca9 | Anthony Liguori | |
105 | a5296ca9 | Anthony Liguori | for (prop = dev->info->props; prop && prop->name; prop++) {
|
106 | a5296ca9 | Anthony Liguori | qdev_property_add_legacy(dev, prop, NULL);
|
107 | a5296ca9 | Anthony Liguori | } |
108 | a5296ca9 | Anthony Liguori | |
109 | a5296ca9 | Anthony Liguori | for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
|
110 | a5296ca9 | Anthony Liguori | qdev_property_add_legacy(dev, prop, NULL);
|
111 | a5296ca9 | Anthony Liguori | } |
112 | a5296ca9 | Anthony Liguori | |
113 | cd34d667 | Anthony Liguori | qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL); |
114 | cd34d667 | Anthony Liguori | |
115 | 0c17542d | Markus Armbruster | return dev;
|
116 | 0c17542d | Markus Armbruster | } |
117 | 0c17542d | Markus Armbruster | |
118 | aae9460e | Paul Brook | /* Create a new device. This only initializes the device state structure
|
119 | aae9460e | Paul Brook | and allows properties to be set. qdev_init should be called to
|
120 | aae9460e | Paul Brook | initialize the actual device emulation. */
|
121 | 02e2da45 | Paul Brook | DeviceState *qdev_create(BusState *bus, const char *name) |
122 | aae9460e | Paul Brook | { |
123 | 0bcdeda7 | Blue Swirl | DeviceState *dev; |
124 | 0bcdeda7 | Blue Swirl | |
125 | 0bcdeda7 | Blue Swirl | dev = qdev_try_create(bus, name); |
126 | 0bcdeda7 | Blue Swirl | if (!dev) {
|
127 | e92714c7 | Peter Maydell | if (bus) {
|
128 | e92714c7 | Peter Maydell | hw_error("Unknown device '%s' for bus '%s'\n", name,
|
129 | e92714c7 | Peter Maydell | bus->info->name); |
130 | e92714c7 | Peter Maydell | } else {
|
131 | e92714c7 | Peter Maydell | hw_error("Unknown device '%s' for default sysbus\n", name);
|
132 | e92714c7 | Peter Maydell | } |
133 | 0bcdeda7 | Blue Swirl | } |
134 | 0bcdeda7 | Blue Swirl | |
135 | 0bcdeda7 | Blue Swirl | return dev;
|
136 | 0bcdeda7 | Blue Swirl | } |
137 | 0bcdeda7 | Blue Swirl | |
138 | 0bcdeda7 | Blue Swirl | DeviceState *qdev_try_create(BusState *bus, const char *name) |
139 | 0bcdeda7 | Blue Swirl | { |
140 | 042f84d0 | Gerd Hoffmann | DeviceInfo *info; |
141 | aae9460e | Paul Brook | |
142 | 10c4c98a | Gerd Hoffmann | if (!bus) {
|
143 | 68694897 | Stefan Weil | bus = sysbus_get_default(); |
144 | 10c4c98a | Gerd Hoffmann | } |
145 | 10c4c98a | Gerd Hoffmann | |
146 | 81ebb98b | Gerd Hoffmann | info = qdev_find_info(bus->info, name); |
147 | 042f84d0 | Gerd Hoffmann | if (!info) {
|
148 | 0bcdeda7 | Blue Swirl | return NULL; |
149 | aae9460e | Paul Brook | } |
150 | aae9460e | Paul Brook | |
151 | 0c17542d | Markus Armbruster | return qdev_create_from_info(bus, info);
|
152 | aae9460e | Paul Brook | } |
153 | aae9460e | Paul Brook | |
154 | 8a9662ca | Markus Armbruster | static void qdev_print_devinfo(DeviceInfo *info) |
155 | 1b524b04 | Gerd Hoffmann | { |
156 | 8a9662ca | Markus Armbruster | error_printf("name \"%s\", bus %s",
|
157 | 8a9662ca | Markus Armbruster | info->name, info->bus_info->name); |
158 | 22f2e344 | Gerd Hoffmann | if (info->alias) {
|
159 | 8a9662ca | Markus Armbruster | error_printf(", alias \"%s\"", info->alias);
|
160 | 22f2e344 | Gerd Hoffmann | } |
161 | 22f2e344 | Gerd Hoffmann | if (info->desc) {
|
162 | 8a9662ca | Markus Armbruster | error_printf(", desc \"%s\"", info->desc);
|
163 | 22f2e344 | Gerd Hoffmann | } |
164 | 22f2e344 | Gerd Hoffmann | if (info->no_user) {
|
165 | 8a9662ca | Markus Armbruster | error_printf(", no-user");
|
166 | 22f2e344 | Gerd Hoffmann | } |
167 | 8a9662ca | Markus Armbruster | error_printf("\n");
|
168 | 1b524b04 | Gerd Hoffmann | } |
169 | 1b524b04 | Gerd Hoffmann | |
170 | f31d07d1 | Gerd Hoffmann | static int set_property(const char *name, const char *value, void *opaque) |
171 | 8ffb1bcf | Gerd Hoffmann | { |
172 | f31d07d1 | Gerd Hoffmann | DeviceState *dev = opaque; |
173 | f31d07d1 | Gerd Hoffmann | |
174 | f31d07d1 | Gerd Hoffmann | if (strcmp(name, "driver") == 0) |
175 | f31d07d1 | Gerd Hoffmann | return 0; |
176 | f31d07d1 | Gerd Hoffmann | if (strcmp(name, "bus") == 0) |
177 | f31d07d1 | Gerd Hoffmann | return 0; |
178 | f31d07d1 | Gerd Hoffmann | |
179 | 3df04ac3 | Mark McLoughlin | if (qdev_prop_parse(dev, name, value) == -1) { |
180 | f31d07d1 | Gerd Hoffmann | return -1; |
181 | f31d07d1 | Gerd Hoffmann | } |
182 | f31d07d1 | Gerd Hoffmann | return 0; |
183 | f31d07d1 | Gerd Hoffmann | } |
184 | f31d07d1 | Gerd Hoffmann | |
185 | ff952ba2 | Markus Armbruster | int qdev_device_help(QemuOpts *opts)
|
186 | ff952ba2 | Markus Armbruster | { |
187 | ff952ba2 | Markus Armbruster | const char *driver; |
188 | ff952ba2 | Markus Armbruster | DeviceInfo *info; |
189 | 08350cf0 | Markus Armbruster | Property *prop; |
190 | ff952ba2 | Markus Armbruster | |
191 | ff952ba2 | Markus Armbruster | driver = qemu_opt_get(opts, "driver");
|
192 | ff952ba2 | Markus Armbruster | if (driver && !strcmp(driver, "?")) { |
193 | ff952ba2 | Markus Armbruster | for (info = device_info_list; info != NULL; info = info->next) { |
194 | c64eafaf | Markus Armbruster | if (info->no_user) {
|
195 | c64eafaf | Markus Armbruster | continue; /* not available, don't show */ |
196 | c64eafaf | Markus Armbruster | } |
197 | 8a9662ca | Markus Armbruster | qdev_print_devinfo(info); |
198 | ff952ba2 | Markus Armbruster | } |
199 | ff952ba2 | Markus Armbruster | return 1; |
200 | ff952ba2 | Markus Armbruster | } |
201 | ff952ba2 | Markus Armbruster | |
202 | 542379f4 | Markus Armbruster | if (!driver || !qemu_opt_get(opts, "?")) { |
203 | 08350cf0 | Markus Armbruster | return 0; |
204 | 08350cf0 | Markus Armbruster | } |
205 | 08350cf0 | Markus Armbruster | |
206 | 08350cf0 | Markus Armbruster | info = qdev_find_info(NULL, driver);
|
207 | 08350cf0 | Markus Armbruster | if (!info) {
|
208 | 08350cf0 | Markus Armbruster | return 0; |
209 | 08350cf0 | Markus Armbruster | } |
210 | 08350cf0 | Markus Armbruster | |
211 | 08350cf0 | Markus Armbruster | for (prop = info->props; prop && prop->name; prop++) {
|
212 | 036f7166 | Markus Armbruster | /*
|
213 | 036f7166 | Markus Armbruster | * TODO Properties without a parser are just for dirty hacks.
|
214 | 036f7166 | Markus Armbruster | * qdev_prop_ptr is the only such PropertyInfo. It's marked
|
215 | 036f7166 | Markus Armbruster | * for removal. This conditional should be removed along with
|
216 | 036f7166 | Markus Armbruster | * it.
|
217 | 036f7166 | Markus Armbruster | */
|
218 | 036f7166 | Markus Armbruster | if (!prop->info->parse) {
|
219 | 036f7166 | Markus Armbruster | continue; /* no way to set it, don't show */ |
220 | 036f7166 | Markus Armbruster | } |
221 | cafe5bdb | Paolo Bonzini | error_printf("%s.%s=%s\n", info->name, prop->name,
|
222 | cafe5bdb | Paolo Bonzini | prop->info->legacy_name ?: prop->info->name); |
223 | a8467c7a | Gerd Hoffmann | } |
224 | a8467c7a | Gerd Hoffmann | for (prop = info->bus_info->props; prop && prop->name; prop++) {
|
225 | a8467c7a | Gerd Hoffmann | if (!prop->info->parse) {
|
226 | a8467c7a | Gerd Hoffmann | continue; /* no way to set it, don't show */ |
227 | a8467c7a | Gerd Hoffmann | } |
228 | cafe5bdb | Paolo Bonzini | error_printf("%s.%s=%s\n", info->name, prop->name,
|
229 | cafe5bdb | Paolo Bonzini | prop->info->legacy_name ?: prop->info->name); |
230 | 08350cf0 | Markus Armbruster | } |
231 | 08350cf0 | Markus Armbruster | return 1; |
232 | ff952ba2 | Markus Armbruster | } |
233 | ff952ba2 | Markus Armbruster | |
234 | 1bdaacb1 | Anthony Liguori | static DeviceState *qdev_get_peripheral(void) |
235 | 1bdaacb1 | Anthony Liguori | { |
236 | 1bdaacb1 | Anthony Liguori | static DeviceState *dev;
|
237 | 1bdaacb1 | Anthony Liguori | |
238 | 1bdaacb1 | Anthony Liguori | if (dev == NULL) { |
239 | 1bdaacb1 | Anthony Liguori | dev = qdev_create(NULL, "container"); |
240 | 1bdaacb1 | Anthony Liguori | qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL); |
241 | 1bdaacb1 | Anthony Liguori | qdev_init_nofail(dev); |
242 | 1bdaacb1 | Anthony Liguori | } |
243 | 1bdaacb1 | Anthony Liguori | |
244 | 1bdaacb1 | Anthony Liguori | return dev;
|
245 | 1bdaacb1 | Anthony Liguori | } |
246 | 1bdaacb1 | Anthony Liguori | |
247 | 8eb02831 | Anthony Liguori | static DeviceState *qdev_get_peripheral_anon(void) |
248 | 8eb02831 | Anthony Liguori | { |
249 | 8eb02831 | Anthony Liguori | static DeviceState *dev;
|
250 | 8eb02831 | Anthony Liguori | |
251 | 8eb02831 | Anthony Liguori | if (dev == NULL) { |
252 | 8eb02831 | Anthony Liguori | dev = qdev_create(NULL, "container"); |
253 | 8eb02831 | Anthony Liguori | qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL); |
254 | 8eb02831 | Anthony Liguori | qdev_init_nofail(dev); |
255 | 8eb02831 | Anthony Liguori | } |
256 | 8eb02831 | Anthony Liguori | |
257 | 8eb02831 | Anthony Liguori | return dev;
|
258 | 8eb02831 | Anthony Liguori | } |
259 | 8eb02831 | Anthony Liguori | |
260 | f31d07d1 | Gerd Hoffmann | DeviceState *qdev_device_add(QemuOpts *opts) |
261 | f31d07d1 | Gerd Hoffmann | { |
262 | f31d07d1 | Gerd Hoffmann | const char *driver, *path, *id; |
263 | 8ffb1bcf | Gerd Hoffmann | DeviceInfo *info; |
264 | 8ffb1bcf | Gerd Hoffmann | DeviceState *qdev; |
265 | 8ffb1bcf | Gerd Hoffmann | BusState *bus; |
266 | 8ffb1bcf | Gerd Hoffmann | |
267 | f31d07d1 | Gerd Hoffmann | driver = qemu_opt_get(opts, "driver");
|
268 | f31d07d1 | Gerd Hoffmann | if (!driver) {
|
269 | 0204276b | Markus Armbruster | qerror_report(QERR_MISSING_PARAMETER, "driver");
|
270 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
271 | 8ffb1bcf | Gerd Hoffmann | } |
272 | f31d07d1 | Gerd Hoffmann | |
273 | f31d07d1 | Gerd Hoffmann | /* find driver */
|
274 | 8ffb1bcf | Gerd Hoffmann | info = qdev_find_info(NULL, driver);
|
275 | c64eafaf | Markus Armbruster | if (!info || info->no_user) {
|
276 | e17ba87c | Markus Armbruster | qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name"); |
277 | 0204276b | Markus Armbruster | error_printf_unless_qmp("Try with argument '?' for a list.\n");
|
278 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
279 | 8ffb1bcf | Gerd Hoffmann | } |
280 | 8ffb1bcf | Gerd Hoffmann | |
281 | f31d07d1 | Gerd Hoffmann | /* find bus */
|
282 | f31d07d1 | Gerd Hoffmann | path = qemu_opt_get(opts, "bus");
|
283 | f31d07d1 | Gerd Hoffmann | if (path != NULL) { |
284 | 8ffb1bcf | Gerd Hoffmann | bus = qbus_find(path); |
285 | ac8dae67 | Markus Armbruster | if (!bus) {
|
286 | ac8dae67 | Markus Armbruster | return NULL; |
287 | ac8dae67 | Markus Armbruster | } |
288 | ac8dae67 | Markus Armbruster | if (bus->info != info->bus_info) {
|
289 | 0204276b | Markus Armbruster | qerror_report(QERR_BAD_BUS_FOR_DEVICE, |
290 | 0204276b | Markus Armbruster | driver, bus->info->name); |
291 | 327867b6 | Markus Armbruster | return NULL; |
292 | 327867b6 | Markus Armbruster | } |
293 | 8ffb1bcf | Gerd Hoffmann | } else {
|
294 | 8ffb1bcf | Gerd Hoffmann | bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
|
295 | ac8dae67 | Markus Armbruster | if (!bus) {
|
296 | 0204276b | Markus Armbruster | qerror_report(QERR_NO_BUS_FOR_DEVICE, |
297 | 0204276b | Markus Armbruster | info->name, info->bus_info->name); |
298 | ac8dae67 | Markus Armbruster | return NULL; |
299 | ac8dae67 | Markus Armbruster | } |
300 | 75570088 | Gerd Hoffmann | } |
301 | 3418bd25 | Gerd Hoffmann | if (qdev_hotplug && !bus->allow_hotplug) {
|
302 | 0204276b | Markus Armbruster | qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); |
303 | 3418bd25 | Gerd Hoffmann | return NULL; |
304 | 3418bd25 | Gerd Hoffmann | } |
305 | 8ffb1bcf | Gerd Hoffmann | |
306 | f31d07d1 | Gerd Hoffmann | /* create device, set properties */
|
307 | 0c17542d | Markus Armbruster | qdev = qdev_create_from_info(bus, info); |
308 | f31d07d1 | Gerd Hoffmann | id = qemu_opts_id(opts); |
309 | f31d07d1 | Gerd Hoffmann | if (id) {
|
310 | f31d07d1 | Gerd Hoffmann | qdev->id = id; |
311 | 1bdaacb1 | Anthony Liguori | qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
|
312 | 8eb02831 | Anthony Liguori | } else {
|
313 | 8eb02831 | Anthony Liguori | static int anon_count; |
314 | 8eb02831 | Anthony Liguori | gchar *name = g_strdup_printf("device[%d]", anon_count++);
|
315 | 8eb02831 | Anthony Liguori | qdev_property_add_child(qdev_get_peripheral_anon(), name, |
316 | 8eb02831 | Anthony Liguori | qdev, NULL);
|
317 | 8eb02831 | Anthony Liguori | g_free(name); |
318 | 8eb02831 | Anthony Liguori | } |
319 | f31d07d1 | Gerd Hoffmann | if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { |
320 | f31d07d1 | Gerd Hoffmann | qdev_free(qdev); |
321 | f31d07d1 | Gerd Hoffmann | return NULL; |
322 | 8ffb1bcf | Gerd Hoffmann | } |
323 | 5c17ca25 | Markus Armbruster | if (qdev_init(qdev) < 0) { |
324 | 0204276b | Markus Armbruster | qerror_report(QERR_DEVICE_INIT_FAILED, driver); |
325 | 81a322d4 | Gerd Hoffmann | return NULL; |
326 | 81a322d4 | Gerd Hoffmann | } |
327 | ef80b466 | Gerd Hoffmann | qdev->opts = opts; |
328 | 8ffb1bcf | Gerd Hoffmann | return qdev;
|
329 | 8ffb1bcf | Gerd Hoffmann | } |
330 | 8ffb1bcf | Gerd Hoffmann | |
331 | aae9460e | Paul Brook | /* Initialize a device. Device properties should be set before calling
|
332 | aae9460e | Paul Brook | this function. IRQs and MMIO regions should be connected/mapped after
|
333 | 18cfeb52 | Markus Armbruster | calling this function.
|
334 | 18cfeb52 | Markus Armbruster | On failure, destroy the device and return negative value.
|
335 | 18cfeb52 | Markus Armbruster | Return 0 on success. */
|
336 | 81a322d4 | Gerd Hoffmann | int qdev_init(DeviceState *dev)
|
337 | aae9460e | Paul Brook | { |
338 | 959f733a | Gerd Hoffmann | int rc;
|
339 | 959f733a | Gerd Hoffmann | |
340 | 131ec1bd | Gerd Hoffmann | assert(dev->state == DEV_STATE_CREATED); |
341 | 959f733a | Gerd Hoffmann | rc = dev->info->init(dev, dev->info); |
342 | 18cfeb52 | Markus Armbruster | if (rc < 0) { |
343 | 18cfeb52 | Markus Armbruster | qdev_free(dev); |
344 | 959f733a | Gerd Hoffmann | return rc;
|
345 | 18cfeb52 | Markus Armbruster | } |
346 | 4d2ffa08 | Jan Kiszka | if (dev->info->vmsd) {
|
347 | 0be71e32 | Alex Williamson | vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
|
348 | 4d2ffa08 | Jan Kiszka | dev->instance_id_alias, |
349 | 4d2ffa08 | Jan Kiszka | dev->alias_required_for_version); |
350 | 4d2ffa08 | Jan Kiszka | } |
351 | 131ec1bd | Gerd Hoffmann | dev->state = DEV_STATE_INITIALIZED; |
352 | 5ab28c83 | Jan Kiszka | if (dev->hotplugged && dev->info->reset) {
|
353 | 5ab28c83 | Jan Kiszka | dev->info->reset(dev); |
354 | 5ab28c83 | Jan Kiszka | } |
355 | 959f733a | Gerd Hoffmann | return 0; |
356 | 02e2da45 | Paul Brook | } |
357 | 02e2da45 | Paul Brook | |
358 | 4d2ffa08 | Jan Kiszka | void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, |
359 | 4d2ffa08 | Jan Kiszka | int required_for_version)
|
360 | 4d2ffa08 | Jan Kiszka | { |
361 | 4d2ffa08 | Jan Kiszka | assert(dev->state == DEV_STATE_CREATED); |
362 | 4d2ffa08 | Jan Kiszka | dev->instance_id_alias = alias_id; |
363 | 4d2ffa08 | Jan Kiszka | dev->alias_required_for_version = required_for_version; |
364 | 4d2ffa08 | Jan Kiszka | } |
365 | 4d2ffa08 | Jan Kiszka | |
366 | 3418bd25 | Gerd Hoffmann | int qdev_unplug(DeviceState *dev)
|
367 | 3418bd25 | Gerd Hoffmann | { |
368 | 3418bd25 | Gerd Hoffmann | if (!dev->parent_bus->allow_hotplug) {
|
369 | cc601cb7 | Markus Armbruster | qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); |
370 | 3418bd25 | Gerd Hoffmann | return -1; |
371 | 3418bd25 | Gerd Hoffmann | } |
372 | 593831de | Amit Shah | assert(dev->info->unplug != NULL);
|
373 | 593831de | Amit Shah | |
374 | 85ed303b | Anthony Liguori | if (dev->ref != 0) { |
375 | 85ed303b | Anthony Liguori | qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
|
376 | 85ed303b | Anthony Liguori | return -1; |
377 | 85ed303b | Anthony Liguori | } |
378 | 85ed303b | Anthony Liguori | |
379 | 0ac8ef71 | Alex Williamson | qdev_hot_removed = true;
|
380 | 0ac8ef71 | Alex Williamson | |
381 | 3418bd25 | Gerd Hoffmann | return dev->info->unplug(dev);
|
382 | 3418bd25 | Gerd Hoffmann | } |
383 | 3418bd25 | Gerd Hoffmann | |
384 | ec990eb6 | Anthony Liguori | static int qdev_reset_one(DeviceState *dev, void *opaque) |
385 | ec990eb6 | Anthony Liguori | { |
386 | ec990eb6 | Anthony Liguori | if (dev->info->reset) {
|
387 | ec990eb6 | Anthony Liguori | dev->info->reset(dev); |
388 | ec990eb6 | Anthony Liguori | } |
389 | ec990eb6 | Anthony Liguori | |
390 | ec990eb6 | Anthony Liguori | return 0; |
391 | ec990eb6 | Anthony Liguori | } |
392 | ec990eb6 | Anthony Liguori | |
393 | ec990eb6 | Anthony Liguori | BusState *sysbus_get_default(void)
|
394 | ec990eb6 | Anthony Liguori | { |
395 | 68694897 | Stefan Weil | if (!main_system_bus) {
|
396 | 2da8bb92 | Isaku Yamahata | main_system_bus_create(); |
397 | 68694897 | Stefan Weil | } |
398 | ec990eb6 | Anthony Liguori | return main_system_bus;
|
399 | ec990eb6 | Anthony Liguori | } |
400 | ec990eb6 | Anthony Liguori | |
401 | b4694b7c | Isaku Yamahata | static int qbus_reset_one(BusState *bus, void *opaque) |
402 | b4694b7c | Isaku Yamahata | { |
403 | b4694b7c | Isaku Yamahata | if (bus->info->reset) {
|
404 | b4694b7c | Isaku Yamahata | return bus->info->reset(bus);
|
405 | b4694b7c | Isaku Yamahata | } |
406 | b4694b7c | Isaku Yamahata | return 0; |
407 | b4694b7c | Isaku Yamahata | } |
408 | b4694b7c | Isaku Yamahata | |
409 | 5af0a04b | Isaku Yamahata | void qdev_reset_all(DeviceState *dev)
|
410 | 5af0a04b | Isaku Yamahata | { |
411 | 5af0a04b | Isaku Yamahata | qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
|
412 | 5af0a04b | Isaku Yamahata | } |
413 | 5af0a04b | Isaku Yamahata | |
414 | 80376c3f | Isaku Yamahata | void qbus_reset_all_fn(void *opaque) |
415 | 80376c3f | Isaku Yamahata | { |
416 | 80376c3f | Isaku Yamahata | BusState *bus = opaque; |
417 | f530cce3 | Michael S. Tsirkin | qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
|
418 | 80376c3f | Isaku Yamahata | } |
419 | 80376c3f | Isaku Yamahata | |
420 | 3418bd25 | Gerd Hoffmann | /* can be used as ->unplug() callback for the simple cases */
|
421 | 3418bd25 | Gerd Hoffmann | int qdev_simple_unplug_cb(DeviceState *dev)
|
422 | 3418bd25 | Gerd Hoffmann | { |
423 | 3418bd25 | Gerd Hoffmann | /* just zap it */
|
424 | 3418bd25 | Gerd Hoffmann | qdev_free(dev); |
425 | 3418bd25 | Gerd Hoffmann | return 0; |
426 | 3418bd25 | Gerd Hoffmann | } |
427 | 3418bd25 | Gerd Hoffmann | |
428 | 3b29a101 | Michael Tokarev | |
429 | 3b29a101 | Michael Tokarev | /* Like qdev_init(), but terminate program via error_report() instead of
|
430 | e23a1b33 | Markus Armbruster | returning an error value. This is okay during machine creation.
|
431 | e23a1b33 | Markus Armbruster | Don't use for hotplug, because there callers need to recover from
|
432 | e23a1b33 | Markus Armbruster | failure. Exception: if you know the device's init() callback can't
|
433 | e23a1b33 | Markus Armbruster | fail, then qdev_init_nofail() can't fail either, and is therefore
|
434 | e23a1b33 | Markus Armbruster | usable even then. But relying on the device implementation that
|
435 | e23a1b33 | Markus Armbruster | way is somewhat unclean, and best avoided. */
|
436 | e23a1b33 | Markus Armbruster | void qdev_init_nofail(DeviceState *dev)
|
437 | e23a1b33 | Markus Armbruster | { |
438 | e23a1b33 | Markus Armbruster | DeviceInfo *info = dev->info; |
439 | e23a1b33 | Markus Armbruster | |
440 | bd6c9a61 | Markus Armbruster | if (qdev_init(dev) < 0) { |
441 | 6daf194d | Markus Armbruster | error_report("Initialization of device %s failed", info->name);
|
442 | bd6c9a61 | Markus Armbruster | exit(1);
|
443 | bd6c9a61 | Markus Armbruster | } |
444 | e23a1b33 | Markus Armbruster | } |
445 | e23a1b33 | Markus Armbruster | |
446 | 44677ded | Anthony Liguori | static void qdev_property_del_all(DeviceState *dev) |
447 | 44677ded | Anthony Liguori | { |
448 | 44677ded | Anthony Liguori | while (!QTAILQ_EMPTY(&dev->properties)) {
|
449 | 44677ded | Anthony Liguori | DeviceProperty *prop = QTAILQ_FIRST(&dev->properties); |
450 | 44677ded | Anthony Liguori | |
451 | 44677ded | Anthony Liguori | QTAILQ_REMOVE(&dev->properties, prop, node); |
452 | 44677ded | Anthony Liguori | |
453 | 44677ded | Anthony Liguori | if (prop->release) {
|
454 | 44677ded | Anthony Liguori | prop->release(dev, prop->name, prop->opaque); |
455 | 44677ded | Anthony Liguori | } |
456 | 44677ded | Anthony Liguori | |
457 | 44677ded | Anthony Liguori | g_free(prop->name); |
458 | 44677ded | Anthony Liguori | g_free(prop->type); |
459 | 44677ded | Anthony Liguori | g_free(prop); |
460 | 44677ded | Anthony Liguori | } |
461 | 44677ded | Anthony Liguori | } |
462 | 44677ded | Anthony Liguori | |
463 | 02e2da45 | Paul Brook | /* Unlink device from bus and free the structure. */
|
464 | 02e2da45 | Paul Brook | void qdev_free(DeviceState *dev)
|
465 | 02e2da45 | Paul Brook | { |
466 | 131ec1bd | Gerd Hoffmann | BusState *bus; |
467 | d21357df | Markus Armbruster | Property *prop; |
468 | 131ec1bd | Gerd Hoffmann | |
469 | 44677ded | Anthony Liguori | qdev_property_del_all(dev); |
470 | 44677ded | Anthony Liguori | |
471 | 131ec1bd | Gerd Hoffmann | if (dev->state == DEV_STATE_INITIALIZED) {
|
472 | 131ec1bd | Gerd Hoffmann | while (dev->num_child_bus) {
|
473 | 131ec1bd | Gerd Hoffmann | bus = QLIST_FIRST(&dev->child_bus); |
474 | 131ec1bd | Gerd Hoffmann | qbus_free(bus); |
475 | 131ec1bd | Gerd Hoffmann | } |
476 | 131ec1bd | Gerd Hoffmann | if (dev->info->vmsd)
|
477 | 0be71e32 | Alex Williamson | vmstate_unregister(dev, dev->info->vmsd, dev); |
478 | d29275f1 | Gerd Hoffmann | if (dev->info->exit)
|
479 | d29275f1 | Gerd Hoffmann | dev->info->exit(dev); |
480 | ef80b466 | Gerd Hoffmann | if (dev->opts)
|
481 | ef80b466 | Gerd Hoffmann | qemu_opts_del(dev->opts); |
482 | 131ec1bd | Gerd Hoffmann | } |
483 | d8bb00d6 | Paolo Bonzini | QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling); |
484 | d21357df | Markus Armbruster | for (prop = dev->info->props; prop && prop->name; prop++) {
|
485 | d21357df | Markus Armbruster | if (prop->info->free) {
|
486 | d21357df | Markus Armbruster | prop->info->free(dev, prop); |
487 | d21357df | Markus Armbruster | } |
488 | d21357df | Markus Armbruster | } |
489 | 7267c094 | Anthony Liguori | g_free(dev); |
490 | aae9460e | Paul Brook | } |
491 | aae9460e | Paul Brook | |
492 | 3418bd25 | Gerd Hoffmann | void qdev_machine_creation_done(void) |
493 | 3418bd25 | Gerd Hoffmann | { |
494 | 3418bd25 | Gerd Hoffmann | /*
|
495 | 3418bd25 | Gerd Hoffmann | * ok, initial machine setup is done, starting from now we can
|
496 | 3418bd25 | Gerd Hoffmann | * only create hotpluggable devices
|
497 | 3418bd25 | Gerd Hoffmann | */
|
498 | 3418bd25 | Gerd Hoffmann | qdev_hotplug = 1;
|
499 | 3418bd25 | Gerd Hoffmann | } |
500 | 3418bd25 | Gerd Hoffmann | |
501 | 0ac8ef71 | Alex Williamson | bool qdev_machine_modified(void) |
502 | 0ac8ef71 | Alex Williamson | { |
503 | 0ac8ef71 | Alex Williamson | return qdev_hot_added || qdev_hot_removed;
|
504 | 0ac8ef71 | Alex Williamson | } |
505 | 0ac8ef71 | Alex Williamson | |
506 | aae9460e | Paul Brook | /* Get a character (serial) device interface. */
|
507 | aae9460e | Paul Brook | CharDriverState *qdev_init_chardev(DeviceState *dev) |
508 | aae9460e | Paul Brook | { |
509 | aae9460e | Paul Brook | static int next_serial; |
510 | 98b19252 | Amit Shah | |
511 | 98b19252 | Amit Shah | /* FIXME: This function needs to go away: use chardev properties! */
|
512 | 98b19252 | Amit Shah | return serial_hds[next_serial++];
|
513 | aae9460e | Paul Brook | } |
514 | aae9460e | Paul Brook | |
515 | 02e2da45 | Paul Brook | BusState *qdev_get_parent_bus(DeviceState *dev) |
516 | aae9460e | Paul Brook | { |
517 | 02e2da45 | Paul Brook | return dev->parent_bus;
|
518 | aae9460e | Paul Brook | } |
519 | aae9460e | Paul Brook | |
520 | aae9460e | Paul Brook | void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) |
521 | aae9460e | Paul Brook | { |
522 | aae9460e | Paul Brook | assert(dev->num_gpio_in == 0);
|
523 | aae9460e | Paul Brook | dev->num_gpio_in = n; |
524 | aae9460e | Paul Brook | dev->gpio_in = qemu_allocate_irqs(handler, dev, n); |
525 | aae9460e | Paul Brook | } |
526 | aae9460e | Paul Brook | |
527 | aae9460e | Paul Brook | void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) |
528 | aae9460e | Paul Brook | { |
529 | aae9460e | Paul Brook | assert(dev->num_gpio_out == 0);
|
530 | aae9460e | Paul Brook | dev->num_gpio_out = n; |
531 | aae9460e | Paul Brook | dev->gpio_out = pins; |
532 | aae9460e | Paul Brook | } |
533 | aae9460e | Paul Brook | |
534 | aae9460e | Paul Brook | qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
|
535 | aae9460e | Paul Brook | { |
536 | aae9460e | Paul Brook | assert(n >= 0 && n < dev->num_gpio_in);
|
537 | aae9460e | Paul Brook | return dev->gpio_in[n];
|
538 | aae9460e | Paul Brook | } |
539 | aae9460e | Paul Brook | |
540 | aae9460e | Paul Brook | void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) |
541 | aae9460e | Paul Brook | { |
542 | aae9460e | Paul Brook | assert(n >= 0 && n < dev->num_gpio_out);
|
543 | aae9460e | Paul Brook | dev->gpio_out[n] = pin; |
544 | aae9460e | Paul Brook | } |
545 | aae9460e | Paul Brook | |
546 | ed16ab5a | Gerd Hoffmann | void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
547 | ed16ab5a | Gerd Hoffmann | { |
548 | 6eed1856 | Jan Kiszka | qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
|
549 | ed16ab5a | Gerd Hoffmann | if (nd->vlan)
|
550 | ed16ab5a | Gerd Hoffmann | qdev_prop_set_vlan(dev, "vlan", nd->vlan);
|
551 | ed16ab5a | Gerd Hoffmann | if (nd->netdev)
|
552 | ed16ab5a | Gerd Hoffmann | qdev_prop_set_netdev(dev, "netdev", nd->netdev);
|
553 | 75422b0d | Amit Shah | if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
|
554 | 97b15621 | Gerd Hoffmann | qdev_prop_exists(dev, "vectors")) {
|
555 | 97b15621 | Gerd Hoffmann | qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
|
556 | 97b15621 | Gerd Hoffmann | } |
557 | 48e2faf2 | Peter Maydell | nd->instantiated = 1;
|
558 | ed16ab5a | Gerd Hoffmann | } |
559 | ed16ab5a | Gerd Hoffmann | |
560 | 02e2da45 | Paul Brook | BusState *qdev_get_child_bus(DeviceState *dev, const char *name) |
561 | 4d6ae674 | Paul Brook | { |
562 | 02e2da45 | Paul Brook | BusState *bus; |
563 | 4d6ae674 | Paul Brook | |
564 | 72cf2d4f | Blue Swirl | QLIST_FOREACH(bus, &dev->child_bus, sibling) { |
565 | 4d6ae674 | Paul Brook | if (strcmp(name, bus->name) == 0) { |
566 | 02e2da45 | Paul Brook | return bus;
|
567 | 4d6ae674 | Paul Brook | } |
568 | 4d6ae674 | Paul Brook | } |
569 | 4d6ae674 | Paul Brook | return NULL; |
570 | 4d6ae674 | Paul Brook | } |
571 | 4d6ae674 | Paul Brook | |
572 | 81699d8a | Anthony Liguori | int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
|
573 | 81699d8a | Anthony Liguori | qbus_walkerfn *busfn, void *opaque)
|
574 | 81699d8a | Anthony Liguori | { |
575 | 81699d8a | Anthony Liguori | DeviceState *dev; |
576 | 81699d8a | Anthony Liguori | int err;
|
577 | 81699d8a | Anthony Liguori | |
578 | 81699d8a | Anthony Liguori | if (busfn) {
|
579 | 81699d8a | Anthony Liguori | err = busfn(bus, opaque); |
580 | 81699d8a | Anthony Liguori | if (err) {
|
581 | 81699d8a | Anthony Liguori | return err;
|
582 | 81699d8a | Anthony Liguori | } |
583 | 81699d8a | Anthony Liguori | } |
584 | 81699d8a | Anthony Liguori | |
585 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
586 | 81699d8a | Anthony Liguori | err = qdev_walk_children(dev, devfn, busfn, opaque); |
587 | 81699d8a | Anthony Liguori | if (err < 0) { |
588 | 81699d8a | Anthony Liguori | return err;
|
589 | 81699d8a | Anthony Liguori | } |
590 | 81699d8a | Anthony Liguori | } |
591 | 81699d8a | Anthony Liguori | |
592 | 81699d8a | Anthony Liguori | return 0; |
593 | 81699d8a | Anthony Liguori | } |
594 | 81699d8a | Anthony Liguori | |
595 | 81699d8a | Anthony Liguori | int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
|
596 | 81699d8a | Anthony Liguori | qbus_walkerfn *busfn, void *opaque)
|
597 | 81699d8a | Anthony Liguori | { |
598 | 81699d8a | Anthony Liguori | BusState *bus; |
599 | 81699d8a | Anthony Liguori | int err;
|
600 | 81699d8a | Anthony Liguori | |
601 | 81699d8a | Anthony Liguori | if (devfn) {
|
602 | 81699d8a | Anthony Liguori | err = devfn(dev, opaque); |
603 | 81699d8a | Anthony Liguori | if (err) {
|
604 | 81699d8a | Anthony Liguori | return err;
|
605 | 81699d8a | Anthony Liguori | } |
606 | 81699d8a | Anthony Liguori | } |
607 | 81699d8a | Anthony Liguori | |
608 | 81699d8a | Anthony Liguori | QLIST_FOREACH(bus, &dev->child_bus, sibling) { |
609 | 81699d8a | Anthony Liguori | err = qbus_walk_children(bus, devfn, busfn, opaque); |
610 | 81699d8a | Anthony Liguori | if (err < 0) { |
611 | 81699d8a | Anthony Liguori | return err;
|
612 | 81699d8a | Anthony Liguori | } |
613 | 81699d8a | Anthony Liguori | } |
614 | 81699d8a | Anthony Liguori | |
615 | 81699d8a | Anthony Liguori | return 0; |
616 | 81699d8a | Anthony Liguori | } |
617 | 81699d8a | Anthony Liguori | |
618 | 8ffb1bcf | Gerd Hoffmann | static BusState *qbus_find_recursive(BusState *bus, const char *name, |
619 | 8ffb1bcf | Gerd Hoffmann | const BusInfo *info)
|
620 | 8ffb1bcf | Gerd Hoffmann | { |
621 | 8ffb1bcf | Gerd Hoffmann | DeviceState *dev; |
622 | 8ffb1bcf | Gerd Hoffmann | BusState *child, *ret; |
623 | 8ffb1bcf | Gerd Hoffmann | int match = 1; |
624 | 8ffb1bcf | Gerd Hoffmann | |
625 | 8ffb1bcf | Gerd Hoffmann | if (name && (strcmp(bus->name, name) != 0)) { |
626 | 8ffb1bcf | Gerd Hoffmann | match = 0;
|
627 | 8ffb1bcf | Gerd Hoffmann | } |
628 | 8ffb1bcf | Gerd Hoffmann | if (info && (bus->info != info)) {
|
629 | 8ffb1bcf | Gerd Hoffmann | match = 0;
|
630 | 8ffb1bcf | Gerd Hoffmann | } |
631 | 8ffb1bcf | Gerd Hoffmann | if (match) {
|
632 | 8ffb1bcf | Gerd Hoffmann | return bus;
|
633 | 8ffb1bcf | Gerd Hoffmann | } |
634 | 8ffb1bcf | Gerd Hoffmann | |
635 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
636 | 72cf2d4f | Blue Swirl | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
637 | 8ffb1bcf | Gerd Hoffmann | ret = qbus_find_recursive(child, name, info); |
638 | 8ffb1bcf | Gerd Hoffmann | if (ret) {
|
639 | 8ffb1bcf | Gerd Hoffmann | return ret;
|
640 | 8ffb1bcf | Gerd Hoffmann | } |
641 | 8ffb1bcf | Gerd Hoffmann | } |
642 | 8ffb1bcf | Gerd Hoffmann | } |
643 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
644 | 8ffb1bcf | Gerd Hoffmann | } |
645 | 8ffb1bcf | Gerd Hoffmann | |
646 | a2ee6b4f | Isaku Yamahata | DeviceState *qdev_find_recursive(BusState *bus, const char *id) |
647 | 3418bd25 | Gerd Hoffmann | { |
648 | 3418bd25 | Gerd Hoffmann | DeviceState *dev, *ret; |
649 | 3418bd25 | Gerd Hoffmann | BusState *child; |
650 | 3418bd25 | Gerd Hoffmann | |
651 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
652 | 3418bd25 | Gerd Hoffmann | if (dev->id && strcmp(dev->id, id) == 0) |
653 | 3418bd25 | Gerd Hoffmann | return dev;
|
654 | 3418bd25 | Gerd Hoffmann | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
655 | 3418bd25 | Gerd Hoffmann | ret = qdev_find_recursive(child, id); |
656 | 3418bd25 | Gerd Hoffmann | if (ret) {
|
657 | 3418bd25 | Gerd Hoffmann | return ret;
|
658 | 3418bd25 | Gerd Hoffmann | } |
659 | 3418bd25 | Gerd Hoffmann | } |
660 | 3418bd25 | Gerd Hoffmann | } |
661 | 3418bd25 | Gerd Hoffmann | return NULL; |
662 | 3418bd25 | Gerd Hoffmann | } |
663 | 3418bd25 | Gerd Hoffmann | |
664 | 53db16b5 | Markus Armbruster | static void qbus_list_bus(DeviceState *dev) |
665 | 8ffb1bcf | Gerd Hoffmann | { |
666 | 8ffb1bcf | Gerd Hoffmann | BusState *child; |
667 | 8ffb1bcf | Gerd Hoffmann | const char *sep = " "; |
668 | 8ffb1bcf | Gerd Hoffmann | |
669 | 53db16b5 | Markus Armbruster | error_printf("child busses at \"%s\":",
|
670 | 53db16b5 | Markus Armbruster | dev->id ? dev->id : dev->info->name); |
671 | 72cf2d4f | Blue Swirl | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
672 | 53db16b5 | Markus Armbruster | error_printf("%s\"%s\"", sep, child->name);
|
673 | 8ffb1bcf | Gerd Hoffmann | sep = ", ";
|
674 | 8ffb1bcf | Gerd Hoffmann | } |
675 | 53db16b5 | Markus Armbruster | error_printf("\n");
|
676 | 8ffb1bcf | Gerd Hoffmann | } |
677 | 8ffb1bcf | Gerd Hoffmann | |
678 | 53db16b5 | Markus Armbruster | static void qbus_list_dev(BusState *bus) |
679 | 8ffb1bcf | Gerd Hoffmann | { |
680 | 8ffb1bcf | Gerd Hoffmann | DeviceState *dev; |
681 | 8ffb1bcf | Gerd Hoffmann | const char *sep = " "; |
682 | 8ffb1bcf | Gerd Hoffmann | |
683 | 53db16b5 | Markus Armbruster | error_printf("devices at \"%s\":", bus->name);
|
684 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
685 | 53db16b5 | Markus Armbruster | error_printf("%s\"%s\"", sep, dev->info->name);
|
686 | 8ffb1bcf | Gerd Hoffmann | if (dev->id)
|
687 | 53db16b5 | Markus Armbruster | error_printf("/\"%s\"", dev->id);
|
688 | 8ffb1bcf | Gerd Hoffmann | sep = ", ";
|
689 | 8ffb1bcf | Gerd Hoffmann | } |
690 | 53db16b5 | Markus Armbruster | error_printf("\n");
|
691 | 8ffb1bcf | Gerd Hoffmann | } |
692 | 8ffb1bcf | Gerd Hoffmann | |
693 | 8ffb1bcf | Gerd Hoffmann | static BusState *qbus_find_bus(DeviceState *dev, char *elem) |
694 | 8ffb1bcf | Gerd Hoffmann | { |
695 | 8ffb1bcf | Gerd Hoffmann | BusState *child; |
696 | 8ffb1bcf | Gerd Hoffmann | |
697 | 72cf2d4f | Blue Swirl | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
698 | 8ffb1bcf | Gerd Hoffmann | if (strcmp(child->name, elem) == 0) { |
699 | 8ffb1bcf | Gerd Hoffmann | return child;
|
700 | 8ffb1bcf | Gerd Hoffmann | } |
701 | 8ffb1bcf | Gerd Hoffmann | } |
702 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
703 | 8ffb1bcf | Gerd Hoffmann | } |
704 | 8ffb1bcf | Gerd Hoffmann | |
705 | 8ffb1bcf | Gerd Hoffmann | static DeviceState *qbus_find_dev(BusState *bus, char *elem) |
706 | 8ffb1bcf | Gerd Hoffmann | { |
707 | 8ffb1bcf | Gerd Hoffmann | DeviceState *dev; |
708 | 8ffb1bcf | Gerd Hoffmann | |
709 | 8ffb1bcf | Gerd Hoffmann | /*
|
710 | 8ffb1bcf | Gerd Hoffmann | * try to match in order:
|
711 | 8ffb1bcf | Gerd Hoffmann | * (1) instance id, if present
|
712 | 8ffb1bcf | Gerd Hoffmann | * (2) driver name
|
713 | 8ffb1bcf | Gerd Hoffmann | * (3) driver alias, if present
|
714 | 8ffb1bcf | Gerd Hoffmann | */
|
715 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
716 | 8ffb1bcf | Gerd Hoffmann | if (dev->id && strcmp(dev->id, elem) == 0) { |
717 | 8ffb1bcf | Gerd Hoffmann | return dev;
|
718 | 8ffb1bcf | Gerd Hoffmann | } |
719 | 8ffb1bcf | Gerd Hoffmann | } |
720 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
721 | 8ffb1bcf | Gerd Hoffmann | if (strcmp(dev->info->name, elem) == 0) { |
722 | 8ffb1bcf | Gerd Hoffmann | return dev;
|
723 | 8ffb1bcf | Gerd Hoffmann | } |
724 | 8ffb1bcf | Gerd Hoffmann | } |
725 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
726 | 8ffb1bcf | Gerd Hoffmann | if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) { |
727 | 8ffb1bcf | Gerd Hoffmann | return dev;
|
728 | 8ffb1bcf | Gerd Hoffmann | } |
729 | 8ffb1bcf | Gerd Hoffmann | } |
730 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
731 | 8ffb1bcf | Gerd Hoffmann | } |
732 | 8ffb1bcf | Gerd Hoffmann | |
733 | 8ffb1bcf | Gerd Hoffmann | static BusState *qbus_find(const char *path) |
734 | 8ffb1bcf | Gerd Hoffmann | { |
735 | 8ffb1bcf | Gerd Hoffmann | DeviceState *dev; |
736 | 8ffb1bcf | Gerd Hoffmann | BusState *bus; |
737 | 53db16b5 | Markus Armbruster | char elem[128]; |
738 | 8ffb1bcf | Gerd Hoffmann | int pos, len;
|
739 | 8ffb1bcf | Gerd Hoffmann | |
740 | 8ffb1bcf | Gerd Hoffmann | /* find start element */
|
741 | 8ffb1bcf | Gerd Hoffmann | if (path[0] == '/') { |
742 | 8ffb1bcf | Gerd Hoffmann | bus = main_system_bus; |
743 | 8ffb1bcf | Gerd Hoffmann | pos = 0;
|
744 | 8ffb1bcf | Gerd Hoffmann | } else {
|
745 | 8ffb1bcf | Gerd Hoffmann | if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { |
746 | fc98eb43 | Markus Armbruster | assert(!path[0]);
|
747 | fc98eb43 | Markus Armbruster | elem[0] = len = 0; |
748 | 8ffb1bcf | Gerd Hoffmann | } |
749 | 8ffb1bcf | Gerd Hoffmann | bus = qbus_find_recursive(main_system_bus, elem, NULL);
|
750 | 8ffb1bcf | Gerd Hoffmann | if (!bus) {
|
751 | ac8dae67 | Markus Armbruster | qerror_report(QERR_BUS_NOT_FOUND, elem); |
752 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
753 | 8ffb1bcf | Gerd Hoffmann | } |
754 | 8ffb1bcf | Gerd Hoffmann | pos = len; |
755 | 8ffb1bcf | Gerd Hoffmann | } |
756 | 8ffb1bcf | Gerd Hoffmann | |
757 | 8ffb1bcf | Gerd Hoffmann | for (;;) {
|
758 | fc98eb43 | Markus Armbruster | assert(path[pos] == '/' || !path[pos]);
|
759 | fc98eb43 | Markus Armbruster | while (path[pos] == '/') { |
760 | fc98eb43 | Markus Armbruster | pos++; |
761 | fc98eb43 | Markus Armbruster | } |
762 | 8ffb1bcf | Gerd Hoffmann | if (path[pos] == '\0') { |
763 | 8ffb1bcf | Gerd Hoffmann | return bus;
|
764 | 8ffb1bcf | Gerd Hoffmann | } |
765 | 8ffb1bcf | Gerd Hoffmann | |
766 | 8ffb1bcf | Gerd Hoffmann | /* find device */
|
767 | fc98eb43 | Markus Armbruster | if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { |
768 | fc98eb43 | Markus Armbruster | assert(0);
|
769 | fc98eb43 | Markus Armbruster | elem[0] = len = 0; |
770 | 8ffb1bcf | Gerd Hoffmann | } |
771 | 8ffb1bcf | Gerd Hoffmann | pos += len; |
772 | 8ffb1bcf | Gerd Hoffmann | dev = qbus_find_dev(bus, elem); |
773 | 8ffb1bcf | Gerd Hoffmann | if (!dev) {
|
774 | ac8dae67 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, elem); |
775 | 8bc27249 | Markus Armbruster | if (!monitor_cur_is_qmp()) {
|
776 | 8bc27249 | Markus Armbruster | qbus_list_dev(bus); |
777 | 8bc27249 | Markus Armbruster | } |
778 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
779 | 8ffb1bcf | Gerd Hoffmann | } |
780 | fc98eb43 | Markus Armbruster | |
781 | fc98eb43 | Markus Armbruster | assert(path[pos] == '/' || !path[pos]);
|
782 | fc98eb43 | Markus Armbruster | while (path[pos] == '/') { |
783 | fc98eb43 | Markus Armbruster | pos++; |
784 | fc98eb43 | Markus Armbruster | } |
785 | 8ffb1bcf | Gerd Hoffmann | if (path[pos] == '\0') { |
786 | 8ffb1bcf | Gerd Hoffmann | /* last specified element is a device. If it has exactly
|
787 | 8ffb1bcf | Gerd Hoffmann | * one child bus accept it nevertheless */
|
788 | 8ffb1bcf | Gerd Hoffmann | switch (dev->num_child_bus) {
|
789 | 8ffb1bcf | Gerd Hoffmann | case 0: |
790 | ac8dae67 | Markus Armbruster | qerror_report(QERR_DEVICE_NO_BUS, elem); |
791 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
792 | 8ffb1bcf | Gerd Hoffmann | case 1: |
793 | 72cf2d4f | Blue Swirl | return QLIST_FIRST(&dev->child_bus);
|
794 | 8ffb1bcf | Gerd Hoffmann | default:
|
795 | ac8dae67 | Markus Armbruster | qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); |
796 | 8bc27249 | Markus Armbruster | if (!monitor_cur_is_qmp()) {
|
797 | 8bc27249 | Markus Armbruster | qbus_list_bus(dev); |
798 | 8bc27249 | Markus Armbruster | } |
799 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
800 | 8ffb1bcf | Gerd Hoffmann | } |
801 | 8ffb1bcf | Gerd Hoffmann | } |
802 | 8ffb1bcf | Gerd Hoffmann | |
803 | 8ffb1bcf | Gerd Hoffmann | /* find bus */
|
804 | fc98eb43 | Markus Armbruster | if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { |
805 | fc98eb43 | Markus Armbruster | assert(0);
|
806 | fc98eb43 | Markus Armbruster | elem[0] = len = 0; |
807 | 8ffb1bcf | Gerd Hoffmann | } |
808 | 8ffb1bcf | Gerd Hoffmann | pos += len; |
809 | 8ffb1bcf | Gerd Hoffmann | bus = qbus_find_bus(dev, elem); |
810 | 8ffb1bcf | Gerd Hoffmann | if (!bus) {
|
811 | ac8dae67 | Markus Armbruster | qerror_report(QERR_BUS_NOT_FOUND, elem); |
812 | 8bc27249 | Markus Armbruster | if (!monitor_cur_is_qmp()) {
|
813 | 8bc27249 | Markus Armbruster | qbus_list_bus(dev); |
814 | 8bc27249 | Markus Armbruster | } |
815 | 8ffb1bcf | Gerd Hoffmann | return NULL; |
816 | 8ffb1bcf | Gerd Hoffmann | } |
817 | 8ffb1bcf | Gerd Hoffmann | } |
818 | 8ffb1bcf | Gerd Hoffmann | } |
819 | 8ffb1bcf | Gerd Hoffmann | |
820 | cd739fb6 | Gerd Hoffmann | void qbus_create_inplace(BusState *bus, BusInfo *info,
|
821 | cd739fb6 | Gerd Hoffmann | DeviceState *parent, const char *name) |
822 | 02e2da45 | Paul Brook | { |
823 | d271de9f | Gerd Hoffmann | char *buf;
|
824 | d271de9f | Gerd Hoffmann | int i,len;
|
825 | 02e2da45 | Paul Brook | |
826 | 10c4c98a | Gerd Hoffmann | bus->info = info; |
827 | 02e2da45 | Paul Brook | bus->parent = parent; |
828 | d271de9f | Gerd Hoffmann | |
829 | d271de9f | Gerd Hoffmann | if (name) {
|
830 | d271de9f | Gerd Hoffmann | /* use supplied name */
|
831 | 7267c094 | Anthony Liguori | bus->name = g_strdup(name); |
832 | d271de9f | Gerd Hoffmann | } else if (parent && parent->id) { |
833 | d271de9f | Gerd Hoffmann | /* parent device has id -> use it for bus name */
|
834 | d271de9f | Gerd Hoffmann | len = strlen(parent->id) + 16;
|
835 | 7267c094 | Anthony Liguori | buf = g_malloc(len); |
836 | d271de9f | Gerd Hoffmann | snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
|
837 | d271de9f | Gerd Hoffmann | bus->name = buf; |
838 | d271de9f | Gerd Hoffmann | } else {
|
839 | d271de9f | Gerd Hoffmann | /* no id -> use lowercase bus type for bus name */
|
840 | d271de9f | Gerd Hoffmann | len = strlen(info->name) + 16;
|
841 | 7267c094 | Anthony Liguori | buf = g_malloc(len); |
842 | d271de9f | Gerd Hoffmann | len = snprintf(buf, len, "%s.%d", info->name,
|
843 | d271de9f | Gerd Hoffmann | parent ? parent->num_child_bus : 0);
|
844 | d271de9f | Gerd Hoffmann | for (i = 0; i < len; i++) |
845 | bb87ece5 | Christoph Egger | buf[i] = qemu_tolower(buf[i]); |
846 | d271de9f | Gerd Hoffmann | bus->name = buf; |
847 | d271de9f | Gerd Hoffmann | } |
848 | d271de9f | Gerd Hoffmann | |
849 | d8bb00d6 | Paolo Bonzini | QTAILQ_INIT(&bus->children); |
850 | 02e2da45 | Paul Brook | if (parent) {
|
851 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling); |
852 | d271de9f | Gerd Hoffmann | parent->num_child_bus++; |
853 | 80376c3f | Isaku Yamahata | } else if (bus != main_system_bus) { |
854 | 80376c3f | Isaku Yamahata | /* TODO: once all bus devices are qdevified,
|
855 | 80376c3f | Isaku Yamahata | only reset handler for main_system_bus should be registered here. */
|
856 | 80376c3f | Isaku Yamahata | qemu_register_reset(qbus_reset_all_fn, bus); |
857 | 02e2da45 | Paul Brook | } |
858 | cd739fb6 | Gerd Hoffmann | } |
859 | cd739fb6 | Gerd Hoffmann | |
860 | cd739fb6 | Gerd Hoffmann | BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name) |
861 | cd739fb6 | Gerd Hoffmann | { |
862 | cd739fb6 | Gerd Hoffmann | BusState *bus; |
863 | cd739fb6 | Gerd Hoffmann | |
864 | 7267c094 | Anthony Liguori | bus = g_malloc0(info->size); |
865 | cd739fb6 | Gerd Hoffmann | bus->qdev_allocated = 1;
|
866 | cd739fb6 | Gerd Hoffmann | qbus_create_inplace(bus, info, parent, name); |
867 | 02e2da45 | Paul Brook | return bus;
|
868 | 02e2da45 | Paul Brook | } |
869 | cae4956e | Gerd Hoffmann | |
870 | 2da8bb92 | Isaku Yamahata | static void main_system_bus_create(void) |
871 | 2da8bb92 | Isaku Yamahata | { |
872 | 2da8bb92 | Isaku Yamahata | /* assign main_system_bus before qbus_create_inplace()
|
873 | 2da8bb92 | Isaku Yamahata | * in order to make "if (bus != main_system_bus)" work */
|
874 | 7267c094 | Anthony Liguori | main_system_bus = g_malloc0(system_bus_info.size); |
875 | 2da8bb92 | Isaku Yamahata | main_system_bus->qdev_allocated = 1;
|
876 | 2da8bb92 | Isaku Yamahata | qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
|
877 | 2da8bb92 | Isaku Yamahata | "main-system-bus");
|
878 | 2da8bb92 | Isaku Yamahata | } |
879 | 2da8bb92 | Isaku Yamahata | |
880 | 131ec1bd | Gerd Hoffmann | void qbus_free(BusState *bus)
|
881 | 131ec1bd | Gerd Hoffmann | { |
882 | 131ec1bd | Gerd Hoffmann | DeviceState *dev; |
883 | 131ec1bd | Gerd Hoffmann | |
884 | d8bb00d6 | Paolo Bonzini | while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) { |
885 | 131ec1bd | Gerd Hoffmann | qdev_free(dev); |
886 | 131ec1bd | Gerd Hoffmann | } |
887 | 131ec1bd | Gerd Hoffmann | if (bus->parent) {
|
888 | 131ec1bd | Gerd Hoffmann | QLIST_REMOVE(bus, sibling); |
889 | 131ec1bd | Gerd Hoffmann | bus->parent->num_child_bus--; |
890 | 80376c3f | Isaku Yamahata | } else {
|
891 | 80376c3f | Isaku Yamahata | assert(bus != main_system_bus); /* main_system_bus is never freed */
|
892 | 80376c3f | Isaku Yamahata | qemu_unregister_reset(qbus_reset_all_fn, bus); |
893 | 131ec1bd | Gerd Hoffmann | } |
894 | 7267c094 | Anthony Liguori | g_free((void*)bus->name);
|
895 | 131ec1bd | Gerd Hoffmann | if (bus->qdev_allocated) {
|
896 | 7267c094 | Anthony Liguori | g_free(bus); |
897 | 131ec1bd | Gerd Hoffmann | } |
898 | 131ec1bd | Gerd Hoffmann | } |
899 | 131ec1bd | Gerd Hoffmann | |
900 | cae4956e | Gerd Hoffmann | #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) |
901 | cae4956e | Gerd Hoffmann | static void qbus_print(Monitor *mon, BusState *bus, int indent); |
902 | cae4956e | Gerd Hoffmann | |
903 | ee6847d1 | Gerd Hoffmann | static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, |
904 | ee6847d1 | Gerd Hoffmann | const char *prefix, int indent) |
905 | ee6847d1 | Gerd Hoffmann | { |
906 | ee6847d1 | Gerd Hoffmann | char buf[64]; |
907 | ee6847d1 | Gerd Hoffmann | |
908 | ee6847d1 | Gerd Hoffmann | if (!props)
|
909 | ee6847d1 | Gerd Hoffmann | return;
|
910 | ee6847d1 | Gerd Hoffmann | while (props->name) {
|
911 | 036f7166 | Markus Armbruster | /*
|
912 | 036f7166 | Markus Armbruster | * TODO Properties without a print method are just for dirty
|
913 | 036f7166 | Markus Armbruster | * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
|
914 | 036f7166 | Markus Armbruster | * marked for removal. The test props->info->print should be
|
915 | 036f7166 | Markus Armbruster | * removed along with it.
|
916 | 036f7166 | Markus Armbruster | */
|
917 | ee6847d1 | Gerd Hoffmann | if (props->info->print) {
|
918 | ee6847d1 | Gerd Hoffmann | props->info->print(dev, props, buf, sizeof(buf));
|
919 | ee6847d1 | Gerd Hoffmann | qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
|
920 | ee6847d1 | Gerd Hoffmann | } |
921 | ee6847d1 | Gerd Hoffmann | props++; |
922 | ee6847d1 | Gerd Hoffmann | } |
923 | ee6847d1 | Gerd Hoffmann | } |
924 | ee6847d1 | Gerd Hoffmann | |
925 | cae4956e | Gerd Hoffmann | static void qdev_print(Monitor *mon, DeviceState *dev, int indent) |
926 | cae4956e | Gerd Hoffmann | { |
927 | cae4956e | Gerd Hoffmann | BusState *child; |
928 | ccb63de3 | Gerd Hoffmann | qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
|
929 | ccb63de3 | Gerd Hoffmann | dev->id ? dev->id : "");
|
930 | cae4956e | Gerd Hoffmann | indent += 2;
|
931 | cae4956e | Gerd Hoffmann | if (dev->num_gpio_in) {
|
932 | cae4956e | Gerd Hoffmann | qdev_printf("gpio-in %d\n", dev->num_gpio_in);
|
933 | cae4956e | Gerd Hoffmann | } |
934 | cae4956e | Gerd Hoffmann | if (dev->num_gpio_out) {
|
935 | cae4956e | Gerd Hoffmann | qdev_printf("gpio-out %d\n", dev->num_gpio_out);
|
936 | cae4956e | Gerd Hoffmann | } |
937 | ee6847d1 | Gerd Hoffmann | qdev_print_props(mon, dev, dev->info->props, "dev", indent);
|
938 | ee6847d1 | Gerd Hoffmann | qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
|
939 | 10c4c98a | Gerd Hoffmann | if (dev->parent_bus->info->print_dev)
|
940 | 10c4c98a | Gerd Hoffmann | dev->parent_bus->info->print_dev(mon, dev, indent); |
941 | 72cf2d4f | Blue Swirl | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
942 | cae4956e | Gerd Hoffmann | qbus_print(mon, child, indent); |
943 | cae4956e | Gerd Hoffmann | } |
944 | cae4956e | Gerd Hoffmann | } |
945 | cae4956e | Gerd Hoffmann | |
946 | cae4956e | Gerd Hoffmann | static void qbus_print(Monitor *mon, BusState *bus, int indent) |
947 | cae4956e | Gerd Hoffmann | { |
948 | cae4956e | Gerd Hoffmann | struct DeviceState *dev;
|
949 | cae4956e | Gerd Hoffmann | |
950 | cae4956e | Gerd Hoffmann | qdev_printf("bus: %s\n", bus->name);
|
951 | cae4956e | Gerd Hoffmann | indent += 2;
|
952 | 10c4c98a | Gerd Hoffmann | qdev_printf("type %s\n", bus->info->name);
|
953 | d8bb00d6 | Paolo Bonzini | QTAILQ_FOREACH(dev, &bus->children, sibling) { |
954 | cae4956e | Gerd Hoffmann | qdev_print(mon, dev, indent); |
955 | cae4956e | Gerd Hoffmann | } |
956 | cae4956e | Gerd Hoffmann | } |
957 | cae4956e | Gerd Hoffmann | #undef qdev_printf
|
958 | cae4956e | Gerd Hoffmann | |
959 | cae4956e | Gerd Hoffmann | void do_info_qtree(Monitor *mon)
|
960 | cae4956e | Gerd Hoffmann | { |
961 | cae4956e | Gerd Hoffmann | if (main_system_bus)
|
962 | cae4956e | Gerd Hoffmann | qbus_print(mon, main_system_bus, 0);
|
963 | cae4956e | Gerd Hoffmann | } |
964 | 9316d30f | Gerd Hoffmann | |
965 | f6c64e0e | Gerd Hoffmann | void do_info_qdm(Monitor *mon)
|
966 | 9316d30f | Gerd Hoffmann | { |
967 | 9316d30f | Gerd Hoffmann | DeviceInfo *info; |
968 | 9316d30f | Gerd Hoffmann | |
969 | 9316d30f | Gerd Hoffmann | for (info = device_info_list; info != NULL; info = info->next) { |
970 | 8a9662ca | Markus Armbruster | qdev_print_devinfo(info); |
971 | 9316d30f | Gerd Hoffmann | } |
972 | 9316d30f | Gerd Hoffmann | } |
973 | 3418bd25 | Gerd Hoffmann | |
974 | 8bc27249 | Markus Armbruster | int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) |
975 | 3418bd25 | Gerd Hoffmann | { |
976 | 3418bd25 | Gerd Hoffmann | QemuOpts *opts; |
977 | 3418bd25 | Gerd Hoffmann | |
978 | 3329f07b | Gerd Hoffmann | opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
|
979 | 8bc27249 | Markus Armbruster | if (!opts) {
|
980 | 8bc27249 | Markus Armbruster | return -1; |
981 | 8bc27249 | Markus Armbruster | } |
982 | 8bc27249 | Markus Armbruster | if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
|
983 | 8bc27249 | Markus Armbruster | qemu_opts_del(opts); |
984 | 8bc27249 | Markus Armbruster | return 0; |
985 | 0f853a38 | Kevin Wolf | } |
986 | 8bc27249 | Markus Armbruster | if (!qdev_device_add(opts)) {
|
987 | 8bc27249 | Markus Armbruster | qemu_opts_del(opts); |
988 | 8bc27249 | Markus Armbruster | return -1; |
989 | 8bc27249 | Markus Armbruster | } |
990 | 8bc27249 | Markus Armbruster | return 0; |
991 | 3418bd25 | Gerd Hoffmann | } |
992 | 3418bd25 | Gerd Hoffmann | |
993 | 17a38eaa | Markus Armbruster | int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) |
994 | 3418bd25 | Gerd Hoffmann | { |
995 | 3418bd25 | Gerd Hoffmann | const char *id = qdict_get_str(qdict, "id"); |
996 | 3418bd25 | Gerd Hoffmann | DeviceState *dev; |
997 | 3418bd25 | Gerd Hoffmann | |
998 | 3418bd25 | Gerd Hoffmann | dev = qdev_find_recursive(main_system_bus, id); |
999 | 3418bd25 | Gerd Hoffmann | if (NULL == dev) { |
1000 | 17a38eaa | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, id); |
1001 | 17a38eaa | Markus Armbruster | return -1; |
1002 | 3418bd25 | Gerd Hoffmann | } |
1003 | 17a38eaa | Markus Armbruster | return qdev_unplug(dev);
|
1004 | 3418bd25 | Gerd Hoffmann | } |
1005 | 1ca4d09a | Gleb Natapov | |
1006 | 1ca4d09a | Gleb Natapov | static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) |
1007 | 1ca4d09a | Gleb Natapov | { |
1008 | 1ca4d09a | Gleb Natapov | int l = 0; |
1009 | 1ca4d09a | Gleb Natapov | |
1010 | 1ca4d09a | Gleb Natapov | if (dev && dev->parent_bus) {
|
1011 | 1ca4d09a | Gleb Natapov | char *d;
|
1012 | 1ca4d09a | Gleb Natapov | l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size); |
1013 | 1ca4d09a | Gleb Natapov | if (dev->parent_bus->info->get_fw_dev_path) {
|
1014 | 1ca4d09a | Gleb Natapov | d = dev->parent_bus->info->get_fw_dev_path(dev); |
1015 | 1ca4d09a | Gleb Natapov | l += snprintf(p + l, size - l, "%s", d);
|
1016 | 7267c094 | Anthony Liguori | g_free(d); |
1017 | 1ca4d09a | Gleb Natapov | } else {
|
1018 | 1ca4d09a | Gleb Natapov | l += snprintf(p + l, size - l, "%s", dev->info->name);
|
1019 | 1ca4d09a | Gleb Natapov | } |
1020 | 1ca4d09a | Gleb Natapov | } |
1021 | 1ca4d09a | Gleb Natapov | l += snprintf(p + l , size - l, "/");
|
1022 | 1ca4d09a | Gleb Natapov | |
1023 | 1ca4d09a | Gleb Natapov | return l;
|
1024 | 1ca4d09a | Gleb Natapov | } |
1025 | 1ca4d09a | Gleb Natapov | |
1026 | 1ca4d09a | Gleb Natapov | char* qdev_get_fw_dev_path(DeviceState *dev)
|
1027 | 1ca4d09a | Gleb Natapov | { |
1028 | 1ca4d09a | Gleb Natapov | char path[128]; |
1029 | 1ca4d09a | Gleb Natapov | int l;
|
1030 | 1ca4d09a | Gleb Natapov | |
1031 | 1ca4d09a | Gleb Natapov | l = qdev_get_fw_dev_path_helper(dev, path, 128);
|
1032 | 1ca4d09a | Gleb Natapov | |
1033 | 1ca4d09a | Gleb Natapov | path[l-1] = '\0'; |
1034 | 1ca4d09a | Gleb Natapov | |
1035 | 1ca4d09a | Gleb Natapov | return strdup(path);
|
1036 | 1ca4d09a | Gleb Natapov | } |
1037 | 85ed303b | Anthony Liguori | |
1038 | cd34d667 | Anthony Liguori | char *qdev_get_type(DeviceState *dev, Error **errp)
|
1039 | cd34d667 | Anthony Liguori | { |
1040 | cd34d667 | Anthony Liguori | return g_strdup(dev->info->name);
|
1041 | cd34d667 | Anthony Liguori | } |
1042 | cd34d667 | Anthony Liguori | |
1043 | 85ed303b | Anthony Liguori | void qdev_ref(DeviceState *dev)
|
1044 | 85ed303b | Anthony Liguori | { |
1045 | 85ed303b | Anthony Liguori | dev->ref++; |
1046 | 85ed303b | Anthony Liguori | } |
1047 | 85ed303b | Anthony Liguori | |
1048 | 85ed303b | Anthony Liguori | void qdev_unref(DeviceState *dev)
|
1049 | 85ed303b | Anthony Liguori | { |
1050 | 85ed303b | Anthony Liguori | g_assert(dev->ref > 0);
|
1051 | 85ed303b | Anthony Liguori | dev->ref--; |
1052 | 85ed303b | Anthony Liguori | } |
1053 | 44677ded | Anthony Liguori | |
1054 | 44677ded | Anthony Liguori | void qdev_property_add(DeviceState *dev, const char *name, const char *type, |
1055 | 44677ded | Anthony Liguori | DevicePropertyAccessor *get, DevicePropertyAccessor *set, |
1056 | 44677ded | Anthony Liguori | DevicePropertyRelease *release, |
1057 | 44677ded | Anthony Liguori | void *opaque, Error **errp)
|
1058 | 44677ded | Anthony Liguori | { |
1059 | 44677ded | Anthony Liguori | DeviceProperty *prop = g_malloc0(sizeof(*prop));
|
1060 | 44677ded | Anthony Liguori | |
1061 | 44677ded | Anthony Liguori | prop->name = g_strdup(name); |
1062 | 44677ded | Anthony Liguori | prop->type = g_strdup(type); |
1063 | 44677ded | Anthony Liguori | |
1064 | 44677ded | Anthony Liguori | prop->get = get; |
1065 | 44677ded | Anthony Liguori | prop->set = set; |
1066 | 44677ded | Anthony Liguori | prop->release = release; |
1067 | 44677ded | Anthony Liguori | prop->opaque = opaque; |
1068 | 44677ded | Anthony Liguori | |
1069 | 44677ded | Anthony Liguori | QTAILQ_INSERT_TAIL(&dev->properties, prop, node); |
1070 | 44677ded | Anthony Liguori | } |
1071 | 44677ded | Anthony Liguori | |
1072 | 44677ded | Anthony Liguori | static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name) |
1073 | 44677ded | Anthony Liguori | { |
1074 | 44677ded | Anthony Liguori | DeviceProperty *prop; |
1075 | 44677ded | Anthony Liguori | |
1076 | 44677ded | Anthony Liguori | QTAILQ_FOREACH(prop, &dev->properties, node) { |
1077 | 44677ded | Anthony Liguori | if (strcmp(prop->name, name) == 0) { |
1078 | 44677ded | Anthony Liguori | return prop;
|
1079 | 44677ded | Anthony Liguori | } |
1080 | 44677ded | Anthony Liguori | } |
1081 | 44677ded | Anthony Liguori | |
1082 | 44677ded | Anthony Liguori | return NULL; |
1083 | 44677ded | Anthony Liguori | } |
1084 | 44677ded | Anthony Liguori | |
1085 | 44677ded | Anthony Liguori | void qdev_property_get(DeviceState *dev, Visitor *v, const char *name, |
1086 | 44677ded | Anthony Liguori | Error **errp) |
1087 | 44677ded | Anthony Liguori | { |
1088 | 44677ded | Anthony Liguori | DeviceProperty *prop = qdev_property_find(dev, name); |
1089 | 44677ded | Anthony Liguori | |
1090 | 44677ded | Anthony Liguori | if (prop == NULL) { |
1091 | 44677ded | Anthony Liguori | error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
|
1092 | 44677ded | Anthony Liguori | return;
|
1093 | 44677ded | Anthony Liguori | } |
1094 | 44677ded | Anthony Liguori | |
1095 | 44677ded | Anthony Liguori | if (!prop->get) {
|
1096 | 44677ded | Anthony Liguori | error_set(errp, QERR_PERMISSION_DENIED); |
1097 | 44677ded | Anthony Liguori | } else {
|
1098 | 44677ded | Anthony Liguori | prop->get(dev, v, prop->opaque, name, errp); |
1099 | 44677ded | Anthony Liguori | } |
1100 | 44677ded | Anthony Liguori | } |
1101 | 44677ded | Anthony Liguori | |
1102 | 44677ded | Anthony Liguori | void qdev_property_set(DeviceState *dev, Visitor *v, const char *name, |
1103 | 44677ded | Anthony Liguori | Error **errp) |
1104 | 44677ded | Anthony Liguori | { |
1105 | 44677ded | Anthony Liguori | DeviceProperty *prop = qdev_property_find(dev, name); |
1106 | 44677ded | Anthony Liguori | |
1107 | 44677ded | Anthony Liguori | if (prop == NULL) { |
1108 | 44677ded | Anthony Liguori | error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
|
1109 | 44677ded | Anthony Liguori | return;
|
1110 | 44677ded | Anthony Liguori | } |
1111 | 44677ded | Anthony Liguori | |
1112 | 44677ded | Anthony Liguori | if (!prop->set) {
|
1113 | 44677ded | Anthony Liguori | error_set(errp, QERR_PERMISSION_DENIED); |
1114 | 44677ded | Anthony Liguori | } else {
|
1115 | 0d41d9aa | Paolo Bonzini | prop->set(dev, v, prop->opaque, name, errp); |
1116 | 44677ded | Anthony Liguori | } |
1117 | 44677ded | Anthony Liguori | } |
1118 | 44677ded | Anthony Liguori | |
1119 | 44677ded | Anthony Liguori | const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp) |
1120 | 44677ded | Anthony Liguori | { |
1121 | 44677ded | Anthony Liguori | DeviceProperty *prop = qdev_property_find(dev, name); |
1122 | 44677ded | Anthony Liguori | |
1123 | 44677ded | Anthony Liguori | if (prop == NULL) { |
1124 | 44677ded | Anthony Liguori | error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
|
1125 | 44677ded | Anthony Liguori | return NULL; |
1126 | 44677ded | Anthony Liguori | } |
1127 | 44677ded | Anthony Liguori | |
1128 | 44677ded | Anthony Liguori | return prop->type;
|
1129 | 44677ded | Anthony Liguori | } |
1130 | a5296ca9 | Anthony Liguori | |
1131 | a5296ca9 | Anthony Liguori | /**
|
1132 | a5296ca9 | Anthony Liguori | * Legacy property handling
|
1133 | a5296ca9 | Anthony Liguori | */
|
1134 | a5296ca9 | Anthony Liguori | |
1135 | a5296ca9 | Anthony Liguori | static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque, |
1136 | a5296ca9 | Anthony Liguori | const char *name, Error **errp) |
1137 | a5296ca9 | Anthony Liguori | { |
1138 | a5296ca9 | Anthony Liguori | Property *prop = opaque; |
1139 | a5296ca9 | Anthony Liguori | |
1140 | e3cb6ba6 | Paolo Bonzini | char buffer[1024]; |
1141 | e3cb6ba6 | Paolo Bonzini | char *ptr = buffer;
|
1142 | a5296ca9 | Anthony Liguori | |
1143 | e3cb6ba6 | Paolo Bonzini | prop->info->print(dev, prop, buffer, sizeof(buffer));
|
1144 | e3cb6ba6 | Paolo Bonzini | visit_type_str(v, &ptr, name, errp); |
1145 | a5296ca9 | Anthony Liguori | } |
1146 | a5296ca9 | Anthony Liguori | |
1147 | a5296ca9 | Anthony Liguori | static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque, |
1148 | a5296ca9 | Anthony Liguori | const char *name, Error **errp) |
1149 | a5296ca9 | Anthony Liguori | { |
1150 | a5296ca9 | Anthony Liguori | Property *prop = opaque; |
1151 | e3cb6ba6 | Paolo Bonzini | Error *local_err = NULL;
|
1152 | e3cb6ba6 | Paolo Bonzini | char *ptr = NULL; |
1153 | e3cb6ba6 | Paolo Bonzini | int ret;
|
1154 | a5296ca9 | Anthony Liguori | |
1155 | a5296ca9 | Anthony Liguori | if (dev->state != DEV_STATE_CREATED) {
|
1156 | a5296ca9 | Anthony Liguori | error_set(errp, QERR_PERMISSION_DENIED); |
1157 | a5296ca9 | Anthony Liguori | return;
|
1158 | a5296ca9 | Anthony Liguori | } |
1159 | a5296ca9 | Anthony Liguori | |
1160 | e3cb6ba6 | Paolo Bonzini | visit_type_str(v, &ptr, name, &local_err); |
1161 | e3cb6ba6 | Paolo Bonzini | if (local_err) {
|
1162 | e3cb6ba6 | Paolo Bonzini | error_propagate(errp, local_err); |
1163 | e3cb6ba6 | Paolo Bonzini | return;
|
1164 | e3cb6ba6 | Paolo Bonzini | } |
1165 | a5296ca9 | Anthony Liguori | |
1166 | e3cb6ba6 | Paolo Bonzini | ret = prop->info->parse(dev, prop, ptr); |
1167 | 7db4c4e8 | Paolo Bonzini | error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr); |
1168 | e3cb6ba6 | Paolo Bonzini | g_free(ptr); |
1169 | a5296ca9 | Anthony Liguori | } |
1170 | a5296ca9 | Anthony Liguori | |
1171 | a5296ca9 | Anthony Liguori | /**
|
1172 | a5296ca9 | Anthony Liguori | * @qdev_add_legacy_property - adds a legacy property
|
1173 | a5296ca9 | Anthony Liguori | *
|
1174 | a5296ca9 | Anthony Liguori | * Do not use this is new code! Properties added through this interface will
|
1175 | a5296ca9 | Anthony Liguori | * be given types in the "legacy<>" type namespace.
|
1176 | a5296ca9 | Anthony Liguori | *
|
1177 | a5296ca9 | Anthony Liguori | * Legacy properties are always processed as strings. The format of the string
|
1178 | a5296ca9 | Anthony Liguori | * depends on the property type.
|
1179 | a5296ca9 | Anthony Liguori | */
|
1180 | a5296ca9 | Anthony Liguori | void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
1181 | a5296ca9 | Anthony Liguori | Error **errp) |
1182 | a5296ca9 | Anthony Liguori | { |
1183 | a5296ca9 | Anthony Liguori | gchar *type; |
1184 | a5296ca9 | Anthony Liguori | |
1185 | cafe5bdb | Paolo Bonzini | type = g_strdup_printf("legacy<%s>",
|
1186 | cafe5bdb | Paolo Bonzini | prop->info->legacy_name ?: prop->info->name); |
1187 | a5296ca9 | Anthony Liguori | |
1188 | a5296ca9 | Anthony Liguori | qdev_property_add(dev, prop->name, type, |
1189 | e3cb6ba6 | Paolo Bonzini | prop->info->print ? qdev_get_legacy_property : NULL,
|
1190 | e3cb6ba6 | Paolo Bonzini | prop->info->parse ? qdev_set_legacy_property : NULL,
|
1191 | a5296ca9 | Anthony Liguori | NULL,
|
1192 | a5296ca9 | Anthony Liguori | prop, errp); |
1193 | a5296ca9 | Anthony Liguori | |
1194 | a5296ca9 | Anthony Liguori | g_free(type); |
1195 | a5296ca9 | Anthony Liguori | } |
1196 | a10f07a7 | Anthony Liguori | |
1197 | a10f07a7 | Anthony Liguori | DeviceState *qdev_get_root(void)
|
1198 | a10f07a7 | Anthony Liguori | { |
1199 | a10f07a7 | Anthony Liguori | static DeviceState *qdev_root;
|
1200 | a10f07a7 | Anthony Liguori | |
1201 | a10f07a7 | Anthony Liguori | if (!qdev_root) {
|
1202 | a10f07a7 | Anthony Liguori | qdev_root = qdev_create(NULL, "container"); |
1203 | a10f07a7 | Anthony Liguori | qdev_init_nofail(qdev_root); |
1204 | a10f07a7 | Anthony Liguori | } |
1205 | a10f07a7 | Anthony Liguori | |
1206 | a10f07a7 | Anthony Liguori | return qdev_root;
|
1207 | a10f07a7 | Anthony Liguori | } |
1208 | f9fbd2fd | Anthony Liguori | |
1209 | 3de1c3e8 | Anthony Liguori | static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque, |
1210 | 3de1c3e8 | Anthony Liguori | const char *name, Error **errp) |
1211 | 3de1c3e8 | Anthony Liguori | { |
1212 | 3de1c3e8 | Anthony Liguori | DeviceState *child = opaque; |
1213 | 3de1c3e8 | Anthony Liguori | gchar *path; |
1214 | 3de1c3e8 | Anthony Liguori | |
1215 | 3de1c3e8 | Anthony Liguori | path = qdev_get_canonical_path(child); |
1216 | 3de1c3e8 | Anthony Liguori | visit_type_str(v, &path, name, errp); |
1217 | 3de1c3e8 | Anthony Liguori | g_free(path); |
1218 | 3de1c3e8 | Anthony Liguori | } |
1219 | 3de1c3e8 | Anthony Liguori | |
1220 | 3de1c3e8 | Anthony Liguori | void qdev_property_add_child(DeviceState *dev, const char *name, |
1221 | 3de1c3e8 | Anthony Liguori | DeviceState *child, Error **errp) |
1222 | 3de1c3e8 | Anthony Liguori | { |
1223 | 3de1c3e8 | Anthony Liguori | gchar *type; |
1224 | 3de1c3e8 | Anthony Liguori | |
1225 | 3de1c3e8 | Anthony Liguori | type = g_strdup_printf("child<%s>", child->info->name);
|
1226 | 3de1c3e8 | Anthony Liguori | |
1227 | 3de1c3e8 | Anthony Liguori | qdev_property_add(dev, name, type, qdev_get_child_property, |
1228 | 3de1c3e8 | Anthony Liguori | NULL, NULL, child, errp); |
1229 | 3de1c3e8 | Anthony Liguori | |
1230 | 3de1c3e8 | Anthony Liguori | qdev_ref(child); |
1231 | b2b6c39a | Anthony Liguori | g_assert(child->parent == NULL);
|
1232 | b2b6c39a | Anthony Liguori | child->parent = dev; |
1233 | 3de1c3e8 | Anthony Liguori | |
1234 | 3de1c3e8 | Anthony Liguori | g_free(type); |
1235 | 3de1c3e8 | Anthony Liguori | } |
1236 | 3de1c3e8 | Anthony Liguori | |
1237 | 83e94fb8 | Anthony Liguori | static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque, |
1238 | 83e94fb8 | Anthony Liguori | const char *name, Error **errp) |
1239 | 83e94fb8 | Anthony Liguori | { |
1240 | 83e94fb8 | Anthony Liguori | DeviceState **child = opaque; |
1241 | 83e94fb8 | Anthony Liguori | gchar *path; |
1242 | 83e94fb8 | Anthony Liguori | |
1243 | 83e94fb8 | Anthony Liguori | if (*child) {
|
1244 | 83e94fb8 | Anthony Liguori | path = qdev_get_canonical_path(*child); |
1245 | 83e94fb8 | Anthony Liguori | visit_type_str(v, &path, name, errp); |
1246 | 83e94fb8 | Anthony Liguori | g_free(path); |
1247 | 83e94fb8 | Anthony Liguori | } else {
|
1248 | 83e94fb8 | Anthony Liguori | path = (gchar *)"";
|
1249 | 83e94fb8 | Anthony Liguori | visit_type_str(v, &path, name, errp); |
1250 | 83e94fb8 | Anthony Liguori | } |
1251 | 83e94fb8 | Anthony Liguori | } |
1252 | 83e94fb8 | Anthony Liguori | |
1253 | 83e94fb8 | Anthony Liguori | static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque, |
1254 | 83e94fb8 | Anthony Liguori | const char *name, Error **errp) |
1255 | 83e94fb8 | Anthony Liguori | { |
1256 | 83e94fb8 | Anthony Liguori | DeviceState **child = opaque; |
1257 | 83e94fb8 | Anthony Liguori | bool ambiguous = false; |
1258 | 83e94fb8 | Anthony Liguori | const char *type; |
1259 | 83e94fb8 | Anthony Liguori | char *path;
|
1260 | 83e94fb8 | Anthony Liguori | |
1261 | 83e94fb8 | Anthony Liguori | type = qdev_property_get_type(dev, name, NULL);
|
1262 | 83e94fb8 | Anthony Liguori | |
1263 | 83e94fb8 | Anthony Liguori | visit_type_str(v, &path, name, errp); |
1264 | 83e94fb8 | Anthony Liguori | |
1265 | 83e94fb8 | Anthony Liguori | if (*child) {
|
1266 | 83e94fb8 | Anthony Liguori | qdev_unref(*child); |
1267 | 83e94fb8 | Anthony Liguori | } |
1268 | 83e94fb8 | Anthony Liguori | |
1269 | 83e94fb8 | Anthony Liguori | if (strcmp(path, "") != 0) { |
1270 | 83e94fb8 | Anthony Liguori | DeviceState *target; |
1271 | 83e94fb8 | Anthony Liguori | |
1272 | 83e94fb8 | Anthony Liguori | target = qdev_resolve_path(path, &ambiguous); |
1273 | 83e94fb8 | Anthony Liguori | if (target) {
|
1274 | 83e94fb8 | Anthony Liguori | gchar *target_type; |
1275 | 83e94fb8 | Anthony Liguori | |
1276 | 83e94fb8 | Anthony Liguori | target_type = g_strdup_printf("link<%s>", target->info->name);
|
1277 | 83e94fb8 | Anthony Liguori | if (strcmp(target_type, type) == 0) { |
1278 | 83e94fb8 | Anthony Liguori | *child = target; |
1279 | 83e94fb8 | Anthony Liguori | qdev_ref(target); |
1280 | 83e94fb8 | Anthony Liguori | } else {
|
1281 | 83e94fb8 | Anthony Liguori | error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type); |
1282 | 83e94fb8 | Anthony Liguori | } |
1283 | 83e94fb8 | Anthony Liguori | |
1284 | 83e94fb8 | Anthony Liguori | g_free(target_type); |
1285 | 83e94fb8 | Anthony Liguori | } else {
|
1286 | 83e94fb8 | Anthony Liguori | error_set(errp, QERR_DEVICE_NOT_FOUND, path); |
1287 | 83e94fb8 | Anthony Liguori | } |
1288 | 83e94fb8 | Anthony Liguori | } else {
|
1289 | 83e94fb8 | Anthony Liguori | *child = NULL;
|
1290 | 83e94fb8 | Anthony Liguori | } |
1291 | 83e94fb8 | Anthony Liguori | |
1292 | 83e94fb8 | Anthony Liguori | g_free(path); |
1293 | 83e94fb8 | Anthony Liguori | } |
1294 | 83e94fb8 | Anthony Liguori | |
1295 | 83e94fb8 | Anthony Liguori | void qdev_property_add_link(DeviceState *dev, const char *name, |
1296 | 83e94fb8 | Anthony Liguori | const char *type, DeviceState **child, |
1297 | 83e94fb8 | Anthony Liguori | Error **errp) |
1298 | 83e94fb8 | Anthony Liguori | { |
1299 | 83e94fb8 | Anthony Liguori | gchar *full_type; |
1300 | 83e94fb8 | Anthony Liguori | |
1301 | 83e94fb8 | Anthony Liguori | full_type = g_strdup_printf("link<%s>", type);
|
1302 | 83e94fb8 | Anthony Liguori | |
1303 | 83e94fb8 | Anthony Liguori | qdev_property_add(dev, name, full_type, |
1304 | 83e94fb8 | Anthony Liguori | qdev_get_link_property, |
1305 | 83e94fb8 | Anthony Liguori | qdev_set_link_property, |
1306 | 83e94fb8 | Anthony Liguori | NULL, child, errp);
|
1307 | 83e94fb8 | Anthony Liguori | |
1308 | 83e94fb8 | Anthony Liguori | g_free(full_type); |
1309 | 83e94fb8 | Anthony Liguori | } |
1310 | 83e94fb8 | Anthony Liguori | |
1311 | b2b6c39a | Anthony Liguori | gchar *qdev_get_canonical_path(DeviceState *dev) |
1312 | f9fbd2fd | Anthony Liguori | { |
1313 | b2b6c39a | Anthony Liguori | DeviceState *root = qdev_get_root(); |
1314 | b2b6c39a | Anthony Liguori | char *newpath = NULL, *path = NULL; |
1315 | f9fbd2fd | Anthony Liguori | |
1316 | b2b6c39a | Anthony Liguori | while (dev != root) {
|
1317 | b2b6c39a | Anthony Liguori | DeviceProperty *prop = NULL;
|
1318 | f9fbd2fd | Anthony Liguori | |
1319 | b2b6c39a | Anthony Liguori | g_assert(dev->parent != NULL);
|
1320 | f9fbd2fd | Anthony Liguori | |
1321 | b2b6c39a | Anthony Liguori | QTAILQ_FOREACH(prop, &dev->parent->properties, node) { |
1322 | b2b6c39a | Anthony Liguori | if (!strstart(prop->type, "child<", NULL)) { |
1323 | b2b6c39a | Anthony Liguori | continue;
|
1324 | b2b6c39a | Anthony Liguori | } |
1325 | f9fbd2fd | Anthony Liguori | |
1326 | b2b6c39a | Anthony Liguori | if (prop->opaque == dev) {
|
1327 | b2b6c39a | Anthony Liguori | if (path) {
|
1328 | b2b6c39a | Anthony Liguori | newpath = g_strdup_printf("%s/%s", prop->name, path);
|
1329 | b2b6c39a | Anthony Liguori | g_free(path); |
1330 | b2b6c39a | Anthony Liguori | path = newpath; |
1331 | b2b6c39a | Anthony Liguori | } else {
|
1332 | b2b6c39a | Anthony Liguori | path = g_strdup(prop->name); |
1333 | b2b6c39a | Anthony Liguori | } |
1334 | b2b6c39a | Anthony Liguori | break;
|
1335 | b2b6c39a | Anthony Liguori | } |
1336 | f9fbd2fd | Anthony Liguori | } |
1337 | f9fbd2fd | Anthony Liguori | |
1338 | b2b6c39a | Anthony Liguori | g_assert(prop != NULL);
|
1339 | f9fbd2fd | Anthony Liguori | |
1340 | b2b6c39a | Anthony Liguori | dev = dev->parent; |
1341 | f9fbd2fd | Anthony Liguori | } |
1342 | f9fbd2fd | Anthony Liguori | |
1343 | f9fbd2fd | Anthony Liguori | newpath = g_strdup_printf("/%s", path);
|
1344 | f9fbd2fd | Anthony Liguori | g_free(path); |
1345 | f9fbd2fd | Anthony Liguori | |
1346 | f9fbd2fd | Anthony Liguori | return newpath;
|
1347 | f9fbd2fd | Anthony Liguori | } |
1348 | dc45c21f | Anthony Liguori | |
1349 | dc45c21f | Anthony Liguori | static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
|
1350 | dc45c21f | Anthony Liguori | gchar **parts, |
1351 | dc45c21f | Anthony Liguori | int index)
|
1352 | dc45c21f | Anthony Liguori | { |
1353 | dc45c21f | Anthony Liguori | DeviceProperty *prop; |
1354 | dc45c21f | Anthony Liguori | DeviceState *child; |
1355 | dc45c21f | Anthony Liguori | |
1356 | dc45c21f | Anthony Liguori | if (parts[index] == NULL) { |
1357 | dc45c21f | Anthony Liguori | return parent;
|
1358 | dc45c21f | Anthony Liguori | } |
1359 | dc45c21f | Anthony Liguori | |
1360 | dc45c21f | Anthony Liguori | if (strcmp(parts[index], "") == 0) { |
1361 | dc45c21f | Anthony Liguori | return qdev_resolve_abs_path(parent, parts, index + 1); |
1362 | dc45c21f | Anthony Liguori | } |
1363 | dc45c21f | Anthony Liguori | |
1364 | dc45c21f | Anthony Liguori | prop = qdev_property_find(parent, parts[index]); |
1365 | dc45c21f | Anthony Liguori | if (prop == NULL) { |
1366 | dc45c21f | Anthony Liguori | return NULL; |
1367 | dc45c21f | Anthony Liguori | } |
1368 | dc45c21f | Anthony Liguori | |
1369 | dc45c21f | Anthony Liguori | child = NULL;
|
1370 | dc45c21f | Anthony Liguori | if (strstart(prop->type, "link<", NULL)) { |
1371 | dc45c21f | Anthony Liguori | DeviceState **pchild = prop->opaque; |
1372 | dc45c21f | Anthony Liguori | if (*pchild) {
|
1373 | dc45c21f | Anthony Liguori | child = *pchild; |
1374 | dc45c21f | Anthony Liguori | } |
1375 | dc45c21f | Anthony Liguori | } else if (strstart(prop->type, "child<", NULL)) { |
1376 | dc45c21f | Anthony Liguori | child = prop->opaque; |
1377 | dc45c21f | Anthony Liguori | } |
1378 | dc45c21f | Anthony Liguori | |
1379 | dc45c21f | Anthony Liguori | if (!child) {
|
1380 | dc45c21f | Anthony Liguori | return NULL; |
1381 | dc45c21f | Anthony Liguori | } |
1382 | dc45c21f | Anthony Liguori | |
1383 | dc45c21f | Anthony Liguori | return qdev_resolve_abs_path(child, parts, index + 1); |
1384 | dc45c21f | Anthony Liguori | } |
1385 | dc45c21f | Anthony Liguori | |
1386 | dc45c21f | Anthony Liguori | static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
|
1387 | dc45c21f | Anthony Liguori | gchar **parts, |
1388 | dc45c21f | Anthony Liguori | bool *ambiguous)
|
1389 | dc45c21f | Anthony Liguori | { |
1390 | dc45c21f | Anthony Liguori | DeviceState *dev; |
1391 | dc45c21f | Anthony Liguori | DeviceProperty *prop; |
1392 | dc45c21f | Anthony Liguori | |
1393 | dc45c21f | Anthony Liguori | dev = qdev_resolve_abs_path(parent, parts, 0);
|
1394 | dc45c21f | Anthony Liguori | |
1395 | dc45c21f | Anthony Liguori | QTAILQ_FOREACH(prop, &parent->properties, node) { |
1396 | dc45c21f | Anthony Liguori | DeviceState *found; |
1397 | dc45c21f | Anthony Liguori | |
1398 | dc45c21f | Anthony Liguori | if (!strstart(prop->type, "child<", NULL)) { |
1399 | dc45c21f | Anthony Liguori | continue;
|
1400 | dc45c21f | Anthony Liguori | } |
1401 | dc45c21f | Anthony Liguori | |
1402 | dc45c21f | Anthony Liguori | found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous); |
1403 | dc45c21f | Anthony Liguori | if (found) {
|
1404 | dc45c21f | Anthony Liguori | if (dev) {
|
1405 | dc45c21f | Anthony Liguori | if (ambiguous) {
|
1406 | dc45c21f | Anthony Liguori | *ambiguous = true;
|
1407 | dc45c21f | Anthony Liguori | } |
1408 | dc45c21f | Anthony Liguori | return NULL; |
1409 | dc45c21f | Anthony Liguori | } |
1410 | dc45c21f | Anthony Liguori | dev = found; |
1411 | dc45c21f | Anthony Liguori | } |
1412 | dc45c21f | Anthony Liguori | |
1413 | dc45c21f | Anthony Liguori | if (ambiguous && *ambiguous) {
|
1414 | dc45c21f | Anthony Liguori | return NULL; |
1415 | dc45c21f | Anthony Liguori | } |
1416 | dc45c21f | Anthony Liguori | } |
1417 | dc45c21f | Anthony Liguori | |
1418 | dc45c21f | Anthony Liguori | return dev;
|
1419 | dc45c21f | Anthony Liguori | } |
1420 | dc45c21f | Anthony Liguori | |
1421 | dc45c21f | Anthony Liguori | DeviceState *qdev_resolve_path(const char *path, bool *ambiguous) |
1422 | dc45c21f | Anthony Liguori | { |
1423 | dc45c21f | Anthony Liguori | bool partial_path = true; |
1424 | dc45c21f | Anthony Liguori | DeviceState *dev; |
1425 | dc45c21f | Anthony Liguori | gchar **parts; |
1426 | dc45c21f | Anthony Liguori | |
1427 | dc45c21f | Anthony Liguori | parts = g_strsplit(path, "/", 0); |
1428 | dc45c21f | Anthony Liguori | if (parts == NULL || parts[0] == NULL) { |
1429 | dc45c21f | Anthony Liguori | g_strfreev(parts); |
1430 | dc45c21f | Anthony Liguori | return qdev_get_root();
|
1431 | dc45c21f | Anthony Liguori | } |
1432 | dc45c21f | Anthony Liguori | |
1433 | dc45c21f | Anthony Liguori | if (strcmp(parts[0], "") == 0) { |
1434 | dc45c21f | Anthony Liguori | partial_path = false;
|
1435 | dc45c21f | Anthony Liguori | } |
1436 | dc45c21f | Anthony Liguori | |
1437 | dc45c21f | Anthony Liguori | if (partial_path) {
|
1438 | dc45c21f | Anthony Liguori | if (ambiguous) {
|
1439 | dc45c21f | Anthony Liguori | *ambiguous = false;
|
1440 | dc45c21f | Anthony Liguori | } |
1441 | dc45c21f | Anthony Liguori | dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous); |
1442 | dc45c21f | Anthony Liguori | } else {
|
1443 | dc45c21f | Anthony Liguori | dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
|
1444 | dc45c21f | Anthony Liguori | } |
1445 | dc45c21f | Anthony Liguori | |
1446 | dc45c21f | Anthony Liguori | g_strfreev(parts); |
1447 | dc45c21f | Anthony Liguori | |
1448 | dc45c21f | Anthony Liguori | return dev;
|
1449 | dc45c21f | Anthony Liguori | } |
1450 | dc45c21f | Anthony Liguori | |
1451 | 6a146eba | Anthony Liguori | typedef struct StringProperty |
1452 | 6a146eba | Anthony Liguori | { |
1453 | 6a146eba | Anthony Liguori | char *(*get)(DeviceState *, Error **);
|
1454 | 6a146eba | Anthony Liguori | void (*set)(DeviceState *, const char *, Error **); |
1455 | 6a146eba | Anthony Liguori | } StringProperty; |
1456 | 6a146eba | Anthony Liguori | |
1457 | 6a146eba | Anthony Liguori | static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque, |
1458 | 6a146eba | Anthony Liguori | const char *name, Error **errp) |
1459 | 6a146eba | Anthony Liguori | { |
1460 | 6a146eba | Anthony Liguori | StringProperty *prop = opaque; |
1461 | 6a146eba | Anthony Liguori | char *value;
|
1462 | 6a146eba | Anthony Liguori | |
1463 | 6a146eba | Anthony Liguori | value = prop->get(dev, errp); |
1464 | 6a146eba | Anthony Liguori | if (value) {
|
1465 | 6a146eba | Anthony Liguori | visit_type_str(v, &value, name, errp); |
1466 | 6a146eba | Anthony Liguori | g_free(value); |
1467 | 6a146eba | Anthony Liguori | } |
1468 | 6a146eba | Anthony Liguori | } |
1469 | 6a146eba | Anthony Liguori | |
1470 | 6a146eba | Anthony Liguori | static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque, |
1471 | 6a146eba | Anthony Liguori | const char *name, Error **errp) |
1472 | 6a146eba | Anthony Liguori | { |
1473 | 6a146eba | Anthony Liguori | StringProperty *prop = opaque; |
1474 | 6a146eba | Anthony Liguori | char *value;
|
1475 | 6a146eba | Anthony Liguori | Error *local_err = NULL;
|
1476 | 6a146eba | Anthony Liguori | |
1477 | 6a146eba | Anthony Liguori | visit_type_str(v, &value, name, &local_err); |
1478 | 6a146eba | Anthony Liguori | if (local_err) {
|
1479 | 6a146eba | Anthony Liguori | error_propagate(errp, local_err); |
1480 | 6a146eba | Anthony Liguori | return;
|
1481 | 6a146eba | Anthony Liguori | } |
1482 | 6a146eba | Anthony Liguori | |
1483 | 6a146eba | Anthony Liguori | prop->set(dev, value, errp); |
1484 | 6a146eba | Anthony Liguori | g_free(value); |
1485 | 6a146eba | Anthony Liguori | } |
1486 | 6a146eba | Anthony Liguori | |
1487 | 6a146eba | Anthony Liguori | static void qdev_property_release_str(DeviceState *dev, const char *name, |
1488 | 6a146eba | Anthony Liguori | void *opaque)
|
1489 | 6a146eba | Anthony Liguori | { |
1490 | 6a146eba | Anthony Liguori | StringProperty *prop = opaque; |
1491 | 6a146eba | Anthony Liguori | g_free(prop); |
1492 | 6a146eba | Anthony Liguori | } |
1493 | 6a146eba | Anthony Liguori | |
1494 | 6a146eba | Anthony Liguori | void qdev_property_add_str(DeviceState *dev, const char *name, |
1495 | 6a146eba | Anthony Liguori | char *(*get)(DeviceState *, Error **),
|
1496 | 6a146eba | Anthony Liguori | void (*set)(DeviceState *, const char *, Error **), |
1497 | 6a146eba | Anthony Liguori | Error **errp) |
1498 | 6a146eba | Anthony Liguori | { |
1499 | 6a146eba | Anthony Liguori | StringProperty *prop = g_malloc0(sizeof(*prop));
|
1500 | 6a146eba | Anthony Liguori | |
1501 | 6a146eba | Anthony Liguori | prop->get = get; |
1502 | 6a146eba | Anthony Liguori | prop->set = set; |
1503 | 6a146eba | Anthony Liguori | |
1504 | 6a146eba | Anthony Liguori | qdev_property_add(dev, name, "string",
|
1505 | 6a146eba | Anthony Liguori | get ? qdev_property_get_str : NULL,
|
1506 | 6a146eba | Anthony Liguori | set ? qdev_property_set_str : NULL,
|
1507 | 6a146eba | Anthony Liguori | qdev_property_release_str, |
1508 | 6a146eba | Anthony Liguori | prop, errp); |
1509 | 6a146eba | Anthony Liguori | } |