Adding a dummy GPIO backend driver. Essentially stores the states in memory and gives some debug output. The current state can be accessed as a string property.
Signed-off-by: Enrico Weigelt, metux IT consult <i...@metux.net> --- MAINTAINERS | 1 + backends/Kconfig | 5 ++ backends/gpio-builtin.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ backends/meson.build | 1 + include/sysemu/gpio.h | 2 + 5 files changed, 146 insertions(+) create mode 100644 backends/gpio-builtin.c diff --git a/MAINTAINERS b/MAINTAINERS index bfa29a4560..d3873121e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2292,6 +2292,7 @@ GPIO Backend API M: Enrico Weigelt, metux IT consult <i...@metux.net> S: Supported F: backends/gpio.c +F: backends/gpio-builtin.c F: include/sysemu/gpio.h Memory API diff --git a/backends/Kconfig b/backends/Kconfig index 2f17189472..1c8a462b57 100644 --- a/backends/Kconfig +++ b/backends/Kconfig @@ -3,3 +3,8 @@ source tpm/Kconfig config BACKEND_GPIO bool "Enable GPIO backends" default y + +config BACKEND_GPIO_BUILTIN + bool "Dummy GPIO backend" + depends on BACKEND_GPIO + default y diff --git a/backends/gpio-builtin.c b/backends/gpio-builtin.c new file mode 100644 index 0000000000..ac89a88092 --- /dev/null +++ b/backends/gpio-builtin.c @@ -0,0 +1,137 @@ +/* + * QEMU GPIO Backend - builtin (dummy) + * + * Copyright 2020 Enrico Weigelt, metux IT consult <i...@metux.net> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "sysemu/gpio.h" +#include "qemu/main-loop.h" +#include "qemu/guest-random.h" +#include "qom/object.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" + +#define MAX_GPIO 256 + +#define WARN(...) warn_report("gpio-builtin: " __VA_ARGS__) + +#define OP_HEAD(name) \ + GpioBuiltin *gpio = GPIO_BUILTIN(obj); \ + if (id >= gpio->num_gpio) { \ + WARN("%s: gpio id %d out of range", name, id); \ + return -ERANGE; \ + } + +#define FLAG_DIRECTION_INPUT 1 +#define FLAG_LINE_ACTIVE 2 + +OBJECT_DECLARE_SIMPLE_TYPE(GpioBuiltin, GPIO_BUILTIN) + +struct GpioBuiltin { + GpioBackend parent; + char *states; + int num_gpio; +}; + +static int gpio_builtin_request(GpioBackend *obj, int id) +{ + OP_HEAD("request"); + return 0; +} + +static int gpio_builtin_set_value(GpioBackend *obj, int id, int state) +{ + OP_HEAD("set"); + if (state & QEMU_GPIO_LINE_ACTIVE) { + gpio->states[id] |= FLAG_LINE_ACTIVE; + } else { + gpio->states[id] &= ~FLAG_LINE_ACTIVE; + } + return 0; +} + +static int gpio_builtin_direction_input(GpioBackend *obj, int id) +{ + OP_HEAD("direction-input"); + gpio->states[id] |= FLAG_DIRECTION_INPUT; + return gpio_builtin_set_value(obj, id, 0); +} + +static int gpio_builtin_direction_output(GpioBackend *obj, int id, int state) +{ + OP_HEAD("direction-output"); + gpio->states[id] &= ~FLAG_DIRECTION_INPUT; + return gpio_builtin_set_value(obj, id, state); +} + +static int gpio_builtin_get_direction(GpioBackend *obj, int id) +{ + OP_HEAD("get-direction"); + return (gpio->states[id] & FLAG_DIRECTION_INPUT ? + QEMU_GPIO_DIRECTION_INPUT : QEMU_GPIO_DIRECTION_OUTPUT); +} + +static int gpio_builtin_get_value(GpioBackend *obj, int id) +{ + OP_HEAD("get"); + return (gpio->states[id] & FLAG_LINE_ACTIVE ? + QEMU_GPIO_LINE_ACTIVE : QEMU_GPIO_LINE_INACTIVE); +} + +static void gpio_builtin_instance_init(Object *obj) +{ + GpioBuiltin *gpio = GPIO_BUILTIN(obj); + + gpio->num_gpio = MAX_GPIO; + gpio->states = g_malloc(gpio->num_gpio + 1); + memset(gpio->states, 'i', gpio->num_gpio); + gpio->states[gpio->num_gpio] = 0; + gpio_backend_register(&gpio->parent); +} + +static void gpio_builtin_instance_finalize(Object *obj) +{ + GpioBuiltin *gpio = GPIO_BUILTIN(obj); + gpio_backend_unregister(&gpio->parent); + g_free(gpio->states); +} + +static int gpio_builtin_get_ngpio(GpioBackend *obj) +{ + GpioBuiltin *gpio = GPIO_BUILTIN(obj); + return gpio->num_gpio; +} + +static void gpio_builtin_class_init(ObjectClass *klass, void *data) +{ + GpioBackendClass *gpio = GPIO_BACKEND_CLASS(klass); + + gpio->name = g_strdup("gpio-builtin"); + gpio->get_value = gpio_builtin_get_value; + gpio->set_value = gpio_builtin_set_value; + gpio->get_direction = gpio_builtin_get_direction; + gpio->direction_input = gpio_builtin_direction_input; + gpio->direction_output = gpio_builtin_direction_output; + gpio->request = gpio_builtin_request; + gpio->get_ngpio = gpio_builtin_get_ngpio; +} + +static const TypeInfo gpio_builtin_info = { + .name = TYPE_GPIO_BUILTIN, + .parent = TYPE_GPIO_BACKEND, + .instance_size = sizeof(GpioBuiltin), + .instance_init = gpio_builtin_instance_init, + .instance_finalize = gpio_builtin_instance_finalize, + .class_init = gpio_builtin_class_init, +}; + +static void register_types(void) +{ + type_register_static(&gpio_builtin_info); +} + +type_init(register_types); diff --git a/backends/meson.build b/backends/meson.build index 332ad7379a..efba675fa7 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -16,5 +16,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c') softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c')) softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio]) softmmu_ss.add(when: 'CONFIG_BACKEND_GPIO', if_true: files('gpio.c')) +softmmu_ss.add(when: 'CONFIG_BACKEND_GPIO_BUILTIN', if_true: files('gpio-builtin.c')) subdir('tpm') diff --git a/include/sysemu/gpio.h b/include/sysemu/gpio.h index 0cfd62b192..374630ee49 100644 --- a/include/sysemu/gpio.h +++ b/include/sysemu/gpio.h @@ -15,6 +15,8 @@ #define TYPE_GPIO_BACKEND "gpio-backend" OBJECT_DECLARE_TYPE(GpioBackend, GpioBackendClass, GPIO_BACKEND) +#define TYPE_GPIO_BUILTIN "gpio-builtin" + /* dont change them - drivers rely on these values */ #define QEMU_GPIO_DIRECTION_OUTPUT 0 #define QEMU_GPIO_DIRECTION_INPUT 1 -- 2.11.0