All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ernest Esene <eroken1@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Stefan Hajnoczi" <stefanha@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Eric Blake" <eblake@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Ernest Esene" <eroken1@gmail.com>
Subject: [Qemu-devel] [PATCH] chardev/char-i2c: Implement Linux I2C character device
Date: Fri, 3 May 2019 20:31:41 +0100	[thread overview]
Message-ID: <20190503193141.GA17700@erokenlabserver> (raw)

[-- Attachment #1: Type: text/plain, Size: 7529 bytes --]

Add support for Linux I2C character device for I2C device passthrough
For example:
-chardev linux-i2c,address=0x46,path=/dev/i2c-N,id=i2c-chardev

Signed-off-by: Ernest Esene <eroken1@gmail.com>
---
 chardev/Makefile.objs  |   1 +
 chardev/char-i2c.c     | 142 +++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c         |   3 ++
 include/chardev/char.h |   1 +
 qapi/char.json         |  16 ++++++
 5 files changed, 163 insertions(+)
 create mode 100644 chardev/char-i2c.c

diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index d68e1347f9..6c96b9a353 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_POSIX) +=char-i2c.o
 
 common-obj-y += msmouse.o wctablet.o testdev.o
 common-obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/chardev/char-i2c.c b/chardev/char-i2c.c
new file mode 100644
index 0000000000..78cf973bd7
--- /dev/null
+++ b/chardev/char-i2c.c
@@ -0,0 +1,142 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2019 Ernest Esene <eroken1@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/option.h"
+#include "qemu-common.h"
+#include "io/channel-file.h"
+
+#include "chardev/char-fd.h"
+#include "chardev/char.h"
+
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#define CHR_IOCTL_I2C_SET_ADDR 1
+
+#define CHR_I2C_ADDR_10BIT_MAX 1023
+#define CHR_I2C_ADDR_7BIT_MAX 127
+
+void qemu_set_block(int fd);
+
+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;
+
+    switch (cmd) {
+        case CHR_IOCTL_I2C_SET_ADDR:
+            addr = (int) (long) arg;
+
+            if (addr > CHR_I2C_ADDR_7BIT_MAX) {
+                /*TODO: check if adapter support 10-bit addr
+                I2C_FUNC_10BIT_ADDR */
+                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_block(fd);
+    qemu_chr_open_fd(chr, fd, fd);
+    addr = (void *) (long) 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");
+    const char *addr = qemu_opt_get(opts, "address");
+    long address;
+    ChardevI2c *i2c;
+    
+    if (device == NULL) {
+        error_setg(errp, "chardev: linux-i2c: no device path given");
+        return;
+    }
+    if (addr == NULL) {
+        error_setg(errp, "chardev: linux-i2c: no device address given");
+        return;
+    }
+    address = strtol(addr, NULL, 0);
+    if (address < 0 || address > CHR_I2C_ADDR_10BIT_MAX) {
+        error_setg(errp, "chardev: linux-i2c: invalid device address given");
+        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..93732a9909 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_STRING,
         },
         { /* end of list */ }
     },
diff --git a/include/chardev/char.h b/include/chardev/char.h
index c0b57f7685..880614391f 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-linux-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..602b4099dc 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -240,6 +240,21 @@
   'data': { 'device': 'str' },
   'base': 'ChardevCommon' }
 
+##
+# @ChardevI2c:
+#
+# Configuration info for i2c chardev (only on linux).
+#
+# @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.
+#
+##
+{ 'struct': 'ChardevI2c',
+  'data': { 'device': 'str',
+            'address': 'int16'},
+  'base': 'ChardevCommon'}
+
 ##
 # @ChardevSocket:
 #
