qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] scripts: minikconf: support config titles
@ 2020-11-27 18:29 Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 2/5] backends: introduce gpio backend subsystem Enrico Weigelt, metux IT consult
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2020-11-27 18:29 UTC (permalink / raw)
  To: mst, ehabkost, crosa, qemu-devel

Add support for config option titles, like the real kconfig does.
Even though they're not presented anywhere yet (since minikconf
only acts in the background), it's good to have them supported,
so we can start adding descriptions in the Kconfig files.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
---
 scripts/minikconf.py | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/scripts/minikconf.py b/scripts/minikconf.py
index bcd91015d3..28c67906cb 100644
--- a/scripts/minikconf.py
+++ b/scripts/minikconf.py
@@ -206,6 +206,7 @@ class KconfigData:
         self.defined_vars = set()
         self.referenced_vars = dict()
         self.clauses = list()
+        self.title = None
 
     # semantic analysis -------------
 
@@ -290,6 +291,9 @@ class KconfigData:
         cond = (cond & var) if cond is not None else var
         self.clauses.append(KconfigData.SelectClause(symbol, cond))
 
+    def do_title(self, title):
+        self.title = title
+
     def do_imply(self, var, symbol, cond=None):
         # "config X imply Y [if COND]" is the same as
         # "config Y default y if X [&& COND]"
@@ -323,6 +327,7 @@ TOK_BOOL = 15;    TOKENS[TOK_BOOL] = '"bool"';
 TOK_IF = 16;      TOKENS[TOK_IF] = '"if"';
 TOK_ID = 17;      TOKENS[TOK_ID] = 'identifier';
 TOK_EOF = 18;     TOKENS[TOK_EOF] = 'end of file';
+TOK_QUOTED = 19;  TOKENS[TOK_QUOTED] = 'quoted string';
 
 class KconfigParserError(Exception):
     def __init__(self, parser, msg, tok=None):
@@ -501,6 +506,7 @@ class KconfigParser:
     # property: DEFAULT y_or_n condition
     #       | DEPENDS ON expr
     #       | SELECT var condition
+    #       | BOOL "comment"
     #       | BOOL
     def parse_property(self, var):
         if self.tok == TOK_DEFAULT:
@@ -526,6 +532,9 @@ class KconfigParser:
             self.data.do_imply(var, symbol, cond)
         elif self.tok == TOK_BOOL:
             self.get_token()
+            if self.tok == TOK_QUOTED:
+                self.data.do_title(self.val)
+                self.get_token()
         else:
             raise KconfigParserError(self, 'Error in recursive descent?')
 
@@ -645,6 +654,11 @@ class KconfigParser:
             self.cursor = self.src.find('\n', self.cursor)
             self.val = self.src[start:self.cursor]
             return TOK_SOURCE
+        elif self.tok == '"':
+            start = self.cursor
+            self.cursor = self.src.find('"', self.cursor)+1
+            self.val = self.src[start:self.cursor]
+            return TOK_QUOTED;
         elif self.tok.isalnum():
             # identifier
             while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_':
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/5] backends: introduce gpio backend subsystem
  2020-11-27 18:29 [PATCH 1/5] scripts: minikconf: support config titles Enrico Weigelt, metux IT consult
