qemu/hw/core/gpio.c
<<
>>
Prefs
   1/*
   2 * qdev GPIO helpers
   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-core.h"
  22#include "hw/irq.h"
  23#include "qapi/error.h"
  24
  25static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
  26                                               const char *name)
  27{
  28    NamedGPIOList *ngl;
  29
  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;
  34        }
  35    }
  36
  37    ngl = g_malloc0(sizeof(*ngl));
  38    ngl->name = g_strdup(name);
  39    QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
  40    return ngl;
  41}
  42
  43void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
  44                                         qemu_irq_handler handler,
  45                                         void *opaque,
  46                                         const char *name, int n)
  47{
  48    int i;
  49    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
  50
  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);
  54
  55    if (!name) {
  56        name = "unnamed-gpio-in";
  57    }
  58    for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
  59        gchar *propname = g_strdup_printf("%s[%u]", name, i);
  60
  61        object_property_add_child(OBJECT(dev), propname,
  62                                  OBJECT(gpio_list->in[i]));
  63        g_free(propname);
  64    }
  65
  66    gpio_list->num_in += n;
  67}
  68
  69void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
  70{
  71    qdev_init_gpio_in_named(dev, handler, NULL, n);
  72}
  73
  74void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
  75                              const char *name, int n)
  76{
  77    int i;
  78    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
  79
  80    assert(gpio_list->num_in == 0 || !name);
  81
  82    if (!name) {
  83        name = "unnamed-gpio-out";
  84    }
  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);
  89
  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);
  95    }
  96    gpio_list->num_out += n;
  97}
  98
  99void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
 100{
 101    qdev_init_gpio_out_named(dev, pins, NULL, n);
 102}
 103
 104qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
 105{
 106    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
 107
 108    assert(n >= 0 && n < gpio_list->num_in);
 109    return gpio_list->in[n];
 110}
 111
 112qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
 113{
 114    return qdev_get_gpio_in_named(dev, NULL, n);
 115}
 116
 117void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
 118                                 qemu_irq input_pin)
 119{
 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));
 127    }
 128    object_property_set_link(OBJECT(dev), propname,
 129                             OBJECT(input_pin), &error_abort);
 130    g_free(propname);
 131}
 132
 133qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
 134{
 135    g_autofree char *propname = g_strdup_printf("%s[%d]",
 136                                     name ? name : "unnamed-gpio-out", n);
 137
 138    qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
 139                                                      NULL);
 140
 141    return ret;
 142}
 143
 144/* disconnect a GPIO output, returning the disconnected input (if any) */
 145
 146static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
 147                                               const char *name, int n)
 148{
 149    char *propname = g_strdup_printf("%s[%d]",
 150                                     name ? name : "unnamed-gpio-out", n);
 151
 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);
 156    }
 157    g_free(propname);
 158    return ret;
 159}
 160
 161qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
 162                                 const char *name, int n)
 163{
 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;
 167}
 168
 169void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
 170{
 171    qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
 172}
 173
 174void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
 175                     const char *name)
 176{
 177    int i;
 178    NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
 179
 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);
 183
 184        object_property_add_alias(OBJECT(container), propname,
 185                                  OBJECT(dev), propname);
 186        g_free(propname);
 187    }
 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);
 191
 192        object_property_add_alias(OBJECT(container), propname,
 193                                  OBJECT(dev), propname);
 194        g_free(propname);
 195    }
 196    QLIST_REMOVE(ngl, node);
 197    QLIST_INSERT_HEAD(&container->gpios, ngl, node);
 198}
 199