1b19a3e2cSEduardo Habkost /*
2b19a3e2cSEduardo Habkost * qdev GPIO helpers
3b19a3e2cSEduardo Habkost *
4b19a3e2cSEduardo Habkost * Copyright (c) 2009 CodeSourcery
5b19a3e2cSEduardo Habkost *
6b19a3e2cSEduardo Habkost * This library is free software; you can redistribute it and/or
7b19a3e2cSEduardo Habkost * modify it under the terms of the GNU Lesser General Public
8b19a3e2cSEduardo Habkost * License as published by the Free Software Foundation; either
9b19a3e2cSEduardo Habkost * version 2 of the License, or (at your option) any later version.
10b19a3e2cSEduardo Habkost *
11b19a3e2cSEduardo Habkost * This library is distributed in the hope that it will be useful,
12b19a3e2cSEduardo Habkost * but WITHOUT ANY WARRANTY; without even the implied warranty of
13b19a3e2cSEduardo Habkost * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14b19a3e2cSEduardo Habkost * Lesser General Public License for more details.
15b19a3e2cSEduardo Habkost *
16b19a3e2cSEduardo Habkost * You should have received a copy of the GNU Lesser General Public
17b19a3e2cSEduardo Habkost * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18b19a3e2cSEduardo Habkost */
19b19a3e2cSEduardo Habkost
20b19a3e2cSEduardo Habkost #include "qemu/osdep.h"
21b19a3e2cSEduardo Habkost #include "hw/qdev-core.h"
22b19a3e2cSEduardo Habkost #include "hw/irq.h"
23b19a3e2cSEduardo Habkost #include "qapi/error.h"
24b19a3e2cSEduardo Habkost
qdev_get_named_gpio_list(DeviceState * dev,const char * name)25b19a3e2cSEduardo Habkost static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
26b19a3e2cSEduardo Habkost const char *name)
27b19a3e2cSEduardo Habkost {
28b19a3e2cSEduardo Habkost NamedGPIOList *ngl;
29b19a3e2cSEduardo Habkost
30b19a3e2cSEduardo Habkost QLIST_FOREACH(ngl, &dev->gpios, node) {
31b19a3e2cSEduardo Habkost /* NULL is a valid and matchable name. */
32b19a3e2cSEduardo Habkost if (g_strcmp0(name, ngl->name) == 0) {
33b19a3e2cSEduardo Habkost return ngl;
34b19a3e2cSEduardo Habkost }
35b19a3e2cSEduardo Habkost }
36b19a3e2cSEduardo Habkost
37b19a3e2cSEduardo Habkost ngl = g_malloc0(sizeof(*ngl));
38b19a3e2cSEduardo Habkost ngl->name = g_strdup(name);
39b19a3e2cSEduardo Habkost QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
40b19a3e2cSEduardo Habkost return ngl;
41b19a3e2cSEduardo Habkost }
42b19a3e2cSEduardo Habkost
qdev_init_gpio_in_named_with_opaque(DeviceState * dev,qemu_irq_handler handler,void * opaque,const char * name,int n)43b19a3e2cSEduardo Habkost void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
44b19a3e2cSEduardo Habkost qemu_irq_handler handler,
45b19a3e2cSEduardo Habkost void *opaque,
46b19a3e2cSEduardo Habkost const char *name, int n)
47b19a3e2cSEduardo Habkost {
48b19a3e2cSEduardo Habkost int i;
49b19a3e2cSEduardo Habkost NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
50b19a3e2cSEduardo Habkost
51b19a3e2cSEduardo Habkost assert(gpio_list->num_out == 0 || !name);
52b19a3e2cSEduardo Habkost gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
53b19a3e2cSEduardo Habkost opaque, n);
54b19a3e2cSEduardo Habkost
55b19a3e2cSEduardo Habkost if (!name) {
56b19a3e2cSEduardo Habkost name = "unnamed-gpio-in";
57b19a3e2cSEduardo Habkost }
58b19a3e2cSEduardo Habkost for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
59b19a3e2cSEduardo Habkost gchar *propname = g_strdup_printf("%s[%u]", name, i);
60b19a3e2cSEduardo Habkost
61b19a3e2cSEduardo Habkost object_property_add_child(OBJECT(dev), propname,
62b19a3e2cSEduardo Habkost OBJECT(gpio_list->in[i]));
63b19a3e2cSEduardo Habkost g_free(propname);
64b19a3e2cSEduardo Habkost }
65b19a3e2cSEduardo Habkost
66b19a3e2cSEduardo Habkost gpio_list->num_in += n;
67b19a3e2cSEduardo Habkost }
68b19a3e2cSEduardo Habkost
qdev_init_gpio_in(DeviceState * dev,qemu_irq_handler handler,int n)69b19a3e2cSEduardo Habkost void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
70b19a3e2cSEduardo Habkost {
71b19a3e2cSEduardo Habkost qdev_init_gpio_in_named(dev, handler, NULL, n);
72b19a3e2cSEduardo Habkost }
73b19a3e2cSEduardo Habkost
qdev_init_gpio_out_named(DeviceState * dev,qemu_irq * pins,const char * name,int n)74b19a3e2cSEduardo Habkost void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
75b19a3e2cSEduardo Habkost const char *name, int n)
76b19a3e2cSEduardo Habkost {
77b19a3e2cSEduardo Habkost int i;
78b19a3e2cSEduardo Habkost NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
79b19a3e2cSEduardo Habkost
80b19a3e2cSEduardo Habkost assert(gpio_list->num_in == 0 || !name);
81b19a3e2cSEduardo Habkost
82b19a3e2cSEduardo Habkost if (!name) {
83b19a3e2cSEduardo Habkost name = "unnamed-gpio-out";
84b19a3e2cSEduardo Habkost }
85b19a3e2cSEduardo Habkost memset(pins, 0, sizeof(*pins) * n);
86b19a3e2cSEduardo Habkost for (i = 0; i < n; ++i) {
87b19a3e2cSEduardo Habkost gchar *propname = g_strdup_printf("%s[%u]", name,
88b19a3e2cSEduardo Habkost gpio_list->num_out + i);
89b19a3e2cSEduardo Habkost
90b19a3e2cSEduardo Habkost object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
91b19a3e2cSEduardo Habkost (Object **)&pins[i],
92b19a3e2cSEduardo Habkost object_property_allow_set_link,
93b19a3e2cSEduardo Habkost OBJ_PROP_LINK_STRONG);
94b19a3e2cSEduardo Habkost g_free(propname);
95b19a3e2cSEduardo Habkost }
96b19a3e2cSEduardo Habkost gpio_list->num_out += n;
97b19a3e2cSEduardo Habkost }
98b19a3e2cSEduardo Habkost
qdev_init_gpio_out(DeviceState * dev,qemu_irq * pins,int n)99b19a3e2cSEduardo Habkost void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
100b19a3e2cSEduardo Habkost {
101b19a3e2cSEduardo Habkost qdev_init_gpio_out_named(dev, pins, NULL, n);
102b19a3e2cSEduardo Habkost }
103b19a3e2cSEduardo Habkost
qdev_get_gpio_in_named(DeviceState * dev,const char * name,int n)104b19a3e2cSEduardo Habkost qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
105b19a3e2cSEduardo Habkost {
106b19a3e2cSEduardo Habkost NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
107b19a3e2cSEduardo Habkost
108b19a3e2cSEduardo Habkost assert(n >= 0 && n < gpio_list->num_in);
109b19a3e2cSEduardo Habkost return gpio_list->in[n];
110b19a3e2cSEduardo Habkost }
111b19a3e2cSEduardo Habkost
qdev_get_gpio_in(DeviceState * dev,int n)112b19a3e2cSEduardo Habkost qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
113b19a3e2cSEduardo Habkost {
114b19a3e2cSEduardo Habkost return qdev_get_gpio_in_named(dev, NULL, n);
115b19a3e2cSEduardo Habkost }
116b19a3e2cSEduardo Habkost
qdev_connect_gpio_out_named(DeviceState * dev,const char * name,int n,qemu_irq input_pin)117b19a3e2cSEduardo Habkost void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
118*2ebd9ce1SPhilippe Mathieu-Daudé qemu_irq input_pin)
119b19a3e2cSEduardo Habkost {
120b19a3e2cSEduardo Habkost char *propname = g_strdup_printf("%s[%d]",
121b19a3e2cSEduardo Habkost name ? name : "unnamed-gpio-out", n);
122*2ebd9ce1SPhilippe Mathieu-Daudé if (input_pin && !OBJECT(input_pin)->parent) {
123b19a3e2cSEduardo Habkost /* We need a name for object_property_set_link to work */
124b19a3e2cSEduardo Habkost object_property_add_child(container_get(qdev_get_machine(),
125b19a3e2cSEduardo Habkost "/unattached"),
126*2ebd9ce1SPhilippe Mathieu-Daudé "non-qdev-gpio[*]", OBJECT(input_pin));
127b19a3e2cSEduardo Habkost }
128*2ebd9ce1SPhilippe Mathieu-Daudé object_property_set_link(OBJECT(dev), propname,
129*2ebd9ce1SPhilippe Mathieu-Daudé OBJECT(input_pin), &error_abort);
130b19a3e2cSEduardo Habkost g_free(propname);
131b19a3e2cSEduardo Habkost }
132b19a3e2cSEduardo Habkost
qdev_get_gpio_out_connector(DeviceState * dev,const char * name,int n)133b19a3e2cSEduardo Habkost qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
134b19a3e2cSEduardo Habkost {
135b19a3e2cSEduardo Habkost g_autofree char *propname = g_strdup_printf("%s[%d]",
136b19a3e2cSEduardo Habkost name ? name : "unnamed-gpio-out", n);
137b19a3e2cSEduardo Habkost
138b19a3e2cSEduardo Habkost qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
139b19a3e2cSEduardo Habkost NULL);
140b19a3e2cSEduardo Habkost
141b19a3e2cSEduardo Habkost return ret;
142b19a3e2cSEduardo Habkost }
143b19a3e2cSEduardo Habkost
144b19a3e2cSEduardo Habkost /* disconnect a GPIO output, returning the disconnected input (if any) */
145b19a3e2cSEduardo Habkost
qdev_disconnect_gpio_out_named(DeviceState * dev,const char * name,int n)146b19a3e2cSEduardo Habkost static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
147b19a3e2cSEduardo Habkost const char *name, int n)
148b19a3e2cSEduardo Habkost {
149b19a3e2cSEduardo Habkost char *propname = g_strdup_printf("%s[%d]",
150b19a3e2cSEduardo Habkost name ? name : "unnamed-gpio-out", n);
151b19a3e2cSEduardo Habkost
152b19a3e2cSEduardo Habkost qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
153b19a3e2cSEduardo Habkost NULL);
154b19a3e2cSEduardo Habkost if (ret) {
155b19a3e2cSEduardo Habkost object_property_set_link(OBJECT(dev), propname, NULL, NULL);
156b19a3e2cSEduardo Habkost }
157b19a3e2cSEduardo Habkost g_free(propname);
158b19a3e2cSEduardo Habkost return ret;
159b19a3e2cSEduardo Habkost }
160b19a3e2cSEduardo Habkost
qdev_intercept_gpio_out(DeviceState * dev,qemu_irq icpt,const char * name,int n)161b19a3e2cSEduardo Habkost qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
162b19a3e2cSEduardo Habkost const char *name, int n)
163b19a3e2cSEduardo Habkost {
164b19a3e2cSEduardo Habkost qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n);
165b19a3e2cSEduardo Habkost qdev_connect_gpio_out_named(dev, name, n, icpt);
166b19a3e2cSEduardo Habkost return disconnected;
167b19a3e2cSEduardo Habkost }
168b19a3e2cSEduardo Habkost
qdev_connect_gpio_out(DeviceState * dev,int n,qemu_irq input_pin)169*2ebd9ce1SPhilippe Mathieu-Daudé void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
170b19a3e2cSEduardo Habkost {
171*2ebd9ce1SPhilippe Mathieu-Daudé qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
172b19a3e2cSEduardo Habkost }
173b19a3e2cSEduardo Habkost
qdev_pass_gpios(DeviceState * dev,DeviceState * container,const char * name)174b19a3e2cSEduardo Habkost void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
175b19a3e2cSEduardo Habkost const char *name)
176b19a3e2cSEduardo Habkost {
177b19a3e2cSEduardo Habkost int i;
178b19a3e2cSEduardo Habkost NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
179b19a3e2cSEduardo Habkost
180b19a3e2cSEduardo Habkost for (i = 0; i < ngl->num_in; i++) {
181b19a3e2cSEduardo Habkost const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in";
182b19a3e2cSEduardo Habkost char *propname = g_strdup_printf("%s[%d]", nm, i);
183b19a3e2cSEduardo Habkost
184b19a3e2cSEduardo Habkost object_property_add_alias(OBJECT(container), propname,
185b19a3e2cSEduardo Habkost OBJECT(dev), propname);
186b19a3e2cSEduardo Habkost g_free(propname);
187b19a3e2cSEduardo Habkost }
188b19a3e2cSEduardo Habkost for (i = 0; i < ngl->num_out; i++) {
189b19a3e2cSEduardo Habkost const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
190b19a3e2cSEduardo Habkost char *propname = g_strdup_printf("%s[%d]", nm, i);
191b19a3e2cSEduardo Habkost
192b19a3e2cSEduardo Habkost object_property_add_alias(OBJECT(container), propname,
193b19a3e2cSEduardo Habkost OBJECT(dev), propname);
194b19a3e2cSEduardo Habkost g_free(propname);
195b19a3e2cSEduardo Habkost }
196b19a3e2cSEduardo Habkost QLIST_REMOVE(ngl, node);
197b19a3e2cSEduardo Habkost QLIST_INSERT_HEAD(&container->gpios, ngl, node);
198b19a3e2cSEduardo Habkost }
199