qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

gpio.c (6586B)


      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 
     25 static 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 
     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)
     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 
     69 void 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 
     74 void 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 
     99 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
    100 {
    101     qdev_init_gpio_out_named(dev, pins, NULL, n);
    102 }
    103 
    104 qemu_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 
    112 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
    113 {
    114     return qdev_get_gpio_in_named(dev, NULL, n);
    115 }
    116 
    117 void 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 
    133 qemu_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 
    146 static 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 
    161 qemu_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 
    169 void 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 
    174 void 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 }