@@ -398,6 +413,7 @@
   'data': { 'file': 'ChardevFile',
             'serial': 'ChardevHostdev',
             'parallel': 'ChardevHostdev',
+            'i2c': 'ChardevI2c',
             'pipe': 'ChardevHostdev',
             'socket': 'ChardevSocket',
             'udp': 'ChardevUdp',
-- 
2.14.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

WARNING: multiple messages have this Message-ID (diff)
From: Ernest Esene <eroken1@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Markus Armbruster" <armbru@redhat.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Ernest Esene" <eroken1@gmail.com>
Subject: [Qemu-devel] [PATCH] chardev/char-i2c: Implement Linux I2C character device
Date: Fri, 3 May 2019 20:31:41 +0100	[thread overview]
Message-ID: <20190503193141.GA17700@erokenlabserver> (raw)
Message-ID: <20190503193141.qmM5YBFHIaV9vyo1L7-BRgT7J3ThJRatQNXmT84U6RA@z> (raw)

[-- Attachment #1: Type: text/plain, Size: 7529 bytes --]

Add support for Linux I2C character device for I2C device passthrough
For example:
-chardev linux-i2c,address=0x46,path=/dev/i2c-N,id=i2c-chardev

Signed-off-by: Ernest Esene <eroken1@gmail.com>
---
 chardev/Makefile.objs  |   1 +
 chardev/char-i2c.c     | 142 +++++++++++++++++++++++++++++++++++++++++++++++++
 chardev/char.c         |   3 ++
 include/chardev/char.h |   1 +
 qapi/char.json         |  16 ++++++
 5 files changed, 163 insertions(+)
 create mode 100644 chardev/char-i2c.c

diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs
index d68e1347f9..6c96b9a353 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_POSIX) +=char-i2c.o
 
 common-obj-y += msmouse.o wctablet.o testdev.o
 common-obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/chardev/char-i2c.c b/chardev/char-i2c.c
new file mode 100644
index 0000000000..78cf973bd7
--- /dev/null
+++ b/chardev/char-i2c.c
@@ -0,0 +1,142 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2019 Ernest Esene <eroken1@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/option.h"
+#include "qemu-common.h"
+#include "io/channel-file.h"
+
+#include "chardev/char-fd.h"
+#include "chardev/char.h"
+
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#define CHR_IOCTL_I2C_SET_ADDR 1
+
+#define CHR_I2C_ADDR_10BIT_MAX 1023
+#define CHR_I2C_ADDR_7BIT_MAX 127
+
+void qemu_set_block(int fd);
+
+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;
+
+    switch (cmd) {
+        case CHR_IOCTL_I2C_SET_ADDR:
+            addr = (int) (long) arg;
+
+            if (addr > CHR_I2C_ADDR_7BIT_MAX) {
+                /*TODO: check if adapter support 10-bit addr
+                I2C_FUNC_10BIT_ADDR */
+                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_block(fd);
+    qemu_chr_open_fd(chr, fd, fd);
+    addr = (void *) (long) 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");
+    const char *addr = qemu_opt_get(opts, "address");
+    long address;
+    ChardevI2c *i2c;
+    
+    if (device == NULL) {
+        error_setg(errp, "chardev: linux-i2c: no device path given");
+        return;
+    }
+    if (addr == NULL) {
+        error_setg(errp, "chardev: linux-i2c: no device address given");
+        return;
+    }
+    address = strtol(addr, NULL, 0);
+    if (address < 0 || address > CHR_I2C_ADDR_10BIT_MAX) {
+        error_setg(errp, "chardev: linux-i2c: invalid device address given");
+        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..93732a9909 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_STRING,
         },
         { /* end of list */ }
     },
diff --git a/include/chardev/char.h b/include/chardev/char.h
index c0b57f7685..880614391f 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-linux-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..602b4099dc 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -240,6 +240,21 @@
   'data': { 'device': 'str' },
   'base': 'ChardevCommon' }
 
+##
+# @ChardevI2c:
+#
+# Configuration info for i2c chardev (only on linux).
+#
+# @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.
+#
+##
+{ 'struct': 'ChardevI2c',
+  'data': { 'device': 'str',
+            'address': 'int16'},
+  'base': 'ChardevCommon'}
+
 ##
 # @ChardevSocket:
 #
@@ -398,6 +413,7 @@
   'data': { 'file': 'ChardevFile',
             'serial': 'ChardevHostdev',
             'parallel': 'ChardevHostdev',
+            'i2c': 'ChardevI2c',
             'pipe': 'ChardevHostdev',
             'socket': 'ChardevSocket',
             'udp': 'ChardevUdp',
-- 
2.14.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

             reply	other threads:[~2019-05-03 19:28 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-03 19:31 Ernest Esene [this message]
2019-05-03 19:31 ` [Qemu-devel] [PATCH] chardev/char-i2c: Implement Linux I2C character device Ernest Esene
2019-05-03 20:24 ` Eric Blake
2019-05-03 20:24   ` Eric Blake
2019-05-03 21:46   ` Ernest Esene
2019-05-03 21:46     ` Ernest Esene

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190503193141.GA17700@erokenlabserver \
    --to=eroken1@gmail.com \
    --cc=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.