@ 2020-11-27 18:29 ` Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 3/5] backends: gpio: dummy builtin backend Enrico Weigelt, metux IT consult
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2020-11-27 18:29 UTC (permalink / raw)
  To: mst, ehabkost, crosa, qemu-devel

Introducing a backend subsys for hardware GPIOs, so we can now
let simulated GPIO devices actually do something, by talking to
pluggable GPIO backends (eg. speaking to host's gpio subsystem,
gpiod, custom simulation, etc).

This patch does not implement any actual gpio backend, nor any
any any hw simulation drivers yet - just the generic infrastructure.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
---
 MAINTAINERS           |   6 ++
 backends/Kconfig      |   4 +
 backends/gpio.c       | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++
 backends/meson.build  |   1 +
 include/sysemu/gpio.h |  76 +++++++++++++++
 5 files changed, 342 insertions(+)
 create mode 100644 backends/gpio.c
 create mode 100644 include/sysemu/gpio.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 68bc160f41..bfa29a4560 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2288,6 +2288,12 @@ S: Maintained
 F: gdbstub*
 F: gdb-xml/
 
+GPIO Backend API
+M: Enrico Weigelt, metux IT consult <info@metux.net>
+S: Supported
+F: backends/gpio.c
+F: include/sysemu/gpio.h
+
 Memory API
 M: Paolo Bonzini <pbonzini@redhat.com>
 S: Supported
diff --git a/backends/Kconfig b/backends/Kconfig
index f35abc1609..2f17189472 100644
--- a/backends/Kconfig
+++ b/backends/Kconfig
@@ -1 +1,5 @@
 source tpm/Kconfig
+
+config BACKEND_GPIO
+    bool "Enable GPIO backends"
+    default y
diff --git a/backends/gpio.c b/backends/gpio.c
new file mode 100644
index 0000000000..dc539b0791
--- /dev/null
+++ b/backends/gpio.c
@@ -0,0 +1,255 @@
+/*
+ * QEMU GPIO Backend
+ *
+ * Copyright 2020 Enrico Weigelt, metux IT consult <info@metux.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <errno.h>
+#include "qemu/osdep.h"
+#include "sysemu/gpio.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/module.h"
+#include "qom/object_interfaces.h"
+#include "qemu/error-report.h"
+#include "sysemu/gpio.h"
+
+#define GPIO_FORMAT_VALUE       "gpio%d.value"
+#define GPIO_FORMAT_DIRECTION   "gpio%d.direction"
+
+#define BACKEND_OP_HEAD \
+    if (!gpio) \
+        return -EFAULT;
+
+#define BACKEND_CLASSOP_HEAD(op) \
+    GpioBackendClass *klass; \
+    BACKEND_OP_HEAD \
+    klass = GPIO_BACKEND_GET_CLASS(gpio); \
+    if (!klass) \
+        return -EFAULT; \
+    if (!klass->op) \
+        return -EUNATCH;
+
+int gpio_backend_set_notify(GpioBackend *gpio,
+                            gpio_backend_notify_t proc,
+                            void *consumer)
+{
+    BACKEND_OP_HEAD
+
+    gpio->notify_proc = proc;
+    gpio->notify_consumer = consumer;
+
+    return 0;
+}
+
+int gpio_backend_send_notify(GpioBackend *gpio, int pin, int event, int value)
+{
+    BACKEND_OP_HEAD
+
+    if (gpio->notify_proc) {
+        return gpio->notify_proc(gpio->notify_consumer, pin, event, value);
+    }
+
+    return 0;
+}
+
+int gpio_backend_request(GpioBackend *gpio, int pin)
+{
+    BACKEND_CLASSOP_HEAD(request);
+    return klass->request(gpio, pin);
+}
+
+int gpio_backend_set_value(GpioBackend *gpio, int pin, int state)
+{
+    BACKEND_CLASSOP_HEAD(set_value);
+    return klass->set_value(gpio, pin, state);
+}
+
+int gpio_backend_get_value(GpioBackend *gpio, int pin)
+{
+    BACKEND_CLASSOP_HEAD(get_value);
+    return klass->get_value(gpio, pin);
+}
+
+int gpio_backend_direction_output(GpioBackend *gpio, int pin, int state)
+{
+    BACKEND_CLASSOP_HEAD(direction_output);
+    return klass->direction_output(gpio, pin, state);
+}
+
+int gpio_backend_direction_input(GpioBackend *gpio, int pin)
+{
+    BACKEND_CLASSOP_HEAD(direction_input);
+    return klass->direction_input(gpio, pin);
+}
+
+int gpio_backend_get_direction(GpioBackend *gpio, int pin)
+{
+    BACKEND_CLASSOP_HEAD(get_direction);
+    return klass->get_direction(gpio, pin);
+}
+
+int gpio_backend_get_ngpio(GpioBackend *gpio)
+{
+    BACKEND_CLASSOP_HEAD(get_ngpio);
+    return klass->get_ngpio(gpio);
+}
+
+static void getattr_value(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    int pin;
+    int64_t val = 0;
+    GpioBackend *gpio = GPIO_BACKEND(obj);
+
+    if (sscanf(name, GPIO_FORMAT_VALUE, &pin) != 1) {
+        error_setg(errp,
+                  "gpio: getattr_value() illegal property: \"%s\"",
+                   name);
+        return;
+    }
+
+    val = gpio_backend_get_value(gpio, pin);
+    visit_type_int(v, name, &val, errp);
+}
+
+static void setattr_value(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    int pin;
+    int64_t val = 0;
+    GpioBackend *gpio = GPIO_BACKEND(obj);
+
+    if (!visit_type_int(v, name, &val, errp)) {
+        return;
+    }
+
+    if (sscanf(name, GPIO_FORMAT_VALUE, &pin) != 1) {
+        error_setg(errp,
+                   "gpio: setattr_value() illegal property: \"%s\"",
+                   name);
+        return;
+    }
+
+    gpio_backend_set_value(gpio, pin, val);
+    gpio_backend_send_notify(gpio, pin, GPIO_EVENT_LEVEL, val);
+}
+
+static void getattr_direction(Object *obj, Visitor *v, const char *name,
+                              void *opaque, Error **errp)
+{
+    int pin;
+    GpioBackend *gpio = GPIO_BACKEND(obj);
+    char str[16] = { 0 };
+    char *val = str;
+
+    if (sscanf(name, GPIO_FORMAT_DIRECTION, &pin) != 1) {
+        error_setg(errp,
+                   "gpio: getattr_direction() illegal property: \"%s\"",
+                   name);
+        return;
+    }
+
+    strcpy(str, (gpio_backend_get_direction(gpio, pin)
+                    == QEMU_GPIO_DIRECTION_INPUT) ? "in" : "out");
+    visit_type_str(v, name, &val, errp);
+}
+
+static void setattr_direction(Object *obj, Visitor *v, const char *name,
+                              void *opaque, Error **errp)
+{
+    int pin;
+    GpioBackend *gpio = GPIO_BACKEND(obj);
+    char *val;
+
+    if (!visit_type_str(v, name, &val, errp)) {
+        return;
+    }
+
+    if (sscanf(name, GPIO_FORMAT_DIRECTION, &pin) != 1) {
+        error_setg(errp, "gpio: setattr_direction() illegal property: \"%s\"",
+                   name);
+        return;
+    }
+
+    if (strcmp(val, "in") == 0) {
+        gpio_backend_direction_input(gpio, pin);
+        gpio_backend_send_notify(gpio, pin, GPIO_EVENT_INPUT, 0);
+        return;
+    }
+
+    if (strcmp(val, "out") == 0) {
+        gpio_backend_direction_output(gpio, pin, QEMU_GPIO_LINE_INACTIVE);
+        gpio_backend_send_notify(gpio, pin, GPIO_EVENT_OUTPUT, 0);
+        return;
+    }
+
+    error_setg(errp, "gpio: setattr_direction() illegal value: \"%s\"", val);
+    return;
+}
+
+int gpio_backend_register(GpioBackend *gpio)
+{
+    int pin;
+    int ngpio = gpio_backend_get_ngpio(gpio);
+
+    if (ngpio < 1) {
+        error_report("gpio_backend_register() illegal number of gpios: %d",
+                     ngpio);
+        return -EINVAL;
+    }
+
+    for (pin = 0; pin < ngpio; pin++) {
+        char name[64];
+        snprintf(name, sizeof(name), GPIO_FORMAT_VALUE, pin);
+        object_property_add(OBJECT(gpio), name, "bool", getattr_value,
+                            setattr_value, NULL, NULL);
+        snprintf(name, sizeof(name), GPIO_FORMAT_DIRECTION, pin);
+        object_property_add(OBJECT(gpio), name, "string", getattr_direction,
+                            setattr_direction, NULL, NULL);
+    }
+
+    return 0;
+}
+
+int gpio_backend_unregister(GpioBackend *s)
+{
+    /* nothing to do for now */
+    return 0;
+}
+
+static void gpio_backend_init(Object *obj)
+{
+}
+
+static void gpio_backend_finalize(Object *obj)
+{
+}
+
+static void gpio_backend_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static const TypeInfo gpio_backend_info = {
+    .name = TYPE_GPIO_BACKEND,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(GpioBackend),
+    .instance_init = gpio_backend_init,
+    .instance_finalize = gpio_backend_finalize,
+    .class_size = sizeof(GpioBackendClass),
+    .class_init = gpio_backend_class_init,
+    .abstract = true,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_USER_CREATABLE },
+        { }
+    }
+};
+
+static void register_types(void)
+{
+    type_register_static(&gpio_backend_info);
+}
+
+type_init(register_types);
diff --git a/backends/meson.build b/backends/meson.build
index 484456ece7..332ad7379a 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -15,5 +15,6 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vho
 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'))
 
 subdir('tpm')
diff --git a/include/sysemu/gpio.h b/include/sysemu/gpio.h
new file mode 100644
index 0000000000..0cfd62b192
--- /dev/null
+++ b/include/sysemu/gpio.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU GPIO backend
+ *
+ * Copyright 2020 Enrico Weigelt, metux IT consult <info@metux.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_GPIO_H
+#define QEMU_GPIO_H
+
+#include "qemu/queue.h"
+#include "qom/object.h"
+
+#define TYPE_GPIO_BACKEND "gpio-backend"
+OBJECT_DECLARE_TYPE(GpioBackend, GpioBackendClass, GPIO_BACKEND)
+
+/* dont change them - drivers rely on these values */
+#define QEMU_GPIO_DIRECTION_OUTPUT  0
+#define QEMU_GPIO_DIRECTION_INPUT   1
+
+#define QEMU_GPIO_LINE_INACTIVE     0
+#define QEMU_GPIO_LINE_ACTIVE       1
+
+/*
+ * notification callback from gpio backend to consumer/frontend
+ *
+ * consumer:    pointer to/for the consumer object
+ * gpio_id:     id of the gpio (-1 = all at once)
+ * event:       whats happened
+ */
+typedef int (*gpio_backend_notify_t)(void *consumer, int gpio, int event,
+                                     int value);
+
+#define GPIO_EVENT_INPUT  1
+#define GPIO_EVENT_OUTPUT 2
+#define GPIO_EVENT_LEVEL  3
+
+struct GpioBackendClass {
+    ObjectClass parent_class;
+    bool opened;
+
+    char *name;
+
+    int (*request)(GpioBackend *s, int gpio);
+    int (*direction_input)(GpioBackend *s, int gpio);
+    int (*direction_output)(GpioBackend *s, int gpio, int state);
+    int (*get_direction)(GpioBackend *s, int gpio);
+    int (*set_value)(GpioBackend *s, int gpio, int state);
+    int (*get_value)(GpioBackend *s, int gpio);
+    int (*get_ngpio)(GpioBackend *s);
+};
+
+struct GpioBackend {
+    Object parent;
+    gpio_backend_notify_t notify_proc;
+    void *notify_consumer;
+};
+
+/* call wrappers to gpio backend */
+int gpio_backend_request(GpioBackend *s, int gpio);
+int gpio_backend_direction_input(GpioBackend *s, int gpio);
+int gpio_backend_direction_output(GpioBackend *s, int gpio, int state);
+int gpio_backend_get_direction(GpioBackend *s, int gpio);
+int gpio_backend_set_value(GpioBackend *s, int gpio, int state);
+int gpio_backend_get_value(GpioBackend *s, int gpio);
+int gpio_backend_set_notify(GpioBackend *s, gpio_backend_notify_t proc,
+                            void *consumer);
+int gpio_backend_send_notify(GpioBackend *s, int gpio, int event, int value);
+int gpio_backend_get_ngpio(GpioBackend *s);
+
+/* used by backend drivers for common initializations */
+int gpio_backend_register(GpioBackend *s);
+int gpio_backend_unregister(GpioBackend *s);
+
+#endif /* QEMU_GPIO_H */
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/5] backends: gpio: dummy builtin backend
  2020-11-27 18:29 [PATCH 1/5] scripts: minikconf: support config titles Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 2/5] backends: introduce gpio backend subsystem Enrico Weigelt, metux IT consult
@ 2020-11-27 18:29 ` Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 4/5] standard-headers: virtio-gpio protocol headers Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 5/5] hw: virtio: add virtio-gpio device emulation Enrico Weigelt, metux IT consult
  3 siblings, 0 replies; 5+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2020-11-27 18:29 UTC (permalink / raw)
  To: mst, ehabkost, crosa, qemu-devel

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 <info@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 <info@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 <info@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



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/5] standard-headers: virtio-gpio protocol headers
  2020-11-27 18:29 [PATCH 1/5] scripts: minikconf: support config titles Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 2/5] backends: introduce gpio backend subsystem Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 3/5] backends: gpio: dummy builtin backend Enrico Weigelt, metux IT consult
