From patchwork Fri May 10 18:04:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ernest Esene X-Patchwork-Id: 10939349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AF0A014B6 for ; Fri, 10 May 2019 18:03:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B90628B2C for ; Fri, 10 May 2019 18:03:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8E27228CBF; Fri, 10 May 2019 18:03:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C0C0828B2C for ; Fri, 10 May 2019 18:03:45 +0000 (UTC) Received: from localhost ([127.0.0.1]:48009 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hP9s0-0001ZX-KF for patchwork-qemu-devel@patchwork.kernel.org; Fri, 10 May 2019 14:03:44 -0400 Received: from eggs.gnu.org ([209.51.188.92]:38114) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hP9rJ-0001GW-90 for qemu-devel@nongnu.org; Fri, 10 May 2019 14:03:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hP9rH-000463-Oe for qemu-devel@nongnu.org; Fri, 10 May 2019 14:03:01 -0400 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:32969) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hP9rH-00044V-E6 for qemu-devel@nongnu.org; Fri, 10 May 2019 14:02:59 -0400 Received: by mail-wr1-x443.google.com with SMTP id d9so494207wrx.0 for ; Fri, 10 May 2019 11:02:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=GD3Q8YZK/ZWAa/bCi1KAoBDy1eZOru2OMD4jJbCs5uo=; b=fdpdx0UqKpgYERqi6rtqnSI8CktjGOfZZfrwed4LzFuWtAvYAHKlLCWKutgxBgSpg9 0IZN0/4qOnEvuLFGUcAdsmWdZGuL9l1gHiNh9cmtNOqZTDbxrR0ZMG9aw0VnBYHvUlSH 9RlTwWdOEh09b5EYh+Sr24xiaEH9KB3yAjtjBomU/lH4BKpNkMiVJXajYVH4WZaeGtgd 6uYNtQWIODEI2S/Q6BaYf+FiY5UXPCL8FqKSuB6h05kwUtgVn3C0GsCcN76EptakJvKz bf3MvGEQ6oY1srEtzfGgxSQ+YaUepXFC3StO9yIxzE9EPmaet5WOT2fWPnXb9ylSoV4Y 0nOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=GD3Q8YZK/ZWAa/bCi1KAoBDy1eZOru2OMD4jJbCs5uo=; b=qZZEnbCUbXU4+KlD7uS3VJ0KVBEoVWxWG72jSg84OxS8/oNYMZHFo0kQ86fCEzJO7r K5H55p1CMXLJ+fb24gE0wWuX4JBAZYb3ry7VzV3hwE7C8nKoCfh9NNlKaOZZG5kd8I8n +/Mwy9VO7rlFqgt+Sc3YibspBitVlkA7d62KKQeWlwLAaVsKzvXobz8m0Y+q5eOQ9o4C YPJc3170MeONt0dr7QGbOgakYSGERVYN88osrdqXdB+G96Iq89ta0dyeT4BkCwm7hHWb r1+ho59YapVDbYbR8bsIjBeVGxzjzvruaG4Sm4lugQGKP7WAMmpk777uc2FmMX4U6g4P NiWA== X-Gm-Message-State: APjAAAXUJseoS0QpURJ9/L+EvRjxB4+r1s+NPncotFhz+nawPntB+mAJ zgIzIiL/rqnW6n5Op+nDEUUBBrrtES3Exw== X-Google-Smtp-Source: APXvYqz/m9P9hcAt8ADHsy5Pn345eiWarc3IGOXKt/8yTI81Ra/swTUKpvKhTLAGHhy0WObiDOag9A== X-Received: by 2002:adf:c709:: with SMTP id k9mr2120074wrg.144.1557511376038; Fri, 10 May 2019 11:02:56 -0700 (PDT) Received: from erokenlabserver ([41.203.78.145]) by smtp.gmail.com with ESMTPSA id f7sm3702948wmb.28.2019.05.10.11.02.51 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Fri, 10 May 2019 11:02:54 -0700 (PDT) Date: Fri, 10 May 2019 19:04:10 +0100 From: Ernest Esene To: qemu-devel@nongnu.org Message-ID: <20190510180410.GA10349@erokenlabserver> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.11.4 (2019-03-13) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::443 Subject: [Qemu-devel] [PATCH v3] chardev/char-i2c: Implement Linux I2C character device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Markus Armbruster , =?iso-8859-1?q?Marc-Andr=E9?= Lureau , Stefan Hajnoczi , Paolo Bonzini , Ernest Esene Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add support for Linux I2C character device for I2C device passthrough For example: -chardev i2c,address=0x46,path=/dev/i2c-N,id=i2c-chardev QEMU supports emulation of I2C devices in software but currently can't passthrough to real I2C devices. This feature is needed by developers using QEMU for writing and testing software for I2C devices. Signed-off-by: Ernest Esene --- v3: * change licence to GPLv2+ * use non blocking IO for the chardev * change "address" to QEMU_OPT_NUMBER * update qemu-options.hx --- v2: * Fixed errors * update "MAINTAINERS" file. --- MAINTAINERS | 5 ++ chardev/Makefile.objs | 1 + chardev/char-linux-i2c.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ chardev/char.c | 3 ++ include/chardev/char.h | 1 + qapi/char.json | 17 +++++++ qemu-options.hx | 14 +++++- 7 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 chardev/char-linux-i2c.c diff --git a/MAINTAINERS b/MAINTAINERS index 66ddbda9c9..d834a12241 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1801,6 +1801,11 @@ M: Samuel Thibault S: Maintained F: chardev/baum.c +Character Devices (I2C) +M: Ernest Esene +S: Maintained +F: chardev/char-linux-i2c.c + Command line option argument parsing M: Markus Armbruster S: Supported diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index d68e1347f9..7b64009aa6 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -16,6 +16,7 @@ chardev-obj-y += char-stdio.o chardev-obj-y += char-udp.o chardev-obj-$(CONFIG_WIN32) += char-win.o chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o +chardev-obj-$(CONFIG_LINUX) +=char-linux-i2c.o common-obj-y += msmouse.o wctablet.o testdev.o common-obj-$(CONFIG_BRLAPI) += baum.o diff --git a/chardev/char-linux-i2c.c b/chardev/char-linux-i2c.c new file mode 100644 index 0000000000..847a18f611 --- /dev/null +++ b/chardev/char-linux-i2c.c @@ -0,0 +1,126 @@ +/* + * QEMU System Emulator + * Linux I2C device support as a character device. + * + * Copyright (c) 2019 Ernest Esene + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/option.h" +#include "qemu-common.h" +#include "io/channel-file.h" +#include "qemu/cutils.h" +#include "qemu/sockets.h" + +#include "chardev/char-fd.h" +#include "chardev/char.h" + +#include +#include +#include + +#define CHR_IOCTL_I2C_SET_ADDR 1 + +#define CHR_I2C_ADDR_10BIT_MAX 1023 +#define CHR_I2C_ADDR_7BIT_MAX 127 + +static int i2c_ioctl(Chardev *chr, int cmd, void *arg) +{ + FDChardev *fd_chr = FD_CHARDEV(chr); + QIOChannelFile *floc = QIO_CHANNEL_FILE(fd_chr->ioc_in); + int fd = floc->fd; + int addr; + unsigned long funcs; + + switch (cmd) { + case CHR_IOCTL_I2C_SET_ADDR: + addr = (intptr_t)arg; + + if (addr > CHR_I2C_ADDR_7BIT_MAX) { + if (ioctl(fd, I2C_FUNCS, &funcs) < 0) { + goto err; + } + if (!(funcs & I2C_FUNC_10BIT_ADDR)) { + goto err; + } + if (ioctl(fd, I2C_TENBIT, addr) < 0) { + goto err; + } + } else { + if (ioctl(fd, I2C_SLAVE, addr) < 0) { + goto err; + } + } + break; + + default: + return -ENOTSUP; + } + return 0; +err: + return -ENOTSUP; +} + +static void qmp_chardev_open_i2c(Chardev *chr, ChardevBackend *backend, + bool *be_opened, Error **errp) +{ + ChardevI2c *i2c = backend->u.i2c.data; + void *addr; + int fd; + + fd = qmp_chardev_open_file_source(i2c->device, O_RDWR | O_NONBLOCK, errp); + if (fd < 0) { + return; + } + qemu_set_nonblock(fd); + qemu_chr_open_fd(chr, fd, fd); + addr = (void *)(intptr_t)i2c->address; + i2c_ioctl(chr, CHR_IOCTL_I2C_SET_ADDR, addr); +} + +static void qemu_chr_parse_i2c(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + long address = qemu_opt_get_number(opts, "address", LONG_MAX); + ChardevI2c *i2c; + + if (device == NULL) { + error_setg(errp, "chardev: i2c: no device path given"); + return; + } + if (address < 0 || address > CHR_I2C_ADDR_10BIT_MAX) { + error_setg(errp, "chardev: i2c: device address out of range"); + return; + } + backend->type = CHARDEV_BACKEND_KIND_I2C; + i2c = backend->u.i2c.data = g_new0(ChardevI2c, 1); + qemu_chr_parse_common(opts, qapi_ChardevI2c_base(i2c)); + i2c->device = g_strdup(device); + i2c->address = (int16_t)address; +} + +static void char_i2c_class_init(ObjectClass *oc, void *data) +{ + ChardevClass *cc = CHARDEV_CLASS(oc); + + cc->parse = qemu_chr_parse_i2c; + cc->open = qmp_chardev_open_i2c; + cc->chr_ioctl = i2c_ioctl; +} + +static const TypeInfo char_i2c_type_info = { + .name = TYPE_CHARDEV_I2C, + .parent = TYPE_CHARDEV_FD, + .class_init = char_i2c_class_init, +}; + +static void register_types(void) +{ + type_register_static(&char_i2c_type_info); +} + +type_init(register_types); diff --git a/chardev/char.c b/chardev/char.c index 54724a56b1..8f5ffe16e6 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -926,6 +926,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "logappend", .type = QEMU_OPT_BOOL, + },{ + .name = "address", + .type = QEMU_OPT_NUMBER, }, { /* end of list */ } }, diff --git a/include/chardev/char.h b/include/chardev/char.h index c0b57f7685..0e08b70fc9 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -245,6 +245,7 @@ int qemu_chr_wait_connected(Chardev *chr, Error **errp); #define TYPE_CHARDEV_SERIAL "chardev-serial" #define TYPE_CHARDEV_SOCKET "chardev-socket" #define TYPE_CHARDEV_UDP "chardev-udp" +#define TYPE_CHARDEV_I2C "chardev-i2c" #define CHARDEV_IS_RINGBUF(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF) diff --git a/qapi/char.json b/qapi/char.json index a6e81ac7bc..7168b58cfe 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -240,6 +240,22 @@ 'data': { 'device': 'str' }, 'base': 'ChardevCommon' } +## +# @ChardevI2c: +# +# Configuration info for i2c chardev. +# +# @device: The name of the special file for the device, +# i.e. /dev/i2c-0 on linux +# @address: The address of the i2c device on the host. +# +# Since: 4.1 +## +{ 'struct': 'ChardevI2c', + 'data': { 'device': 'str', + 'address': 'int16'}, + 'base': 'ChardevCommon' } + ## # @ChardevSocket: # @@ -398,6 +414,7 @@ 'data': { 'file': 'ChardevFile', 'serial': 'ChardevHostdev', 'parallel': 'ChardevHostdev', + 'i2c': 'ChardevI2c', 'pipe': 'ChardevHostdev', 'socket': 'ChardevSocket', 'udp': 'ChardevUdp', diff --git a/qemu-options.hx b/qemu-options.hx index 51802cbb26..435b6975dd 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2695,6 +2695,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #if defined(CONFIG_SPICE) "-chardev spicevmc,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n" "-chardev spiceport,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n" +#endif +#ifdef CONFIG_LINUX + "-chardev i2c,id=id,address=address[,path=path][,logfile=PATH][,logappend=on|off]\n" #endif , QEMU_ARCH_ALL ) @@ -2723,7 +2726,8 @@ Backend is one of: @option{parallel}, @option{parport}, @option{spicevmc}, -@option{spiceport}. +@option{spiceport}, +@option{i2c}. The specific backend will determine the applicable options. Use @code{-chardev help} to print all available chardev backend types. @@ -2990,6 +2994,14 @@ Connect to a spice virtual machine channel, such as vdiport. Connect to a spice port, allowing a Spice client to handle the traffic identified by a name (preferably a fqdn). + +@item -chardev i2c,id=@var{id},address=@var{address},path=@var{path} + +@option{path} i2c character device (Eg: /dev/i2c-N on Linux) + +@option{address} address of the slave device. + +I2C device support as a character device. ETEXI STEXI