1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "hw/qdev-core.h"
22#include "hw/irq.h"
23#include "qapi/error.h"
24#include "hw/pm_debug.h"
25
26static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
27 const char *name)
28{
29 NamedGPIOList *ngl;
30
31 QLIST_FOREACH(ngl, &dev->gpios, node) {
32
33 if (g_strcmp0(name, ngl->name) == 0) {
34 return ngl;
35 }
36 }
37
38 ngl = g_malloc0(sizeof(*ngl));
39 ngl->name = g_strdup(name);
40 QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
41 return ngl;
42}
43
44void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
45 qemu_irq_handler handler,
46 void *opaque,
47 const char *name, int n)
48{
49 int i;
50 NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
51
52 assert(gpio_list->num_out == 0 || !name);
53 gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
54 opaque, n);
55
56 if (!name) {
57 name = "unnamed-gpio-in";
58 }
59
60
61
62
63 gchar *propname = g_strdup_printf("%s[*]", name);
64
65 for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
66 object_property_add_child(OBJECT(dev), propname,
67 OBJECT(gpio_list->in[i]));
68 }
69
70 g_free(propname);
71 gpio_list->num_in += n;
72}
73
74void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
75{
76 qdev_init_gpio_in_named(dev, handler, NULL, n);
77}
78
79void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
80 const char *name, int n)
81{
82 int i;
83 NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
84
85 assert(gpio_list->num_in == 0 || !name);
86
87 if (!name) {
88 name = "unnamed-gpio-out";
89 }
90 memset(pins, 0, sizeof(*pins) * n);
91
92
93
94
95 gchar *propname = g_strdup_printf("%s[*]", name);
96
97 for (i = 0; i < n; ++i) {
98 object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
99 (Object **)&pins[i],
100 object_property_allow_set_link,
101 OBJ_PROP_LINK_STRONG);
102 }
103 g_free(propname);
104 gpio_list->num_out += n;
105}
106
107void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
108{
109 qdev_init_gpio_out_named(dev, pins, NULL, n);
110}
111
112qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
113{
114 char *propname = g_strdup_printf("%s[%d]",
115 name ? name : "unnamed-gpio-in", n);
116 return (qemu_irq)object_property_get_link(OBJECT(dev), propname, NULL);
117}
118
119qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
120{
121 return qdev_get_gpio_in_named(dev, NULL, n);
122}
123
124qemu_irq qdev_get_gpio_out_named(DeviceState *dev, const char *name, int n)
125{
126 char *propname = g_strdup_printf("%s[%d]",
127 name ? name : "unnamed-gpio-out", n);
128 return (qemu_irq)object_property_get_link(OBJECT(dev), propname, NULL);
129}
130
131qemu_irq qdev_get_gpio_out(DeviceState *dev, int n)
132{
133 return qdev_get_gpio_out_named(dev, NULL, n);
134}
135
136void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
137 qemu_irq input_pin)
138{
139 Error *errp = NULL;
140 qemu_irq irq;
141 if (!input_pin) {
142 return;
143 }
144 char *propname = g_strdup_printf("%s[%d]",
145 name ? name : "unnamed-gpio-out", n);
146
147 irq = (qemu_irq)object_property_get_link(OBJECT(dev), propname, NULL);
148 if (irq) {
149 char *splitter_name;
150 irq = qemu_irq_split(irq, input_pin);
151
152 splitter_name = g_strdup_printf("%s-split-%p", propname, irq);
153 object_property_add_child(OBJECT(dev), splitter_name,OBJECT(irq));
154 } else {
155 irq = input_pin;
156 }
157 if (irq && !OBJECT(irq)->parent) {
158
159
160
161
162
163 object_property_add_child(container_get(qdev_get_machine(),
164 "/unattached"),
165 "non-qdev-gpio[*]", OBJECT(input_pin));
166 }
167 object_property_set_link(OBJECT(dev), propname, OBJECT(irq), &errp);
168 if (errp) {
169 qemu_log_mask(LOG_FDT, "FAILED to connect %s.%s <-> %s\n",
170 object_get_canonical_path(OBJECT(dev)), propname,
171 object_get_canonical_path(OBJECT(input_pin)));
172 }
173 g_free(propname);
174}
175
176qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
177{
178 g_autofree char *propname = g_strdup_printf("%s[%d]",
179 name ? name : "unnamed-gpio-out", n);
180
181 qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
182 NULL);
183
184 return ret;
185}
186
187
188
189static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
190 const char *name, int n)
191{
192 char *propname = g_strdup_printf("%s[%d]",
193 name ? name : "unnamed-gpio-out", n);
194
195 qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
196 NULL);
197 if (ret) {
198 object_property_set_link(OBJECT(dev), propname, NULL, NULL);
199 }
200 g_free(propname);
201 return ret;
202}
203
204qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
205 const char *name, int n)
206{
207 qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n);
208 qdev_connect_gpio_out_named(dev, name, n, icpt);
209 return disconnected;
210}
211
212void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
213{
214 qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
215}
216
217void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
218 const char *name)
219{
220 int i;
221 NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
222
223 for (i = 0; i < ngl->num_in; i++) {
224 const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in";
225 char *propname = g_strdup_printf("%s[%d]", nm, i);
226
227 object_property_add_alias(OBJECT(container), propname,
228 OBJECT(dev), propname);
229 g_free(propname);
230 }
231 for (i = 0; i < ngl->num_out; i++) {
232 const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
233 char *propname = g_strdup_printf("%s[%d]", nm, i);
234
235 object_property_add_alias(OBJECT(container), propname,
236 OBJECT(dev), propname);
237 g_free(propname);
238 }
239 QLIST_REMOVE(ngl, node);
240 QLIST_INSERT_HEAD(&container->gpios, ngl, node);
241}
242