@ 2020-11-27 18:29 ` Enrico Weigelt, metux IT consult
  2020-11-27 18:29 ` [PATCH 5/5] hw: virtio: add virtio-gpio device emulation Enrico Weigelt, metux IT consult
  3 siblings, 0 replies; 5+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2020-11-27 18:29 UTC (permalink / raw)
  To: mst, ehabkost, crosa, qemu-devel

Introduce virtio-gpio protocol headers from Linux kernel.
(work in progress, not mainlined yet)

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
---
 include/standard-headers/linux/virtio_gpio.h | 39 ++++++++++++++++++++++++++++
 include/standard-headers/linux/virtio_ids.h  |  1 +
 2 files changed, 40 insertions(+)
 create mode 100644 include/standard-headers/linux/virtio_gpio.h

diff --git a/include/standard-headers/linux/virtio_gpio.h b/include/standard-headers/linux/virtio_gpio.h
new file mode 100644
index 0000000000..d1db0ef1fe
--- /dev/null
+++ b/include/standard-headers/linux/virtio_gpio.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#ifndef _LINUX_VIRTIO_GPIO_H
+#define _LINUX_VIRTIO_GPIO_H
+
+#include <linux/types.h>
+
+enum virtio_gpio_event_type {
+	// requests from quest to host
+	VIRTIO_GPIO_EV_GUEST_REQUEST		= 0x01,	// ->request()
+	VIRTIO_GPIO_EV_GUEST_DIRECTION_INPUT	= 0x02,	// ->direction_input()
+	VIRTIO_GPIO_EV_GUEST_DIRECTION_OUTPUT	= 0x03,	// ->direction_output()
+	VIRTIO_GPIO_EV_GUEST_GET_DIRECTION	= 0x04,	// ->get_direction()
+	VIRTIO_GPIO_EV_GUEST_GET_VALUE		= 0x05,	// ->get_value()
+	VIRTIO_GPIO_EV_GUEST_SET_VALUE		= 0x06,	// ->set_value()
+
+	// messages from host to guest
+	VIRTIO_GPIO_EV_HOST_LEVEL		= 0x11,	// gpio state changed
+
+	/* mask bit set on host->guest reply */
+	VIRTIO_GPIO_EV_REPLY			= 0xF000,
+};
+
+struct virtio_gpio_config {
+	__u8    version;
+	__u8    reserved0;
+	__u16   num_gpios;
+	__u32   names_size;
+	__u8    reserved1[24];
+	__u8    name[32];
+};
+
+struct virtio_gpio_event {
+	__le16 type;
+	__le16 pin;
+	__le32 value;
+};
+
+#endif /* _LINUX_VIRTIO_GPIO_H */
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index b052355ac7..053fe59c73 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -48,5 +48,6 @@
 #define VIRTIO_ID_FS           26 /* virtio filesystem */
 #define VIRTIO_ID_PMEM         27 /* virtio pmem */
 #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
