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#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        /* NULL is a valid and matchable name. */
  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    /* Xilinx: For the FDT Generic GPIO magic we need this to be a wild card
  61     * and not the usual numbered GPIOs.
  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    /* Xilinx: For the FDT Generic GPIO magic we need this to be a wild card
  93     * and not the usual numbered GPIOs.
  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        /* ugly, be a sure-fire way to get a unique name */
 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        /* We need a name for object_property_set_link to work.  If the
 159         * object has a parent, object_property_add_child will come back
 160         * with an error without doing anything.  If it has none, it will
 161         * never fail.  So we can just call it with a NULL Error pointer.
 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/* disconnect a GPIO output, returning the disconnected input (if any) */
 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