OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

virtio-dev message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: [PATCH qemu 3/6] virtio-input: core code & base class


This patch adds virtio-input support to qemu.  It brings a abstract
base class providing core support, other classes can build on it to
actually implement input devices.

virtio-input basically sends linux input layer events (evdev) over
virtio.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/input/Makefile.objs           |   4 +
 hw/input/virtio-input.c          | 253 +++++++++++++++++++++++++++++++++++++++
 hw/virtio/virtio-pci.c           |  36 ++++++
 hw/virtio/virtio-pci.h           |  14 +++
 include/hw/virtio/virtio-input.h | 105 ++++++++++++++++
 include/hw/virtio/virtio.h       |   1 +
 6 files changed, 413 insertions(+)
 create mode 100644 hw/input/virtio-input.c
 create mode 100644 include/hw/virtio/virtio-input.h

diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index e8c80b9..ee8bba9 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -8,6 +8,10 @@ common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
 common-obj-$(CONFIG_TSC2005) += tsc2005.o
 common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 
+ifeq ($(CONFIG_LINUX),y)
+common-obj-$(CONFIG_VIRTIO) += virtio-input.o
+endif
+
 obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
 obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
 obj-$(CONFIG_TSC210X) += tsc210x.o
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
new file mode 100644
index 0000000..35f0cfc
--- /dev/null
+++ b/hw/input/virtio-input.c
@@ -0,0 +1,253 @@
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.  See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/iov.h"
+
+#include "hw/qdev.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-input.h"
+
+#include "ui/console.h"
+
+#include <linux/input.h>
+
+/* ----------------------------------------------------------------- */
+
+void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
+{
+    VirtQueueElement elem;
+    int len;
+
+    if (!virtqueue_pop(vinput->evt, &elem)) {
+        fprintf(stderr, "%s: virtqueue empty, dropping event\n", __func__);
+        return;
+    }
+    len = iov_from_buf(elem.in_sg, elem.in_num,
+                       0, event, sizeof(*event));
+    virtqueue_push(vinput->evt, &elem, len);
+}
+
+static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /* nothing */
+}
+
+static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
+    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
+    virtio_input_event event;
+    VirtQueueElement elem;
+    int len;
+
+    while (virtqueue_pop(vinput->sts, &elem)) {
+        memset(&event, 0, sizeof(event));
+        len = iov_to_buf(elem.out_sg, elem.out_num,
+                         0, &event, sizeof(event));
+        if (vic->handle_status) {
+            vic->handle_status(vinput, &event);
+        }
+        virtqueue_push(vinput->sts, &elem, len);
+    }
+    virtio_notify(vdev, vinput->sts);
+}
+
+static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
+                                                     uint8_t select,
+                                                     uint8_t subsel)
+{
+    VirtIOInputConfig *cfg;
+
+    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
+        if (select == cfg->config.select &&
+            subsel == cfg->config.subsel) {
+            return &cfg->config;
+        }
+    }
+    return NULL;
+}
+
+void virtio_input_add_config(VirtIOInput *vinput,
+                             virtio_input_config *config)
+{
+    VirtIOInputConfig *cfg;
+
+    if (virtio_input_find_config(vinput, config->select, config->subsel)) {
+        /* should not happen */
+        fprintf(stderr, "%s: duplicate config: %d/%d\n",
+                __func__, config->select, config->subsel);
+        abort();
+    }
+
+    cfg = g_new0(VirtIOInputConfig, 1);
+    cfg->config = *config;
+    QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
+}
+
+void virtio_input_init_config(VirtIOInput *vinput,
+                              virtio_input_config *config)
+{
+    int i = 0;
+
+    QTAILQ_INIT(&vinput->cfg_list);
+    while (config[i].select) {
+        virtio_input_add_config(vinput, config + i);
+        i++;
+    }
+}
+
+void virtio_input_idstr_config(VirtIOInput *vinput,
+                               uint8_t select, const char *string)
+{
+    virtio_input_config id;
+
+    if (!string) {
+        return;
+    }
+    memset(&id, 0, sizeof(id));
+    id.select = select;
+    id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
+    virtio_input_add_config(vinput, &id);
+}
+
+static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
+    virtio_input_config *config;
+
+    config = virtio_input_find_config(vinput, vinput->cfg_select,
+                                      vinput->cfg_subsel);
+    if (config) {
+        memcpy(config_data, config, vinput->cfg_size);
+    } else {
+        memset(config_data, 0, vinput->cfg_size);
+    }
+}
+
+static void virtio_input_set_config(VirtIODevice *vdev,
+                                    const uint8_t *config_data)
+{
+    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
+    virtio_input_config *config = (virtio_input_config *)config_data;
+
+    vinput->cfg_select = config->select;
+    vinput->cfg_subsel = config->subsel;
+    virtio_notify_config(vdev);
+}
+
+static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
+{
+    return f;
+}
+
+static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
+    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
+
+    if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
+        if (!vinput->active) {
+            vinput->active = true;
+            if (vic->change_active) {
+                vic->change_active(vinput);
+            }
+        }
+    }
+}
+
+static void virtio_input_reset(VirtIODevice *vdev)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
+    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
+
+    if (vinput->active) {
+        vinput->active = false;
+        if (vic->change_active) {
+            vic->change_active(vinput);
+        }
+    }
+}
+
+static void virtio_input_device_realize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOInput *vinput = VIRTIO_INPUT(dev);
+    VirtIOInputConfig *cfg;
+
+
+    if (vic->unrealize) {
+        vic->realize(dev, errp);
+        if (error_is_set(errp)) {
+            return;
+        }
+    }
+
+    virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
+                              vinput->input.serial);
+    virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SEAT,
+                              vinput->input.seat);
+
+    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
+        if (vinput->cfg_size < cfg->config.size) {
+            vinput->cfg_size = cfg->config.size;
+        }
+    }
+    vinput->cfg_size += 4;
+    assert(vinput->cfg_size <= sizeof(virtio_input_config));
+
+    virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
+                vinput->cfg_size);
+    vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
+    vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
+}
+
+static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+    if (vic->unrealize) {
+        vic->unrealize(dev, errp);
+        if (error_is_set(errp)) {
+            return;
+        }
+    }
+    virtio_cleanup(vdev);
+}
+
+static void virtio_input_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    vdc->realize      = virtio_input_device_realize;
+    vdc->unrealize    = virtio_input_device_unrealize;
+    vdc->get_config   = virtio_input_get_config;
+    vdc->set_config   = virtio_input_set_config;
+    vdc->get_features = virtio_input_get_features;
+    vdc->set_status   = virtio_input_set_status;
+    vdc->reset        = virtio_input_reset;
+}
+
+static const TypeInfo virtio_input_info = {
+    .name          = TYPE_VIRTIO_INPUT,
+    .parent        = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOInput),
+    .class_size    = sizeof(VirtIOInputClass),
+    .class_init    = virtio_input_class_init,
+    .abstract      = true,
+};
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_input_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ce97514..5518192 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -23,6 +23,7 @@
 #include "hw/virtio/virtio-serial.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "hw/virtio/virtio-balloon.h"
