Merge tag 'migration-staging-pull-request' of https://gitlab.com/peterx/qemu into...
[qemu/ar7.git] / hw / core / gpio.c
blob80d07a6ec99ade02cbf69ed4b2f691e04eef03d7
1 /*
2 * qdev GPIO helpers
4 * Copyright (c) 2009 CodeSourcery
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.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "hw/qdev-core.h"
22 #include "hw/irq.h"
23 #include "qapi/error.h"
25 static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
26 const char *name)
28 NamedGPIOList *ngl;
30 QLIST_FOREACH(ngl, &dev->gpios, node) {
31 /* NULL is a valid and matchable name. */
32 if (g_strcmp0(name, ngl->name) == 0) {
33 return ngl;
37 ngl = g_malloc0(sizeof(*ngl));
38 ngl->name = g_strdup(name);
39 QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
40 return ngl;
43 void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
44 qemu_irq_handler handler,
45 void *opaque,
46 const char *name, int n)
48 int i;
49 NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
51 assert(gpio_list->num_out == 0 || !name);
52 gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
53 opaque, n);
55 if (!name) {
56 name = "unnamed-gpio-in";
58 for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
59 gchar *propname = g_strdup_printf("%s[%u]", name, i);
61 object_property_add_child(OBJECT(dev), propname,
62 OBJECT(gpio_list->in[i]));
63 g_free(propname);
66 gpio_list->num_in += n;
69 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
71 qdev_init_gpio_in_named(dev, handler, NULL, n);
74 void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
75 const char *name, int n)
77 int i;
78 NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
80 assert(gpio_list->num_in == 0 || !name);
82 if (!name) {
83 name = "unnamed-gpio-out";
85 memset(pins, 0, sizeof(*pins) * n);
86 for (i = 0; i < n; ++i) {
87 gchar *propname = g_strdup_printf("%s[%u]", name,
88 gpio_list->num_out + i);
90 object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
91 (Object **)&pins[i],
92 object_property_allow_set_link,
93 OBJ_PROP_LINK_STRONG);
94 g_free(propname);
96 gpio_list->num_out += n;
99 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
101 qdev_init_gpio_out_named(dev, pins, NULL, n);
104 qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
106 NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
108 assert(n >= 0 && n < gpio_list->num_in);
109 return gpio_list->in[n];
112 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
114 return qdev_get_gpio_in_named(dev, NULL, n);
117 void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
118 qemu_irq input_pin)
120 char *propname = g_strdup_printf("%s[%d]",
121 name ? name : "unnamed-gpio-out", n);
122 if (input_pin && !OBJECT(input_pin)->parent) {
123 /* We need a name for object_property_set_link to work */
124 object_property_add_child(container_get(qdev_get_machine(),
125 "/unattached"),
126 "non-qdev-gpio[*]", OBJECT(input_pin));
128 object_property_set_link(OBJECT(dev), propname,
129 OBJECT(input_pin), &error_abort);
130 g_free(propname);
133 qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
135 g_autofree char *propname = g_strdup_printf("%s[%d]",
136 name ? name : "unnamed-gpio-out", n);
138 qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
139 NULL);
141 return ret;
144 /* disconnect a GPIO output, returning the disconnected input (if any) */
146 static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
147 const char *name, int n)
149 char *propname = g_strdup_printf("%s[%d]",
150 name ? name : "unnamed-gpio-out", n);
152 qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
153 NULL);
154 if (ret) {
155 object_property_set_link(OBJECT(dev), propname, NULL, NULL);
157 g_free(propname);
158 return ret;
161 qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
162 const char *name, int n)
164 qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n);
165 qdev_connect_gpio_out_named(dev, name, n, icpt);
166 return disconnected;
169 void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
171 qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
174 void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
175 const char *name)
177 int i;
178 NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
180 for (i = 0; i < ngl->num_in; i++) {
181 const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in";
182 char *propname = g_strdup_printf("%s[%d]", nm, i);
184 object_property_add_alias(OBJECT(container), propname,
185 OBJECT(dev), propname);
186 g_free(propname);
188 for (i = 0; i < ngl->num_out; i++) {
189 const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
190 char *propname = g_strdup_printf("%s[%d]", nm, i);
192 object_property_add_alias(OBJECT(container), propname,
193 OBJECT(dev), propname);
194 g_free(propname);
196 QLIST_REMOVE(ngl, node);
197 QLIST_INSERT_HEAD(&container->gpios, ngl, node);