+#define VIRTIO_ID_GPIO		 30 /* virtio GPIO */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5/5] hw: virtio: add virtio-gpio device emulation
  2020-11-27 18:29 [PATCH 1/5] scripts: minikconf: support config titles Enrico Weigelt, metux IT consult
                   ` (2 preceding siblings ...)
  2020-11-27 18:29 ` [PATCH 4/5] standard-headers: virtio-gpio protocol headers Enrico Weigelt, metux IT consult
@ 2020-11-27 18:29 ` Enrico Weigelt, metux IT consult
  3 siblings, 0 replies; 5+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2020-11-27 18:29 UTC (permalink / raw)
  To: mst, ehabkost, crosa, qemu-devel

Adding a driver for virtio-based GPIOs. The driver connects to
specified gpio backend and routes all requests there.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
---
 MAINTAINERS             |   7 +
 hw/virtio/Kconfig       |   7 +
 hw/virtio/meson.build   |   1 +
 hw/virtio/virtio-gpio.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 386 insertions(+)
 create mode 100644 hw/virtio/virtio-gpio.c

diff --git a/MAINTAINERS b/MAINTAINERS
index d3873121e2..57deed6c20 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2294,6 +2294,13 @@ S: Supported
 F: backends/gpio.c
 F: backends/gpio-builtin.c
 F: include/sysemu/gpio.h
+F: include/standard-headers/linux/virtio_gpio.h
+
+GPIO Virtio backend
+M: Enrico Weigelt, metux IT consult <info@metux.net>
+S: Supported
+F: hw/virtio/virtio-gpio.c
+F: include/hw/virtio/virtio-gpio.h
 
 Memory API
 M: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
index 0eda25c4e1..81da1ee763 100644
--- a/hw/virtio/Kconfig
+++ b/hw/virtio/Kconfig
@@ -33,6 +33,13 @@ config VIRTIO_BALLOON
     default y
     depends on VIRTIO
 
+config VIRTIO_GPIO
+    bool
+    default y
+    depends on VIRTIO
+    select BACKEND_GPIO
+    select BACKEND_GPIO_BUILTIN
+
 config VIRTIO_CRYPTO
     bool
     default y
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index fbff9bc9d4..88577ff812 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -25,6 +25,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.
 virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
 virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c'))
 virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
+virtio_ss.add(when: 'CONFIG_VIRTIO_GPIO', if_true: files('virtio-gpio.c'))
 
 virtio_pci_ss = ss.source_set()
 virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c'))
diff --git a/hw/virtio/virtio-gpio.c b/hw/virtio/virtio-gpio.c
new file mode 100644
index 0000000000..37e7614c96
--- /dev/null
+++ b/hw/virtio/virtio-gpio.c
@@ -0,0 +1,371 @@
+/*
+ * A virtio device implementing a hardware gpio port.
+ *
+ * Copyright 2020 Enrico Weigelt, metux IT consult <info@metux.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/timer.h"
+#include "hw/virtio/virtio.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/gpio.h"
+#include "sysemu/runstate.h"
+#include "qom/object.h"
+#include "qom/object_interfaces.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_gpio.h"
+
+#define WARN(...) warn_report("virtio-gpio: " __VA_ARGS__)
+
+#define TYPE_VIRTIO_GPIO "virtio-gpio-device"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPIO, VIRTIO_GPIO)
+#define VIRTIO_GPIO_GET_PARENT_CLASS(obj) \
+        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_GPIO)
+
+typedef struct VirtIOGPIO VirtIOGPIO;
+
+struct VirtIOGPIO {
+    VirtIODevice parent_obj;
+
+    VirtQueue *vq_in;
+    VirtQueue *vq_out;
+
+    uint32_t num_gpios;
+
+    char **gpio_names;
+    uint32_t gpio_names_len;
+
+    GpioBackend *gpio;
+    char *name;
+
+    VMChangeStateEntry *vmstate;
+    struct virtio_gpio_event reply_buffer;
+
+    void *config_buf;
+    int config_len;
+};
+
+static bool is_guest_ready(VirtIOGPIO *vgpio)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vgpio);
+    if (virtio_queue_ready(vgpio->vq_in)
+        && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return true;
+    }
+    return false;
+}
+
+static void virtio_gpio_reply(VirtIOGPIO *vgpio, int type, int pin, int value)
+{
+    VirtQueueElement *elem;
+    size_t len;
+
+    if (!virtio_queue_ready(vgpio->vq_out)) {
+        WARN("out queue is not ready yet");
+        return;
+    }
+
+    elem = virtqueue_pop(vgpio->vq_out, sizeof(VirtQueueElement));
+    if (!elem) {
+        WARN("failed to get xmit queue element");
+        return;
+    }
+
+    vgpio->reply_buffer.type = type;
+    vgpio->reply_buffer.pin = pin;
+    vgpio->reply_buffer.value = value;
+    len = iov_from_buf(elem->in_sg, elem->in_num, 0, &vgpio->reply_buffer,
+                       sizeof(struct virtio_gpio_event));
+    virtqueue_push(vgpio->vq_out, elem, len);
+    g_free(elem);
+    virtio_notify(VIRTIO_DEVICE(vgpio), vgpio->vq_out);
+}
+
+static int do_request(VirtIOGPIO *vgpio, struct virtio_gpio_event *reqbuf)
+{
+    switch (reqbuf->type) {
+    case VIRTIO_GPIO_EV_GUEST_REQUEST:
+        return gpio_backend_request(vgpio->gpio, reqbuf->pin);
+    case VIRTIO_GPIO_EV_GUEST_DIRECTION_INPUT:
+        return gpio_backend_direction_input(vgpio->gpio, reqbuf->pin);
+    case VIRTIO_GPIO_EV_GUEST_DIRECTION_OUTPUT:
+        return gpio_backend_direction_output(vgpio->gpio, reqbuf->pin,
+                                             reqbuf->value);
+    case VIRTIO_GPIO_EV_GUEST_GET_DIRECTION:
+        return gpio_backend_get_direction(vgpio->gpio, reqbuf->pin);
+    case VIRTIO_GPIO_EV_GUEST_GET_VALUE:
+        return gpio_backend_get_value(vgpio->gpio, reqbuf->pin);
+    case VIRTIO_GPIO_EV_GUEST_SET_VALUE:
+        return gpio_backend_set_value(vgpio->gpio, reqbuf->pin,
+                                      reqbuf->value);
+    }
+    WARN("unknown request type: %d", reqbuf->type);
+    return -EINVAL;
+}
+
+static int virtio_gpio_notify(void *obj, int pin, int event, int value)
+{
+    VirtIOGPIO *vgpio = obj;
+
+    switch (event) {
+    case GPIO_EVENT_LEVEL:
+        virtio_gpio_reply(vgpio, VIRTIO_GPIO_EV_HOST_LEVEL, pin, value);
+    break;
+    case GPIO_EVENT_INPUT:
+    break;
+    case GPIO_EVENT_OUTPUT:
+    break;
+    default:
+        WARN("unhandled notification: pin=%d event=%d value=%d", pin,
+             event, value);
+    break;
+    }
+
+    return 0;
+}
+
+static void virtio_gpio_process(VirtIOGPIO *vgpio)
+{
+    VirtQueueElement *elem;
+
+    if (!is_guest_ready(vgpio)) {
+        return;
+    }
+
+    while ((elem = virtqueue_pop(vgpio->vq_in, sizeof(VirtQueueElement)))) {
+        size_t offset = 0;
+        struct virtio_gpio_event reqbuf;
+        while ((iov_to_buf(elem->out_sg, elem->out_num, offset, &reqbuf,
+                           sizeof(reqbuf))) == sizeof(reqbuf))
+        {
+            offset += sizeof(reqbuf);
+            virtio_gpio_reply(vgpio, reqbuf.type | VIRTIO_GPIO_EV_REPLY,
+                              reqbuf.pin, do_request(vgpio, &reqbuf));
+        }
+        virtqueue_push(vgpio->vq_in, elem, sizeof(reqbuf));
+        virtio_notify(VIRTIO_DEVICE(vgpio), vgpio->vq_in);
+    }
+}
+
+static void virtio_gpio_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPIO *vgpio = VIRTIO_GPIO(vdev);
+    virtio_gpio_process(vgpio);
+}
+
+static uint64_t virtio_gpio_get_features(VirtIODevice *vdev, uint64_t f,
+                                         Error **errp)
+{
+    return f;
+}
+
+static void virtio_gpio_get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOGPIO *vgpio = VIRTIO_GPIO(vdev);
+    memcpy(config_data, vgpio->config_buf, vgpio->config_len);
+}
+
+static void virtio_gpio_vm_state_change(void *opaque, int running,
+                                        RunState state)
+{
+    VirtIOGPIO *vgpio = opaque;
+
+    if (running && is_guest_ready(vgpio)) {
+        virtio_gpio_process(vgpio);
+    }
+}
+
+static void virtio_gpio_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VirtIOGPIO *vgpio = VIRTIO_GPIO(vdev);
+
+    if (!vdev->vm_running) {
+        return;
+    }
+
+    vdev->status = status;
+    virtio_gpio_process(vgpio);
+}
+
+static void virtio_gpio_default_backend(VirtIOGPIO *vgpio, DeviceState* dev,
+                                        Error **errp)
+{
+    Object *b = NULL;
+
+    if (vgpio->gpio != NULL) {
+        return;
+    }
+
+    b = object_new(TYPE_GPIO_BUILTIN);
+
+    if (!user_creatable_complete(USER_CREATABLE(b), errp)) {
+        object_unref(b);
+        return;
+    }
+
+    object_property_add_child(OBJECT(dev), "default-backend", b);
+
+    /* The child property took a reference, we can safely drop ours now */
+    object_unref(b);
+
+    object_property_set_link(OBJECT(dev), "gpio", b, &error_abort);
+}
+
+/* count the string array size */
+static int str_array_size(char **str, int len)
+{
+    int x;
+    int ret = 0;
+    for (x = 0; x < len; x++) {
+        ret += (str[x] ? strlen(str[x]) + 1 : 1);
+    }
+    return ret;
+}
+
+static void virtio_gpio_device_realize(DeviceState *dev, Error **errp)
+{
+    struct virtio_gpio_config *config;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOGPIO *vgpio = VIRTIO_GPIO(dev);
+    int nbuf_len = 0;
+    char *bufptr;
+    int x;
+
+    /* make sure we have a backend */
+    virtio_gpio_default_backend(vgpio, dev, errp);
+
+    /* parameter checking */
+    if (vgpio->gpio == NULL) {
+        error_setg(errp, "'gpio' parameter expects a valid object");
+        return;
+    }
+
+    if ((vgpio->num_gpios < 1) && (vgpio->gpio_names_len > 0)) {
+        vgpio->num_gpios = vgpio->gpio_names_len;
+    }
+
+    if (vgpio->num_gpios < 1) {
+        vgpio->num_gpios = gpio_backend_get_ngpio(vgpio->gpio);
+    }
+
+    if (vgpio->num_gpios < 1) {
+        error_setg(errp,
+                   "'num_gpios' parameter invalid / no setting from backend");
+        return;
+    }
+
+    if (vgpio->gpio_names_len > vgpio->num_gpios) {
+        error_setg(errp, "'num_gpios' parameter less than 'len-gpio-names'");
+        return;
+    }
+
+    /* count required buffer space */
+    if (vgpio->gpio_names) {
+        nbuf_len = str_array_size(vgpio->gpio_names, vgpio->gpio_names_len)
+                 + (vgpio->num_gpios - vgpio->gpio_names_len);
+    } else {
+        nbuf_len = vgpio->num_gpios;
+    }
+
+    vgpio->config_len = sizeof(struct virtio_gpio_config) + nbuf_len;
+    vgpio->config_buf = calloc(1, vgpio->config_len);
+
+    /* fill out our struct */
+    config = vgpio->config_buf;
+    config->version = 1;
+    config->num_gpios = vgpio->num_gpios;
+    config->names_size = nbuf_len;
+    strncpy((char *)&config->name, vgpio->name, sizeof(config->name));
+    config->name[sizeof(config->name) - 1] = 0;
+
+    /* copy the names */
+    bufptr = (char *)(vgpio->config_buf) + sizeof(struct virtio_gpio_config);
+
+    for (x = 0; x < vgpio->gpio_names_len; x++) {
+        if (vgpio->gpio_names[x]) {
+            strcpy(bufptr, vgpio->gpio_names[x]);
+            bufptr += strlen(vgpio->gpio_names[x]) + 1;
+        } else {
+            *bufptr = 0;
+            bufptr++;
+        }
+    }
+
+    memset(&vgpio->reply_buffer, 0, sizeof(struct virtio_gpio_event));
+
+    gpio_backend_set_notify(vgpio->gpio, virtio_gpio_notify, vgpio);
+
+    virtio_init(vdev, "virtio-gpio", VIRTIO_ID_GPIO, vgpio->config_len);
+
+    vgpio->vq_out = virtio_add_queue(vdev, 256, NULL);
+    vgpio->vq_in = virtio_add_queue(vdev, 256, virtio_gpio_handle_rx);
+
+    vgpio->vmstate = qemu_add_vm_change_state_handler(
+                        virtio_gpio_vm_state_change, vgpio);
+}
+
+static void virtio_gpio_device_unrealize(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOGPIO *vgpio = VIRTIO_GPIO(dev);
+
+    qemu_del_vm_change_state_handler(vgpio->vmstate);
+    virtio_del_queue(vdev, 0);
+    virtio_cleanup(vdev);
+}
+
+static const VMStateDescription vmstate_virtio_gpio = {
+    .name = "virtio-gpio",
+    .minimum_version_id = 1,
+    .version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_VIRTIO_DEVICE,
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static Property virtio_gpio_properties[] = {
+    DEFINE_PROP_STRING("name", VirtIOGPIO, name),
+    DEFINE_PROP_UINT32("num-gpios", VirtIOGPIO, num_gpios, 0),
+    DEFINE_PROP_LINK("gpio", VirtIOGPIO, gpio, TYPE_GPIO_BACKEND,
+                     GpioBackend *),
+    DEFINE_PROP_ARRAY("gpio-names", VirtIOGPIO, gpio_names_len, gpio_names,
+                      qdev_prop_string, char*),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, virtio_gpio_properties);
+    dc->vmsd = &vmstate_virtio_gpio;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    vdc->realize = virtio_gpio_device_realize;
+    vdc->unrealize = virtio_gpio_device_unrealize;
+    vdc->get_features = virtio_gpio_get_features;
+    vdc->set_status = virtio_gpio_set_status;
+    vdc->get_config = virtio_gpio_get_config;
+}
+
+static const TypeInfo virtio_gpio_info = {
+    .name = TYPE_VIRTIO_GPIO,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOGPIO),
+    .class_init = virtio_gpio_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_gpio_info);
+}
+
+type_init(virtio_register_types)
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-11-27 19:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-27 18:29 [PATCH 1/5] scripts: minikconf: support config titles Enrico Weigelt, metux IT consult
2020-11-27 18:29 ` [PATCH 2/5] backends: introduce gpio backend subsystem Enrico Weigelt, metux IT consult
2020-11-27 18:29 ` [PATCH 3/5] backends: gpio: dummy builtin backend Enrico Weigelt, metux IT consult
2020-11-27 18:29 ` [PATCH 4/5] standard-headers: virtio-gpio protocol headers Enrico Weigelt, metux IT consult
2020-11-27 18:29 ` [PATCH 5/5] hw: virtio: add virtio-gpio device emulation Enrico Weigelt, metux IT consult

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).