From patchwork Fri Nov 27 18:29:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Enrico Weigelt, metux IT consult" X-Patchwork-Id: 1407380 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=metux.net Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CjPFs0n8Lz9sSf for ; Sat, 28 Nov 2020 06:05:03 +1100 (AEDT) Received: from localhost ([::1]:53172 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kij3D-0004SE-DS for incoming@patchwork.ozlabs.org; Fri, 27 Nov 2020 14:04:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:43640) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUn-0007KP-6l for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:25 -0500 Received: from mout.kundenserver.de ([217.72.192.75]:36129) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUl-00073c-BC for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:24 -0500 Received: from orion.localdomain ([95.114.158.11]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MI4gb-1kxL4L0Dnb-00FG2i; Fri, 27 Nov 2020 19:29:18 +0100 From: "Enrico Weigelt, metux IT consult" To: mst@redhat.com, ehabkost@redhat.com, crosa@redhat.com, qemu-devel@nongnu.org Subject: [PATCH 1/5] scripts: minikconf: support config titles Date: Fri, 27 Nov 2020 19:29:13 +0100 Message-Id: <20201127182917.2387-1-info@metux.net> X-Mailer: git-send-email 2.11.0 X-Provags-ID: V03:K1:OuaTerzzvNagYuqlNfw7vkn8/kL6ypSN/V9m8rxluxhjbMVDcS2 sJDwjYexfdGgP/sQCin4k7BDk1yl3uSAvIxkVWptVm5KfPBZyTfXSo9DXbQMv3kllGf26mW nu0NegApLoPsK7a3e9gZedSjruO5XnvKnHTnqR5TRq7k6gwg4fZLoyVeV1rCX38l/TNYO9U 7A3Djdb8IHew89q3yQoYA== X-UI-Out-Filterresults: notjunk:1;V03:K0:3jbbhP5G9xU=:c4QcDBdJmctPXN8CJUVHEV 0SrxIqyhb7fI7AnEupPrNtZQiW0GC9oG6otqigqe+DfHKCJ8R92CKuYp9Gh6s1MPuqDW1wRgR eQ/eiJYBc97ZHvR5oHhEMX8wpHrb8A5IynUQt9d/MdUU1N58JyA73eKhjDbNx/QHTyHSEeaKr QJr5W4TRn8B/WNEaMBAaR6cgGwWvtJLX+FqH8fbHU48X6w9tL/9wHTzwEkW26ukaWz8dfRQ/s EgKXfmpG+eVb6gpg0Iw+3hjFIlZQ7Lz9yv22phZO/mR6oaghoN0nSpTQMFm+75DedknXPRXaa +/PqRMj0vbMv3+kPcpC6X4BJpGal3/KXAU374QI0d72WZK09YsVFa5jx3faiIHJkFASq5qOoh DtjdXvMWdkAirug5McvZjsvtUCKN98Pe2VevBSMHU4xhdZqez0FGgvkDMzMFC Received-SPF: none client-ip=217.72.192.75; envelope-from=info@metux.net; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 27 Nov 2020 14:04:07 -0500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "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 --- 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] == '_': From patchwork Fri Nov 27 18:29:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Enrico Weigelt, metux IT consult" X-Patchwork-Id: 1407383 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=metux.net Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CjPFv1pvjz9sSn for ; Sat, 28 Nov 2020 06:05:07 +1100 (AEDT) Received: from localhost ([::1]:53224 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kij3J-0004U9-3E for incoming@patchwork.ozlabs.org; Fri, 27 Nov 2020 14:05:05 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:43688) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUp-0007M1-3a for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:27 -0500 Received: from mout.kundenserver.de ([217.72.192.75]:48475) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUl-00073L-Ej for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:26 -0500 Received: from orion.localdomain ([95.114.158.11]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.183]) with ESMTPSA (Nemesis) id 1Mo7if-1kPOMP1XPn-00pgGC; Fri, 27 Nov 2020 19:29:18 +0100 From: "Enrico Weigelt, metux IT consult" To: mst@redhat.com, ehabkost@redhat.com, crosa@redhat.com, qemu-devel@nongnu.org Subject: [PATCH 2/5] backends: introduce gpio backend subsystem Date: Fri, 27 Nov 2020 19:29:14 +0100 Message-Id: <20201127182917.2387-2-info@metux.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20201127182917.2387-1-info@metux.net> References: <20201127182917.2387-1-info@metux.net> X-Provags-ID: V03:K1:lAlJbKOOCZ2db15vXILeB3yZyDFHii5jiefS1F62Mtx4TR0TAxU WUXQ8rc9Muom7+2HoCljKU26LoYwMi96R4L460C9vzCkDkCLK8PFTqWlF5qJvqxZ49VPIY6 AtSDBsp38rMSXHtjhCWKTmBoMRqa7f5jvz6CXYhKyMhi4TkHmr+ndWUI+JC62oqPa2At3/r UXPgWZjGV3zaTQpqZY6wQ== X-UI-Out-Filterresults: notjunk:1;V03:K0://nGqypOBSs=:PycHBQgrkjcXi2Qxxl9/bj /tiEMaEKMyvmAoa4H1Gk/k/GKhDc6b+l6GMcj+07j/aH/Cmo1w/E3qNFT8L5uyvgIqGt0fd0v 8LCoGF604DNPIK2jsUhwgkAhmpEOTTNwWuPCJpV7/L2rbx3bslgC0Qji7LOeNybffTK9lsodL tNm/fP2jIt342E6MDJI5KTs58UP4/SwYTcDMSfqWpWFhb8aPzbWkPHt2jeH99ZKtFnuAoPyTT qL+iuN+6qicvTTezbya8vThgydtpOCtgpB4ZwdYQmd6Mvt7UgKjlpKKkzvycNwqHrA9x3GE9d A++xuLg8VkYenUcaBpKRwtVT4fI2xukuL+F306CufqSmj2OLIurcbbhXmoI/HMCLhcrxREC5x ywAzF27C6Xup+S3k9cV0vyGmBC9cU1Jd/v3f53/SC2d4q9EN6CphaSAfoz1yg Received-SPF: none client-ip=217.72.192.75; envelope-from=info@metux.net; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 27 Nov 2020 14:04:07 -0500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "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 --- 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 +S: Supported +F: backends/gpio.c +F: include/sysemu/gpio.h + Memory API M: Paolo Bonzini 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 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#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 + * + * 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 */ From patchwork Fri Nov 27 18:29:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Enrico Weigelt, metux IT consult" X-Patchwork-Id: 1407381 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=metux.net Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CjPFs2N4gz9sSn for ; Sat, 28 Nov 2020 06:05:05 +1100 (AEDT) Received: from localhost ([::1]:53190 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kij3H-0004T1-87 for incoming@patchwork.ozlabs.org; Fri, 27 Nov 2020 14:05:03 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:43642) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUn-0007KV-EE for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:25 -0500 Received: from mout.kundenserver.de ([217.72.192.73]:51291) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUl-00073i-Dc for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:25 -0500 Received: from orion.localdomain ([95.114.158.11]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MFL8J-1kxtpf2qtd-00FnTi; Fri, 27 Nov 2020 19:29:18 +0100 From: "Enrico Weigelt, metux IT consult" To: mst@redhat.com, ehabkost@redhat.com, crosa@redhat.com, qemu-devel@nongnu.org Subject: [PATCH 3/5] backends: gpio: dummy builtin backend Date: Fri, 27 Nov 2020 19:29:15 +0100 Message-Id: <20201127182917.2387-3-info@metux.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20201127182917.2387-1-info@metux.net> References: <20201127182917.2387-1-info@metux.net> X-Provags-ID: V03:K1:IqH5M+EEtNsD5+wLkNcbaGHTddTKpYFrNlqKUcU+BzMqo1pGsmI kBvNdW7cLsKpyH4IejrSBKVAlqBrudKjZSoRTUf+CxpHfClcFWbhBS3qUj3d1pOUcAgU2Ao Ei+FVEKJKYS3mwSltZ7u+T9mCq6UYCyus5LJ/muttr6vQbwmCVoqJSaEPMljsJNBCm6/ZZG sWPmoIUhQtMNCWo4lXncw== X-UI-Out-Filterresults: notjunk:1;V03:K0:kKrjzB1mbY4=:zPsb4KLaYhsc8Ll6FTO5tN oo2EdLro8AP3Jpm6evmKC/B/l3u/Wty2E3ZRnge+TfA00qSQdpKip3WdL4lb4YUA7QTvjH1+V 9a1gqr1oBXVZw0zqqSb8VNJ1jydZDBQ3t4+/WDvXKgnwNKR6P4rEZ2uqKVehLHPd9ySxv5eHV AKDjgjD9IXqLxBSmubL/8sp/o9yYIVQChlze99heqmAANxkqwYWCOMLPDrtDr0scPE6UgUnnI vrkZsyWOcC3DeWkYvGrNF44aR2LJq0GELHSu2eBb/qjlLZtPpG8EuM9PaieC+jVaSzzvfngrk nK6SptSHQbnRSf7BazV9fd2rgRfWvh9ACgv7Wq72hSomiZsmzQoDzk8blZaq7wn0v5M70hV0f p098jLaVmQoUL+Dz33iJA1es9azkI7vWVJ/zLXZegI02ThVD9n+6Z/whkYSPq Received-SPF: none client-ip=217.72.192.73; envelope-from=info@metux.net; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 27 Nov 2020 14:04:07 -0500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "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 --- 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 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 + * + * 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 From patchwork Fri Nov 27 18:29:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Enrico Weigelt, metux IT consult" X-Patchwork-Id: 1407388 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=metux.net Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CjPK00ZYGz9sSf for ; Sat, 28 Nov 2020 06:07:48 +1100 (AEDT) Received: from localhost ([::1]:33440 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kij5u-0008BL-2X for incoming@patchwork.ozlabs.org; Fri, 27 Nov 2020 14:07:46 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:43686) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUo-0007Lt-Lf for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:26 -0500 Received: from mout.kundenserver.de ([212.227.17.13]:56909) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUm-00073k-4E for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:26 -0500 Received: from orion.localdomain ([95.114.158.11]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MCJvA-1ks6Pd030M-009Sc9; Fri, 27 Nov 2020 19:29:19 +0100 From: "Enrico Weigelt, metux IT consult" To: mst@redhat.com, ehabkost@redhat.com, crosa@redhat.com, qemu-devel@nongnu.org Subject: [PATCH 4/5] standard-headers: virtio-gpio protocol headers Date: Fri, 27 Nov 2020 19:29:16 +0100 Message-Id: <20201127182917.2387-4-info@metux.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20201127182917.2387-1-info@metux.net> References: <20201127182917.2387-1-info@metux.net> X-Provags-ID: V03:K1:vHz07pv+Uh+Gimj7PM+ycUO4NFOapbDFnrlbSvbR4di0v0erYTj qMtJssvvNaHqDk1B5rC2KtcffNmb++ZG0gUN4t3lPQNK61ck9HmZFL+k8rUJZUt3MSPHQsf 67RzgGd6lrElmBu7sXLkM6jrM6qeYF+KULYMJP+y+0WTvoPoDHkCNSIvGWuPY6q+28X/HMu E+2DyJsqo9kkQ/TB5yfGg== X-UI-Out-Filterresults: notjunk:1;V03:K0:nyu3MaZgHN0=:3OX9tsvDglg/Wflk4h4akp uu6rDNhcqfqleHaxoLW2LRkab4mnMht8rfRfkus0sNRKbIe0yLPGfCFimqU3KEWbe0Enbyzae 4Ud3paTozO+hdz1HbHTUo1XeyiqwBYZAHMxOEOfL9MDS/PkRHv7Sx17Y+EGr5OvTvWPYFyXBi ELGYihWDbG8fgvR1JFz6pXaB2y6GN7vi0rZ517elyhZze7tEf8u5vbcTFt2KEyiVnl31qszO1 tPRr7WCfdBpE5tYVabnNpSeLifkjvrNHyFtBX9noCw+4UCvOFwWC/cr8X8yH9XYxG86SRP+5y B4NBMubAUozf0kaajZvyYKNirFGPzOiOBUTYtIZkVTjWjCnuLQX+HyPVPaX5+dcc6a0nINX1d cIwh1t4KdanhN4VLHVvLepdajNOs1L/aX3Cq5Wd4u+ZFjnV+5zkx1u45RPZI5 Received-SPF: none client-ip=212.227.17.13; envelope-from=info@metux.net; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 27 Nov 2020 14:04:07 -0500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Introduce virtio-gpio protocol headers from Linux kernel. (work in progress, not mainlined yet) Signed-off-by: Enrico Weigelt, metux IT consult --- 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 + +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 */ From patchwork Fri Nov 27 18:29:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Enrico Weigelt, metux IT consult" X-Patchwork-Id: 1407387 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=metux.net Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CjPJz4JQzz9s0b for ; Sat, 28 Nov 2020 06:07:46 +1100 (AEDT) Received: from localhost ([::1]:33178 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kij5s-00084p-J1 for incoming@patchwork.ozlabs.org; Fri, 27 Nov 2020 14:07:44 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:43722) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUq-0007MT-H5 for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:28 -0500 Received: from mout.kundenserver.de ([212.227.17.10]:44779) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kiiUm-00073o-GE for qemu-devel@nongnu.org; Fri, 27 Nov 2020 13:29:28 -0500 Received: from orion.localdomain ([95.114.158.11]) by mrelayeu.kundenserver.de (mreue106 [212.227.15.183]) with ESMTPSA (Nemesis) id 1N1gWU-1k31zb1Py4-011yBD; Fri, 27 Nov 2020 19:29:19 +0100 From: "Enrico Weigelt, metux IT consult" To: mst@redhat.com, ehabkost@redhat.com, crosa@redhat.com, qemu-devel@nongnu.org Subject: [PATCH 5/5] hw: virtio: add virtio-gpio device emulation Date: Fri, 27 Nov 2020 19:29:17 +0100 Message-Id: <20201127182917.2387-5-info@metux.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20201127182917.2387-1-info@metux.net> References: <20201127182917.2387-1-info@metux.net> X-Provags-ID: V03:K1:9x4tkuVzY43cF0yp4TsSBiASpypzeVIeOXuhx740vFj1QgkWugo wDOyr2OeOaF8R77Sv9d1DZ8+HMBumB/wC7T/bXtrtz/Jnr8p5zWQqbaE8rNBp6d2uteo9Sq DCV1xuos0oCKvVWcN0k+5PVegIUTd5nQJIimwx91uq7xkoFRV85go/CTFd1OcNm9rOpNolT e3wPYScE+9LszwA7s37cg== X-UI-Out-Filterresults: notjunk:1;V03:K0:w1bg3a21rj0=:nw/MkXZyfR2bUZHUIaczXH 4qwE5sBu+YQKO4NX4zRWzLY+GHgZX/qHB9w8IMC8QmGnOWC+SfYwECiTp2sejLWSKPWsxszHz h49tsV9Z+M35ahagqN6+jLPWBqPSMY+bORQ+EYo1LUFCLUEheHTmB0yA9WQNwpuw4R7awtKJ8 9x7kViQemcVxyhsE19GfJ0rSBZZlsc0BXH2LWu+9qY55Zfqpt1oCjUPvsQUQYAkpTUio9jMu6 NlvJgq4GudLoCuSVM04P+RIthR/syaqb10CN4ZgibKA1Hda6UNyWi+XtlKOo1a0VTCo0jUMmM ZheEKJ1WVxoijQovPKzKXeeyD+Ye0RHdQWkITpy+xWG0+YSAvArEkclsSs8T+qSFI7YDhz6m8 kwR9HQd6mZlPsymJgslXZWFIvhreJVIfGDWnzuZCuwRyPGw7VWXbI1dhn/XtA Received-SPF: none client-ip=212.227.17.10; envelope-from=info@metux.net; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 27 Nov 2020 14:04:07 -0500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "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 --- 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 +S: Supported +F: hw/virtio/virtio-gpio.c +F: include/hw/virtio/virtio-gpio.h Memory API M: Paolo Bonzini 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 + * + * 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)