gpio.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. #include "qemu/osdep.h"
  20. #include "hw/qdev-core.h"
  21. #include "hw/irq.h"
  22. #include "qapi/error.h"
  23. static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
  24. const char *name)
  25. {
  26. NamedGPIOList *ngl;
  27. QLIST_FOREACH(ngl, &dev->gpios, node) {
  28. /* NULL is a valid and matchable name. */
  29. if (g_strcmp0(name, ngl->name) == 0) {
  30. return ngl;
  31. }
  32. }
  33. ngl = g_malloc0(sizeof(*ngl));
  34. ngl->name = g_strdup(name);
  35. QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
  36. return ngl;
  37. }
  38. void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
  39. qemu_irq_handler handler,
  40. void *opaque,
  41. const char *name, int n)
  42. {
  43. int i;
  44. NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
  45. assert(gpio_list->num_out == 0 || !name);
  46. gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
  47. opaque, n);
  48. if (!name) {
  49. name = "unnamed-gpio-in";
  50. }
  51. for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
  52. gchar *propname = g_strdup_printf("%s[%u]", name, i);
  53. object_property_add_child(OBJECT(dev), propname,
  54. OBJECT(gpio_list->in[i]));
  55. g_free(propname);
  56. }
  57. gpio_list->num_in += n;
  58. }
  59. void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
  60. {
  61. qdev_init_gpio_in_named(dev, handler, NULL, n);
  62. }
  63. void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
  64. const char *name, int n)
  65. {
  66. int i;
  67. NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
  68. assert(gpio_list->num_in == 0 || !name);
  69. if (!name) {
  70. name = "unnamed-gpio-out";
  71. }
  72. memset(pins, 0, sizeof(*pins) * n);
  73. for (i = 0; i < n; ++i) {
  74. gchar *propname = g_strdup_printf("%s[%u]", name,
  75. gpio_list->num_out + i);
  76. object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
  77. (Object **)&pins[i],
  78. object_property_allow_set_link,
  79. OBJ_PROP_LINK_STRONG);
  80. g_free(propname);
  81. }
  82. gpio_list->num_out += n;
  83. }
  84. void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
  85. {
  86. qdev_init_gpio_out_named(dev, pins, NULL, n);
  87. }
  88. qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
  89. {
  90. NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
  91. assert(n >= 0 && n < gpio_list->num_in);
  92. return gpio_list->in[n];
  93. }
  94. qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
  95. {
  96. return qdev_get_gpio_in_named(dev, NULL, n);
  97. }
  98. void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
  99. qemu_irq input_pin)
  100. {
  101. char *propname = g_strdup_printf("%s[%d]",
  102. name ? name : "unnamed-gpio-out", n);
  103. if (input_pin && !OBJECT(input_pin)->parent) {
  104. /* We need a name for object_property_set_link to work */
  105. object_property_add_child(container_get(qdev_get_machine(),
  106. "/unattached"),
  107. "non-qdev-gpio[*]", OBJECT(input_pin));
  108. }
  109. object_property_set_link(OBJECT(dev), propname,
  110. OBJECT(input_pin), &error_abort);
  111. g_free(propname);
  112. }
  113. qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
  114. {
  115. g_autofree char *propname = g_strdup_printf("%s[%d]",
  116. name ? name : "unnamed-gpio-out", n);
  117. qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
  118. NULL);
  119. return ret;
  120. }
  121. /* disconnect a GPIO output, returning the disconnected input (if any) */
  122. static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
  123. const char *name, int n)
  124. {
  125. char *propname = g_strdup_printf("%s[%d]",
  126. name ? name : "unnamed-gpio-out", n);
  127. qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
  128. NULL);
  129. if (ret) {
  130. object_property_set_link(OBJECT(dev), propname, NULL, NULL);
  131. }
  132. g_free(propname);
  133. return ret;
  134. }
  135. qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
  136. const char *name, int n)
  137. {
  138. qemu_irq disconnected = qdev_disconnect_gpio_out_named(dev, name, n);
  139. qdev_connect_gpio_out_named(dev, name, n, icpt);
  140. return disconnected;
  141. }
  142. void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
  143. {
  144. qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
  145. }
  146. void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
  147. const char *name)
  148. {
  149. int i;
  150. NamedGPIOList *ngl = qdev_get_named_gpio_list(dev, name);
  151. for (i = 0; i < ngl->num_in; i++) {
  152. const char *nm = ngl->name ? ngl->name : "unnamed-gpio-in";
  153. char *propname = g_strdup_printf("%s[%d]", nm, i);
  154. object_property_add_alias(OBJECT(container), propname,
  155. OBJECT(dev), propname);
  156. g_free(propname);
  157. }
  158. for (i = 0; i < ngl->num_out; i++) {
  159. const char *nm = ngl->name ? ngl->name : "unnamed-gpio-out";
  160. char *propname = g_strdup_printf("%s[%d]", nm, i);
  161. object_property_add_alias(OBJECT(container), propname,
  162. OBJECT(dev), propname);
  163. g_free(propname);
  164. }
  165. QLIST_REMOVE(ngl, node);
  166. QLIST_INSERT_HEAD(&container->gpios, ngl, node);
  167. }