1 | /* |
2 | * Dynamic device configuration and creation -- buses. |
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 | #include "qemu/osdep.h" |
21 | #include "hw/qdev-properties.h" |
22 | #include "qemu/ctype.h" |
23 | #include "qemu/module.h" |
24 | #include "qapi/error.h" |
25 | |
26 | void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) |
27 | { |
28 | object_property_set_link(OBJECT(bus), OBJECT(handler), |
29 | QDEV_HOTPLUG_HANDLER_PROPERTY, errp); |
30 | } |
31 | |
32 | void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp) |
33 | { |
34 | qbus_set_hotplug_handler(bus, OBJECT(bus), errp); |
35 | } |
36 | |
37 | int qbus_walk_children(BusState *bus, |
38 | qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, |
39 | qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, |
40 | void *opaque) |
41 | { |
42 | BusChild *kid; |
43 | int err; |
44 | |
45 | if (pre_busfn) { |
46 | err = pre_busfn(bus, opaque); |
47 | if (err) { |
48 | return err; |
49 | } |
50 | } |
51 | |
52 | QTAILQ_FOREACH(kid, &bus->children, sibling) { |
53 | err = qdev_walk_children(kid->child, |
54 | pre_devfn, pre_busfn, |
55 | post_devfn, post_busfn, opaque); |
56 | if (err < 0) { |
57 | return err; |
58 | } |
59 | } |
60 | |
61 | if (post_busfn) { |
62 | err = post_busfn(bus, opaque); |
63 | if (err) { |
64 | return err; |
65 | } |
66 | } |
67 | |
68 | return 0; |
69 | } |
70 | |
71 | static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) |
72 | { |
73 | const char *typename = object_get_typename(OBJECT(bus)); |
74 | BusClass *bc; |
75 | int i, bus_id; |
76 | |
77 | bus->parent = parent; |
78 | |
79 | if (name) { |
80 | bus->name = g_strdup(name); |
81 | } else if (bus->parent && bus->parent->id) { |
82 | /* parent device has id -> use it plus parent-bus-id for bus name */ |
83 | bus_id = bus->parent->num_child_bus; |
84 | bus->name = g_strdup_printf("%s.%d" , bus->parent->id, bus_id); |
85 | } else { |
86 | /* no id -> use lowercase bus type plus global bus-id for bus name */ |
87 | bc = BUS_GET_CLASS(bus); |
88 | bus_id = bc->automatic_ids++; |
89 | bus->name = g_strdup_printf("%s.%d" , typename, bus_id); |
90 | for (i = 0; bus->name[i]; i++) { |
91 | bus->name[i] = qemu_tolower(bus->name[i]); |
92 | } |
93 | } |
94 | |
95 | if (bus->parent) { |
96 | QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); |
97 | bus->parent->num_child_bus++; |
98 | object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); |
99 | object_unref(OBJECT(bus)); |
100 | } else { |
101 | /* The only bus without a parent is the main system bus */ |
102 | assert(bus == sysbus_get_default()); |
103 | } |
104 | } |
105 | |
106 | static void bus_unparent(Object *obj) |
107 | { |
108 | BusState *bus = BUS(obj); |
109 | BusChild *kid; |
110 | |
111 | /* Only the main system bus has no parent, and that bus is never freed */ |
112 | assert(bus->parent); |
113 | |
114 | while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { |
115 | DeviceState *dev = kid->child; |
116 | object_unparent(OBJECT(dev)); |
117 | } |
118 | QLIST_REMOVE(bus, sibling); |
119 | bus->parent->num_child_bus--; |
120 | bus->parent = NULL; |
121 | } |
122 | |
123 | void qbus_create_inplace(void *bus, size_t size, const char *typename, |
124 | DeviceState *parent, const char *name) |
125 | { |
126 | object_initialize(bus, size, typename); |
127 | qbus_realize(bus, parent, name); |
128 | } |
129 | |
130 | BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) |
131 | { |
132 | BusState *bus; |
133 | |
134 | bus = BUS(object_new(typename)); |
135 | qbus_realize(bus, parent, name); |
136 | |
137 | return bus; |
138 | } |
139 | |
140 | static bool bus_get_realized(Object *obj, Error **errp) |
141 | { |
142 | BusState *bus = BUS(obj); |
143 | |
144 | return bus->realized; |
145 | } |
146 | |
147 | static void bus_set_realized(Object *obj, bool value, Error **errp) |
148 | { |
149 | BusState *bus = BUS(obj); |
150 | BusClass *bc = BUS_GET_CLASS(bus); |
151 | BusChild *kid; |
152 | Error *local_err = NULL; |
153 | |
154 | if (value && !bus->realized) { |
155 | if (bc->realize) { |
156 | bc->realize(bus, &local_err); |
157 | } |
158 | |
159 | /* TODO: recursive realization */ |
160 | } else if (!value && bus->realized) { |
161 | QTAILQ_FOREACH(kid, &bus->children, sibling) { |
162 | DeviceState *dev = kid->child; |
163 | object_property_set_bool(OBJECT(dev), false, "realized" , |
164 | &local_err); |
165 | if (local_err != NULL) { |
166 | break; |
167 | } |
168 | } |
169 | if (bc->unrealize && local_err == NULL) { |
170 | bc->unrealize(bus, &local_err); |
171 | } |
172 | } |
173 | |
174 | if (local_err != NULL) { |
175 | error_propagate(errp, local_err); |
176 | return; |
177 | } |
178 | |
179 | bus->realized = value; |
180 | } |
181 | |
182 | static void qbus_initfn(Object *obj) |
183 | { |
184 | BusState *bus = BUS(obj); |
185 | |
186 | QTAILQ_INIT(&bus->children); |
187 | object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, |
188 | TYPE_HOTPLUG_HANDLER, |
189 | (Object **)&bus->hotplug_handler, |
190 | object_property_allow_set_link, |
191 | 0, |
192 | NULL); |
193 | object_property_add_bool(obj, "realized" , |
194 | bus_get_realized, bus_set_realized, NULL); |
195 | } |
196 | |
197 | static char *default_bus_get_fw_dev_path(DeviceState *dev) |
198 | { |
199 | return g_strdup(object_get_typename(OBJECT(dev))); |
200 | } |
201 | |
202 | static void bus_class_init(ObjectClass *class, void *data) |
203 | { |
204 | BusClass *bc = BUS_CLASS(class); |
205 | |
206 | class->unparent = bus_unparent; |
207 | bc->get_fw_dev_path = default_bus_get_fw_dev_path; |
208 | } |
209 | |
210 | static void qbus_finalize(Object *obj) |
211 | { |
212 | BusState *bus = BUS(obj); |
213 | |
214 | g_free(bus->name); |
215 | } |
216 | |
217 | static const TypeInfo bus_info = { |
218 | .name = TYPE_BUS, |
219 | .parent = TYPE_OBJECT, |
220 | .instance_size = sizeof(BusState), |
221 | .abstract = true, |
222 | .class_size = sizeof(BusClass), |
223 | .instance_init = qbus_initfn, |
224 | .instance_finalize = qbus_finalize, |
225 | .class_init = bus_class_init, |
226 | }; |
227 | |
228 | static void bus_register_types(void) |
229 | { |
230 | type_register_static(&bus_info); |
231 | } |
232 | |
233 | type_init(bus_register_types) |
234 | |