+#include "hw/virtio/virtio-input.h"
 #include "hw/pci/pci.h"
 #include "qemu/error-report.h"
 #include "hw/pci/msi.h"
@@ -1531,6 +1532,40 @@ static const TypeInfo virtio_rng_pci_info = {
     .class_init    = virtio_rng_pci_class_init,
 };
 
+/* virtio-input-pci */
+
+static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&vinput->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    return qdev_init(vdev);
+}
+
+static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_input_pci_init;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_INPUT;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static const TypeInfo virtio_input_pci_info = {
+    .name          = TYPE_VIRTIO_INPUT_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOInputPCI),
+    .class_init    = virtio_input_pci_class_init,
+    .abstract      = true,
+};
+
 /* virtio-pci-bus */
 
 static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -1575,6 +1610,7 @@ static const TypeInfo virtio_pci_bus_info = {
 static void virtio_pci_register_types(void)
 {
     type_register_static(&virtio_rng_pci_info);
+    type_register_static(&virtio_input_pci_info);
     type_register_static(&virtio_pci_bus_info);
     type_register_static(&virtio_pci_info);
 #ifdef CONFIG_VIRTFS
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index dc332ae..f1e75ad 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -24,6 +24,7 @@
 #include "hw/virtio/virtio-balloon.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/virtio-9p.h"
+#include "hw/virtio/virtio-input.h"
 #ifdef CONFIG_VIRTFS
 #include "hw/9pfs/virtio-9p.h"
 #endif
@@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI;
 typedef struct VirtIONetPCI VirtIONetPCI;
 typedef struct VHostSCSIPCI VHostSCSIPCI;
 typedef struct VirtIORngPCI VirtIORngPCI;
+typedef struct VirtIOInputPCI VirtIOInputPCI;
 
 /* virtio-pci-bus */
 
@@ -199,6 +201,18 @@ struct VirtIORngPCI {
     VirtIORNG vdev;
 };
 
+/*
+ * virtio-input-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
+#define VIRTIO_INPUT_PCI(obj) \
+        OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
+
+struct VirtIOInputPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOInput vdev;
+};
+
 /* Virtio ABI version, if we increment this, we break the guest driver. */
 #define VIRTIO_PCI_ABI_VERSION          0
 
diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h
new file mode 100644
index 0000000..5d37a70
--- /dev/null
+++ b/include/hw/virtio/virtio-input.h
@@ -0,0 +1,105 @@
+#ifndef _QEMU_VIRTIO_INPUT_H
+#define _QEMU_VIRTIO_INPUT_H
+
+#include "ui/input.h"
+
+/* ----------------------------------------------------------------- */
+/* virtio input protocol                                             */
+
+/* The Virtio ID for the virtio input device */
+#define VIRTIO_ID_INPUT 18
+
+enum virtio_input_config_select {
+    VIRTIO_INPUT_CFG_UNSET      = 0x00,
+    VIRTIO_INPUT_CFG_ID_NAME    = 0x01,
+    VIRTIO_INPUT_CFG_ID_SERIAL  = 0x02,
+    VIRTIO_INPUT_CFG_ID_SEAT    = 0x03,
+    VIRTIO_INPUT_CFG_PROP_BITS  = 0x10,
+    VIRTIO_INPUT_CFG_EV_BITS    = 0x11,
+    VIRTIO_INPUT_CFG_ABS_INFO   = 0x12,
+};
+
+typedef struct virtio_input_absinfo {
+    uint32_t       min;
+    uint32_t       max;
+    uint32_t       fuzz;
+    uint32_t       flat;
+} virtio_input_absinfo;
+
+typedef struct virtio_input_config {
+    uint8_t        select;
+    uint8_t        subsel;
+    uint8_t        size;
+    uint8_t        reserved;
+    union {
+        char       string[128];
+        uint8_t    bitmap[128];
+        virtio_input_absinfo abs;
+    } u;
+} virtio_input_config;
+
+typedef struct virtio_input_event {
+    uint16_t       type;
+    uint16_t       code;
+    int32_t        value;
+} virtio_input_event;
+
+/* ----------------------------------------------------------------- */
+/* qemu internals                                                    */
+
+#define TYPE_VIRTIO_INPUT "virtio-input-device"
+#define VIRTIO_INPUT(obj) \
+        OBJECT_CHECK(VirtIOInput, (obj), TYPE_VIRTIO_INPUT)
+#define VIRTIO_INPUT_GET_PARENT_CLASS(obj) \
+        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT)
+#define VIRTIO_INPUT_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtIOInputClass, obj, TYPE_VIRTIO_INPUT)
+#define VIRTIO_INPUT_CLASS(klass) \
+        OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT)
+
+typedef struct VirtIOInput VirtIOInput;
+typedef struct VirtIOInputClass VirtIOInputClass;
+typedef struct VirtIOInputConfig VirtIOInputConfig;
+
+struct virtio_input_conf {
+    char *serial;
+    char *seat;
+};
+
+struct VirtIOInputConfig {
+    virtio_input_config               config;
+    QTAILQ_ENTRY(VirtIOInputConfig)   node;
+};
+
+struct VirtIOInput {
+    VirtIODevice                      parent_obj;
+    uint8_t                           cfg_select;
+    uint8_t                           cfg_subsel;
+    uint32_t                          cfg_size;
+    QTAILQ_HEAD(, VirtIOInputConfig)  cfg_list;
+    VirtQueue                         *evt, *sts;
+    virtio_input_conf                 input;
+
+    bool                              active;
+};
+
+struct VirtIOInputClass {
+    /*< private >*/
+    VirtioDeviceClass parent;
+    /*< public >*/
+
+    DeviceRealize realize;
+    DeviceUnrealize unrealize;
+    void (*change_active)(VirtIOInput *vinput);
+    void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event);
+};
+
+void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
+void virtio_input_init_config(VirtIOInput *vinput,
+                              virtio_input_config *config);
+void virtio_input_add_config(VirtIOInput *vinput,
+                             virtio_input_config *config);
+void virtio_input_idstr_config(VirtIOInput *vinput,
+                               uint8_t select, const char *string);
+
+#endif /* _QEMU_VIRTIO_INPUT_H */
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 3e54e90..93d1607 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -222,6 +222,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
                               struct virtio_net_conf *net,
                               uint32_t host_features);
 typedef struct virtio_serial_conf virtio_serial_conf;
+typedef struct virtio_input_conf virtio_input_conf;
 typedef struct VirtIOSCSIConf VirtIOSCSIConf;
 typedef struct VirtIORNGConf VirtIORNGConf;
 
-- 
1.8.3.1



[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]