All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHES] add virtio input device
@ 2014-04-10  9:07 Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH spec] Add virtio input device specification Gerd Hoffmann
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann

  Hi,

Here comes a bunch of patches inplementing the virtio input device for
review.  One patch for the virtio specification.  One patch for the
linux kernel.  A small patch series for qemu.  Please review.

Note that the qemu patch series has dependencies on unmerged input layer
patches (waiting for the tree being opened up for 2.1), so if you wanna
play with please fetch everything here:
	http://www.kraxel.org/cgit/qemu/log/?h=rebase/input-wip

cheers,
  Gerd

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

* [Qemu-devel] [PATCH spec] Add virtio input device specification
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10 15:36   ` Christopher Covington
  2014-04-10  9:07 ` [Qemu-devel] [PATCH linux] Add virtio-input driver Gerd Hoffmann
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 content.tex      |   2 +
 virtio-input.tex | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)
 create mode 100644 virtio-input.tex

diff --git a/content.tex b/content.tex
index c31a99e..196950d 100644
--- a/content.tex
+++ b/content.tex
@@ -4887,6 +4887,8 @@ descriptor for the \field{sense_len}, \field{residual},
 \field{status_qualifier}, \field{status}, \field{response} and
 \field{sense} fields.
 
+\input{virtio-input.tex}
+
 \chapter{Reserved Feature Bits}\label{sec:Reserved Feature Bits}
 
 Currently there are three device-independent feature bits defined:
diff --git a/virtio-input.tex b/virtio-input.tex
new file mode 100644
index 0000000..3c34a52
--- /dev/null
+++ b/virtio-input.tex
@@ -0,0 +1,135 @@
+\section{Input Device}\label{sec:Device Types / Input Device}
+
+The virtio input device can be used to create virtual human interface
+devices such as keyboards, mice and tables.  It basically sends linux
+input layer events over virtio.
+See \url{file:///usr/include/linux/input.h}.
+
+\subsection{Device ID}\label{sec:Device Types / Input Device / Device ID}
+
+18
+
+\subsection{Virtqueues}\label{sec:Device Types / Input Device / Virtqueues}
+
+\begin{description}
+\item[0] eventq
+\item[1] statusq
+\end{description}
+
+\subsection{Feature bits}\label{sec:Device Types / Input Device / Feature bits}
+
+None.
+
+\subsection{Device configuration layout}\label{sec:Device Types / Input Device / Device configuration layout}
+
+Device configuration holds all information the guest needs to handle
+the device, most importantly the events which are supported.
+
+\begin{lstlisting}
+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,
+};
+
+struct virtio_input_absinfo {
+	le32  min;
+	le32  max;
+	le32  fuzz;
+	le32  flat;
+};
+
+struct virtio_input_config {
+	u8    select;
+	u8    subsel;
+	u8    size;
+	u8    reserved;
+	union {
+		char string[128];
+		u8   bitmap[128];
+		struct virtio_input_absinfo abs;
+	} u;
+};
+\end{lstlisting}
+
+To query a specific piece of information the driver MUST set
+\field{select} and \field{subsel} accordingly, then check \field{size}
+to see and how much information is available.  \field{size} can be
+zero if no information is available.
+
+\begin{description}
+
+\item[VIRTIO_INPUT_CFG_ID_NAME]
+\field{subsel} is not used and MUST be zero.
+Returns the name of the device, in \field{u.string}.
+
+Same as EVIOCGNAME ioctl for linux evdev devices.
+
+\item[VIRTIO_INPUT_CFG_ID_SERIAL]
+\field{subsel} is not used and MUST be zero.
+Returns the serial number of the device, in \field{u.string}.
+
+\item[VIRTIO_INPUT_CFG_ID_SEAT]
+\field{subsel} is not used and MUST be zero.
+Returns the seat the device should be assigned to, in \field{u.string}.
+
+\item[VIRTIO_INPUT_CFG_PROP_BITS]
+\field{subsel} is not used and MUST be zero.
+Returns input properties (INPUT_PROP_*) of the device, in \field{u.bitmap}.
+
+\item[VIRTIO_INPUT_CFG_EV_BITS]
+\field{subsel} specifies the event type (EV_*).  If \field{size} is
+non-zero the event type is supported and a bitmap the of supported
+event codes is returned in \field{u.bitmap}.
+
+Same as EVIOCGBIT ioctl.
+
+\item[VIRTIO_INPUT_CFG_ABS_INFO]
+\field{subsel} specifies the absolute axes (ABS_*).
+Informations about the axis will be returned in \field{u.abs}.
+
+Same as EVIOCGABS ioctl.
+
+\end{description}
+
+\subsection{Device Initialization}\label{sec:Device Types / Input Device / Device Initialization}
+
+\begin{enumerate}
+\item The device is queried for supported event types and codes.
+\item The eventq is populated with receive buffers.
+\end{enumerate}
+
+\subsection{Device Operation}\label{sec:Device Types / Input Device / Device Operation}
+
+\begin{enumerate}
+\item Input events such as press and release events for keys and
+  buttons and motion events are send from the device to the driver
+  using the eventq.
+\item Status feedback such as keyboard led updates are sent from the
+  driver to the device using the statusq.
+\item Both queues use the same virtio_input_event struct.
+  \field{type}, \field{code} and \field{value} are filled according to
+  the linux input layer (evdev) interface, except that the fields are
+  in little endian byte order whereas the evdev ioctl interface uses
+  native endian.
+\end{enumerate}
+
+\begin{lstlisting}
+struct virtio_input_event {
+	le16 type;
+	le16 code;
+	le32 value;
+};
+\end{lstlisting}
+
+\subsection{TODO List}\label{sec:Device Types / Input Device / TODO List}
+
+\begin{description}
+\item[Multitouch]
+Just EVIOCGMTSLOTS -> cfgspace I think.
+Maybe add feature flag for this?
+\end{description}
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH linux] Add virtio-input driver.
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH spec] Add virtio input device specification Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 1/6] pci: add virtio input pci device id Gerd Hoffmann
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann

virtio-input is basically evdev-events-over-virtio, so this driver isn't
much more than forwarding incoming events to the linux input layer.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/virtio/Kconfig            |  10 ++
 drivers/virtio/Makefile           |   1 +
 drivers/virtio/virtio_input.c     | 329 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/virtio_ids.h   |   1 +
 include/uapi/linux/virtio_input.h |  66 ++++++++
 5 files changed, 407 insertions(+)
 create mode 100644 drivers/virtio/virtio_input.c
 create mode 100644 include/uapi/linux/virtio_input.h

diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index c6683f2..05e2fda 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -31,6 +31,16 @@ config VIRTIO_BALLOON
 
 	 If unsure, say M.
 
+config VIRTIO_INPUT
+	tristate "Virtio input driver"
+	depends on VIRTIO
+	depends on INPUT
+	---help---
+	 This driver supports virtio input devices such as
+	 keyboards, mice and tablets.
+
+	 If unsure, say M.
+
  config VIRTIO_MMIO
 	tristate "Platform bus driver for memory mapped virtio devices"
 	depends on HAS_IOMEM
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 9076635..45aeaac 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o
 obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
 obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
+obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
new file mode 100644
index 0000000..25036fb
--- /dev/null
+++ b/drivers/virtio/virtio_input.c
@@ -0,0 +1,329 @@
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/input.h>
+
+#include <uapi/linux/virtio_ids.h>
+#include <uapi/linux/virtio_input.h>
+
+struct virtio_input {
+	struct virtio_device       *vdev;
+	struct input_dev           *idev;
+	char                       name[64];
+	char                       serial[64];
+	char                       seat[64];
+	char                       phys[64];
+	struct virtqueue           *evt, *sts;
+	struct virtio_input_event  evts[64];
+};
+
+static ssize_t serial_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct input_dev *idev = to_input_dev(dev);
+	struct virtio_input *vi = input_get_drvdata(idev);
+	return sprintf(buf, "%s\n", vi->serial);
+}
+static DEVICE_ATTR_RO(serial);
+
+static ssize_t seat_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct input_dev *idev = to_input_dev(dev);
+	struct virtio_input *vi = input_get_drvdata(idev);
+	return sprintf(buf, "%s\n", vi->seat);
+}
+static DEVICE_ATTR_RO(seat);
+
+static struct attribute *dev_attrs[] = {
+	&dev_attr_serial.attr,
+	&dev_attr_seat.attr,
+	NULL
+};
+
+static umode_t dev_attrs_are_visible(struct kobject *kobj,
+				     struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct input_dev *idev = to_input_dev(dev);
+	struct virtio_input *vi = input_get_drvdata(idev);
+
+	if (a == &dev_attr_serial.attr && !strlen(vi->serial))
+		return 0;
+	if (a == &dev_attr_seat.attr && !strlen(vi->seat))
+		return 0;
+
+	return a->mode;
+}
+
+static struct attribute_group dev_attr_grp = {
+	.attrs =	dev_attrs,
+	.is_visible =	dev_attrs_are_visible,
+};
+
+static const struct attribute_group *dev_attr_groups[] = {
+	&dev_attr_grp,
+	NULL
+};
+
+static void virtinput_queue_evtbuf(struct virtio_input *vi,
+				   struct virtio_input_event *evtbuf)
+{
+	struct scatterlist sg[1];
+
+	sg_init_one(sg, evtbuf, sizeof(*evtbuf));
+	virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);
+}
+
+static void virtinput_recv_events(struct virtqueue *vq)
+{
+	struct virtio_input *vi = vq->vdev->priv;
+	struct virtio_input_event *event;
+	unsigned int len;
+
+	while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
+		input_event(vi->idev,
+			    le16_to_cpu(event->type),
+			    le16_to_cpu(event->code),
+			    le32_to_cpu(event->value));
+		virtinput_queue_evtbuf(vi, event);
+	}
+	virtqueue_kick(vq);
+}
+
+static int virtinput_send_status(struct virtio_input *vi,
+				 u16 type, u16 code, s32 value)
+{
+	struct virtio_input_event *stsbuf;
+	struct scatterlist sg[1];
+
+	stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);
+	if (!stsbuf)
+		return -ENOMEM;
+
+	stsbuf->type  = cpu_to_le16(type);
+	stsbuf->code  = cpu_to_le16(code);
+	stsbuf->value = cpu_to_le32(value);
+	sg_init_one(sg, stsbuf, sizeof(*stsbuf));
+	virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);
+	virtqueue_kick(vi->sts);
+	return 0;
+}
+
+static void virtinput_recv_status(struct virtqueue *vq)
+{
+	struct virtio_input *vi = vq->vdev->priv;
+	struct virtio_input_event *stsbuf;
+	unsigned int len;
+
+	while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)
+		kfree(stsbuf);
+	virtqueue_kick(vq);
+}
+
+static int virtinput_status(struct input_dev *idev, unsigned int type,
+			    unsigned int code, int value)
+{
+	struct virtio_input *vi = input_get_drvdata(idev);
+
+	return virtinput_send_status(vi, type, code, value);
+}
+
+static size_t virtinput_cfg_select(struct virtio_input *vi,
+				   u8 select, u8 subsel)
+{
+	u8 size;
+
+	virtio_cwrite(vi->vdev, struct virtio_input_config, select, &select);
+	virtio_cwrite(vi->vdev, struct virtio_input_config, subsel, &subsel);
+	virtio_cread(vi->vdev, struct virtio_input_config, size, &size);
+	return size;
+}
+
+static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,
+			       unsigned long *bits, unsigned int bitcount)
+{
+	unsigned int bit;
+	size_t bytes;
+	u8 cfg = 0;
+
+	bytes = virtinput_cfg_select(vi, select, subsel);
+	if (!bytes)
+		return;
+	if (bitcount > bytes*8)
+		bitcount = bytes*8;
+	if (select == VIRTIO_INPUT_CFG_EV_BITS)
+		set_bit(subsel, vi->idev->evbit);
+	for (bit = 0; bit < bitcount; bit++) {
+		if ((bit % 8) == 0)
+			virtio_cread(vi->vdev, struct virtio_input_config,
+				     u.bitmap[bit/8], &cfg);
+		if (cfg & (1 << (bit % 8)))
+			set_bit(bit, bits);
+	}
+}
+
+static void virtinput_cfg_abs(struct virtio_input *vi, int abs)
+{
+	u32 size, mi, ma, fu, fl;
+
+	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);
+	virtio_cread(vi->vdev, struct virtio_input_config, u.abs.min, &mi);
+	virtio_cread(vi->vdev, struct virtio_input_config, u.abs.max, &ma);
+	virtio_cread(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);
+	virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);
+	input_set_abs_params(vi->idev, abs,
+			     le32_to_cpu(mi), le32_to_cpu(ma),
+			     le32_to_cpu(fu), le32_to_cpu(fl));
+}
+
+static int virtinput_init_vqs(struct virtio_input *vi)
+{
+	struct virtqueue *vqs[2];
+	vq_callback_t *cbs[] = { virtinput_recv_events,
+				 virtinput_recv_status };
+	const char *names[] = { "events", "status" };
+	int i, err, size;
+
+	err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
+	if (err)
+		return err;
+	vi->evt = vqs[0];
+	vi->sts = vqs[1];
+
+	size = virtqueue_get_vring_size(vi->evt);
+	if (size > ARRAY_SIZE(vi->evts))
+		size = ARRAY_SIZE(vi->evts);
+	for (i = 0; i < size; i++)
+		virtinput_queue_evtbuf(vi, &vi->evts[i]);
+
+	return 0;
+}
+
+static int virtinput_probe(struct virtio_device *vdev)
+{
+	struct virtio_input *vi;
+	size_t size;
+	int abs, err;
+
+	vi = kzalloc(sizeof(*vi), GFP_KERNEL);
+	if (!vi) {
+		err = -ENOMEM;
+		goto out1;
+	}
+	vdev->priv = vi;
+	vi->vdev = vdev;
+
+	err = virtinput_init_vqs(vi);
+	if (err)
+		goto out2;
+
+	vi->idev = input_allocate_device();
+	if (!vi->idev) {
+		err = -ENOMEM;
+		goto out3;
+	}
+	input_set_drvdata(vi->idev, vi);
+
+	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0);
+	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
+			   vi->name, min(size, sizeof(vi->name)));
+	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0);
+	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
+			   vi->serial, min(size, sizeof(vi->serial)));
+	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SEAT, 0);
+	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, u),
+			   vi->seat, min(size, sizeof(vi->seat)));
+	snprintf(vi->phys, sizeof(vi->phys),
+		 "virtio%d/input0", vdev->index);
+
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0,
+			   vi->idev->propbit, INPUT_PROP_CNT);
+	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP);
+	if (size)
+		set_bit(EV_REP, vi->idev->evbit);
+
+	vi->idev->name = vi->name;
+	vi->idev->phys = vi->phys;
+	vi->idev->id.bustype = BUS_VIRTUAL;
+	vi->idev->id.vendor  = 0x0001;
+	vi->idev->id.product = 0x0001;
+	vi->idev->id.version = 0x0100;
+	vi->idev->dev.parent = &vdev->dev;
+	vi->idev->dev.groups = dev_attr_groups;
+	vi->idev->event = virtinput_status;
+
+	/* device -> kernel */
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,
+			   vi->idev->keybit, KEY_CNT);
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,
+			   vi->idev->relbit, REL_CNT);
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,
+			   vi->idev->absbit, ABS_CNT);
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC,
+			   vi->idev->mscbit, MSC_CNT);
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW,
+			   vi->idev->swbit,  SW_CNT);
+
+	/* kernel -> device */
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED,
+			   vi->idev->ledbit, LED_CNT);
+	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND,
+			   vi->idev->sndbit, SND_CNT);
+
+	if (test_bit(EV_ABS, vi->idev->evbit)) {
+		for (abs = 0; abs < ABS_CNT; abs++) {
+			if (!test_bit(abs, vi->idev->absbit))
+				continue;
+			virtinput_cfg_abs(vi, abs);
+		}
+	}
+
+	err = input_register_device(vi->idev);
+	if (err)
+		goto out4;
+
+	return 0;
+
+out4:
+	input_free_device(vi->idev);
+out3:
+	vdev->config->del_vqs(vdev);
+out2:
+	kfree(vi);
+out1:
+	return err;
+}
+
+static void virtinput_remove(struct virtio_device *vdev)
+{
+	struct virtio_input *vi = vdev->priv;
+
+	input_unregister_device(vi->idev);
+	vdev->config->reset(vdev);
+	vdev->config->del_vqs(vdev);
+	kfree(vi);
+}
+
+static unsigned int features[] = {
+};
+static struct virtio_device_id id_table[] = {
+	{ VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID },
+	{ 0 },
+};
+
+static struct virtio_driver virtio_input_driver = {
+	.driver.name         = KBUILD_MODNAME,
+	.driver.owner        = THIS_MODULE,
+	.feature_table       = features,
+	.feature_table_size  = ARRAY_SIZE(features),
+	.id_table            = id_table,
+	.probe               = virtinput_probe,
+	.remove              = virtinput_remove,
+};
+
+module_virtio_driver(virtio_input_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Virtio input device driver");
+MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index 284fc3a..5f60aa4 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -39,5 +39,6 @@
 #define VIRTIO_ID_9P		9 /* 9p virtio console */
 #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */
 #define VIRTIO_ID_CAIF	       12 /* Virtio caif */
+#define VIRTIO_ID_INPUT        18 /* virtio input */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_input.h b/include/uapi/linux/virtio_input.h
new file mode 100644
index 0000000..1de5155
--- /dev/null
+++ b/include/uapi/linux/virtio_input.h
@@ -0,0 +1,66 @@
+#ifndef _LINUX_VIRTIO_INPUT_H
+#define _LINUX_VIRTIO_INPUT_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+
+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,
+};
+
+struct virtio_input_absinfo {
+	__le32  min;
+	__le32  max;
+	__le32  fuzz;
+	__le32  flat;
+};
+
+struct virtio_input_config {
+	__u8    select;
+	__u8    subsel;
+	__u8    size;
+	__u8    reserved;
+	union {
+		char string[128];
+		__u8 bitmap[128];
+		struct virtio_input_absinfo abs;
+	} u;
+};
+
+struct virtio_input_event {
+	__le16 type;
+	__le16 code;
+	__le32 value;
+};
+
+#endif /* _LINUX_VIRTIO_INPUT_H */
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH qemu 1/6] pci: add virtio input pci device id
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH spec] Add virtio input device specification Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH linux] Add virtio-input driver Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 2/6] pci: add virtio gpu " Gerd Hoffmann
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Michael S. Tsirkin

Using 0x1012 because virtio id is 18 (0x12).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 docs/specs/pci-ids.txt | 1 +
 include/hw/pci/pci.h   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt
index 3c65e1a..3b0a448 100644
--- a/docs/specs/pci-ids.txt
+++ b/docs/specs/pci-ids.txt
@@ -22,6 +22,7 @@ maintained as part of the virtio specification.
 1af4:1004  SCSI host bus adapter device
 1af4:1005  entropy generator device
 1af4:1009  9p filesystem device
+1af4:1012  input device
 
 1af4:10f0  Available for experimental usage without registration.  Must get
    to      official ID when the code leaves the test lab (i.e. when seeking
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 693dd6b..6539cbd 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -80,6 +80,7 @@
 #define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
 #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
 #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
+#define PCI_DEVICE_ID_VIRTIO_INPUT       0x1012
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
 #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH qemu 2/6] pci: add virtio gpu pci device id
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 1/6] pci: add virtio input pci device id Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class Gerd Hoffmann
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Michael S. Tsirkin

Using 0x1010 because virtio id is 16 (0x10).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 docs/specs/pci-ids.txt | 1 +
 include/hw/pci/pci.h   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt
index 3b0a448..69a2de9 100644
--- a/docs/specs/pci-ids.txt
+++ b/docs/specs/pci-ids.txt
@@ -22,6 +22,7 @@ maintained as part of the virtio specification.
 1af4:1004  SCSI host bus adapter device
 1af4:1005  entropy generator device
 1af4:1009  9p filesystem device
+1af4:1010  gpu device
 1af4:1012  input device
 
 1af4:10f0  Available for experimental usage without registration.  Must get
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 6539cbd..6ebc5fa 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -80,6 +80,7 @@
 #define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
 #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
 #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
+#define PCI_DEVICE_ID_VIRTIO_GPU         0x1010
 #define PCI_DEVICE_ID_VIRTIO_INPUT       0x1012
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 2/6] pci: add virtio gpu " Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10 11:06   ` Michael S. Tsirkin
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices Gerd Hoffmann
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

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

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

* [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10 10:55   ` Michael S. Tsirkin
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device Gerd Hoffmann
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough Gerd Hoffmann
  7 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

This patch adds the virtio-input-hid base class and
virtio-{keyboard,mouse,tablet} subclasses building on the base class.
They are hooked up to the qemu input core and deliver input events
to the guest like all other hid devices (ps/2 kbd, usb tablet, ...).

Using them is as simple as adding "-device virtio-tablet-pci" to your
command line.  If you want add multiple devices but don't want waste
a pci slot for each you can compose a multifunction device this way:

qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
     -device virtio-tablet-pci,addr=0d.1,multifunction=on

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/input/Makefile.objs           |   1 +
 hw/input/virtio-input-hid.c      | 486 +++++++++++++++++++++++++++++++++++++++
 hw/virtio/virtio-pci.c           |  68 ++++++
 hw/virtio/virtio-pci.h           |  13 ++
 include/hw/virtio/virtio-input.h |  22 ++
 5 files changed, 590 insertions(+)
 create mode 100644 hw/input/virtio-input-hid.c

diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index ee8bba9..0dae710 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -10,6 +10,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 
 ifeq ($(CONFIG_LINUX),y)
 common-obj-$(CONFIG_VIRTIO) += virtio-input.o
+common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
 endif
 
 obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
new file mode 100644
index 0000000..2db993e
--- /dev/null
+++ b/hw/input/virtio-input-hid.c
@@ -0,0 +1,486 @@
+/*
+ * 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>
+
+#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard"
+#define VIRTIO_ID_NAME_MOUSE    "QEMU Virtio Mouse"
+#define VIRTIO_ID_NAME_TABLET   "QEMU Virtio Tablet"
+
+/* ----------------------------------------------------------------- */
+
+static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
+    [Q_KEY_CODE_ESC]                 = KEY_ESC,
+    [Q_KEY_CODE_1]                   = KEY_1,
+    [Q_KEY_CODE_2]                   = KEY_2,
+    [Q_KEY_CODE_3]                   = KEY_3,
+    [Q_KEY_CODE_4]                   = KEY_4,
+    [Q_KEY_CODE_5]                   = KEY_5,
+    [Q_KEY_CODE_6]                   = KEY_6,
+    [Q_KEY_CODE_7]                   = KEY_7,
+    [Q_KEY_CODE_8]                   = KEY_8,
+    [Q_KEY_CODE_9]                   = KEY_9,
+    [Q_KEY_CODE_0]                   = KEY_0,
+    [Q_KEY_CODE_MINUS]               = KEY_MINUS,
+    [Q_KEY_CODE_EQUAL]               = KEY_EQUAL,
+    [Q_KEY_CODE_BACKSPACE]           = KEY_BACKSPACE,
+
+    [Q_KEY_CODE_TAB]                 = KEY_TAB,
+    [Q_KEY_CODE_Q]                   = KEY_Q,
+    [Q_KEY_CODE_W]                   = KEY_W,
+    [Q_KEY_CODE_E]                   = KEY_E,
+    [Q_KEY_CODE_R]                   = KEY_R,
+    [Q_KEY_CODE_T]                   = KEY_T,
+    [Q_KEY_CODE_Y]                   = KEY_Y,
+    [Q_KEY_CODE_U]                   = KEY_U,
+    [Q_KEY_CODE_I]                   = KEY_I,
+    [Q_KEY_CODE_O]                   = KEY_O,
+    [Q_KEY_CODE_P]                   = KEY_P,
+    [Q_KEY_CODE_BRACKET_LEFT]        = KEY_LEFTBRACE,
+    [Q_KEY_CODE_BRACKET_RIGHT]       = KEY_RIGHTBRACE,
+    [Q_KEY_CODE_RET]                 = KEY_ENTER,
+
+    [Q_KEY_CODE_CTRL]                = KEY_LEFTCTRL,
+    [Q_KEY_CODE_A]                   = KEY_A,
+    [Q_KEY_CODE_S]                   = KEY_S,
+    [Q_KEY_CODE_D]                   = KEY_D,
+    [Q_KEY_CODE_F]                   = KEY_F,
+    [Q_KEY_CODE_G]                   = KEY_G,
+    [Q_KEY_CODE_H]                   = KEY_H,
+    [Q_KEY_CODE_J]                   = KEY_J,
+    [Q_KEY_CODE_K]                   = KEY_K,
+    [Q_KEY_CODE_L]                   = KEY_L,
+    [Q_KEY_CODE_SEMICOLON]           = KEY_SEMICOLON,
+    [Q_KEY_CODE_APOSTROPHE]          = KEY_APOSTROPHE,
+    [Q_KEY_CODE_GRAVE_ACCENT]        = KEY_GRAVE,
+
+    [Q_KEY_CODE_SHIFT]               = KEY_LEFTSHIFT,
+    [Q_KEY_CODE_BACKSLASH]           = KEY_BACKSLASH,
+    [Q_KEY_CODE_LESS]                = KEY_102ND,
+    [Q_KEY_CODE_Z]                   = KEY_Z,
+    [Q_KEY_CODE_X]                   = KEY_X,
+    [Q_KEY_CODE_C]                   = KEY_C,
+    [Q_KEY_CODE_V]                   = KEY_V,
+    [Q_KEY_CODE_B]                   = KEY_B,
+    [Q_KEY_CODE_N]                   = KEY_N,
+    [Q_KEY_CODE_M]                   = KEY_M,
+    [Q_KEY_CODE_COMMA]               = KEY_COMMA,
+    [Q_KEY_CODE_DOT]                 = KEY_DOT,
+    [Q_KEY_CODE_SLASH]               = KEY_SLASH,
+    [Q_KEY_CODE_SHIFT_R]             = KEY_RIGHTSHIFT,
+
+    [Q_KEY_CODE_ALT]                 = KEY_LEFTALT,
+    [Q_KEY_CODE_SPC]                 = KEY_SPACE,
+    [Q_KEY_CODE_CAPS_LOCK]           = KEY_CAPSLOCK,
+
+    [Q_KEY_CODE_F1]                  = KEY_F1,
+    [Q_KEY_CODE_F2]                  = KEY_F2,
+    [Q_KEY_CODE_F3]                  = KEY_F3,
+    [Q_KEY_CODE_F4]                  = KEY_F4,
+    [Q_KEY_CODE_F5]                  = KEY_F5,
+    [Q_KEY_CODE_F6]                  = KEY_F6,
+    [Q_KEY_CODE_F7]                  = KEY_F7,
+    [Q_KEY_CODE_F8]                  = KEY_F8,
+    [Q_KEY_CODE_F9]                  = KEY_F9,
+    [Q_KEY_CODE_F10]                 = KEY_F10,
+    [Q_KEY_CODE_NUM_LOCK]            = KEY_NUMLOCK,
+    [Q_KEY_CODE_SCROLL_LOCK]         = KEY_SCROLLLOCK,
+
+    [Q_KEY_CODE_KP_0]                = KEY_KP0,
+    [Q_KEY_CODE_KP_1]                = KEY_KP1,
+    [Q_KEY_CODE_KP_2]                = KEY_KP2,
+    [Q_KEY_CODE_KP_3]                = KEY_KP3,
+    [Q_KEY_CODE_KP_4]                = KEY_KP4,
+    [Q_KEY_CODE_KP_5]                = KEY_KP5,
+    [Q_KEY_CODE_KP_6]                = KEY_KP6,
+    [Q_KEY_CODE_KP_7]                = KEY_KP7,
+    [Q_KEY_CODE_KP_8]                = KEY_KP8,
+    [Q_KEY_CODE_KP_9]                = KEY_KP9,
+    [Q_KEY_CODE_KP_SUBTRACT]         = KEY_KPMINUS,
+    [Q_KEY_CODE_KP_ADD]              = KEY_KPPLUS,
+    [Q_KEY_CODE_KP_DECIMAL]          = KEY_KPDOT,
+    [Q_KEY_CODE_KP_ENTER]            = KEY_KPENTER,
+    [Q_KEY_CODE_KP_DIVIDE]           = KEY_KPSLASH,
+    [Q_KEY_CODE_KP_MULTIPLY]         = KEY_KPASTERISK,
+
+    [Q_KEY_CODE_F11]                 = KEY_F11,
+    [Q_KEY_CODE_F12]                 = KEY_F12,
+
+    [Q_KEY_CODE_CTRL_R]              = KEY_RIGHTCTRL,
+    [Q_KEY_CODE_SYSRQ]               = KEY_SYSRQ,
+    [Q_KEY_CODE_ALT_R]               = KEY_RIGHTALT,
+
+    [Q_KEY_CODE_HOME]                = KEY_HOME,
+    [Q_KEY_CODE_UP]                  = KEY_UP,
+    [Q_KEY_CODE_PGUP]                = KEY_PAGEUP,
+    [Q_KEY_CODE_LEFT]                = KEY_LEFT,
+    [Q_KEY_CODE_RIGHT]               = KEY_RIGHT,
+    [Q_KEY_CODE_END]                 = KEY_END,
+    [Q_KEY_CODE_DOWN]                = KEY_DOWN,
+    [Q_KEY_CODE_PGDN]                = KEY_PAGEDOWN,
+    [Q_KEY_CODE_INSERT]              = KEY_INSERT,
+    [Q_KEY_CODE_DELETE]              = KEY_DELETE,
+
+    [Q_KEY_CODE_META_L]              = KEY_LEFTMETA,
+    [Q_KEY_CODE_META_R]              = KEY_RIGHTMETA,
+    [Q_KEY_CODE_MENU]                = KEY_MENU,
+};
+
+static const unsigned int keymap_button[INPUT_BUTTON_MAX] = {
+    [INPUT_BUTTON_LEFT]              = BTN_LEFT,
+    [INPUT_BUTTON_RIGHT]             = BTN_RIGHT,
+    [INPUT_BUTTON_MIDDLE]            = BTN_MIDDLE,
+    [INPUT_BUTTON_WHEEL_UP]          = BTN_GEAR_UP,
+    [INPUT_BUTTON_WHEEL_DOWN]        = BTN_GEAR_DOWN,
+};
+
+static const unsigned int axismap_rel[INPUT_AXIS_MAX] = {
+    [INPUT_AXIS_X]                   = REL_X,
+    [INPUT_AXIS_Y]                   = REL_Y,
+};
+
+static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
+    [INPUT_AXIS_X]                   = ABS_X,
+    [INPUT_AXIS_Y]                   = ABS_Y,
+};
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_input_key_config(VirtIOInput *vinput,
+                                    const unsigned int *keymap,
+                                    size_t mapsize)
+{
+    virtio_input_config keys;
+    int i, bit, byte, bmax = 0;
+
+    memset(&keys, 0, sizeof(keys));
+    for (i = 0; i < mapsize; i++) {
+        bit = keymap[i];
+        if (!bit) {
+            continue;
+        }
+        byte = bit / 8;
+        bit  = bit % 8;
+        keys.u.bitmap[byte] |= (1 << bit);
+        if (bmax < byte+1) {
+            bmax = byte+1;
+        }
+    }
+    keys.select = VIRTIO_INPUT_CFG_EV_BITS;
+    keys.subsel = EV_KEY;
+    keys.size   = bmax;
+    virtio_input_add_config(vinput, &keys);
+}
+
+static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
+                                      InputEvent *evt)
+{
+    VirtIOInput *vinput = VIRTIO_INPUT(dev);
+    virtio_input_event event;
+    int qcode;
+
+    switch (evt->kind) {
+    case INPUT_EVENT_KIND_KEY:
+        qcode = qemu_input_key_value_to_qcode(evt->key->key);
+        if (qcode && keymap_qcode[qcode]) {
+            event.type  = cpu_to_le16(EV_KEY);
+            event.code  = cpu_to_le16(keymap_qcode[qcode]);
+            event.value = cpu_to_le32(evt->key->down ? 1 : 0);
+            virtio_input_send(vinput, &event);
+        } else {
+            if (evt->key->down) {
+                fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
+                        qcode, QKeyCode_lookup[qcode]);
+            }
+        }
+        break;
+    case INPUT_EVENT_KIND_BTN:
+        if (keymap_button[evt->btn->button]) {
+            event.type  = cpu_to_le16(EV_KEY);
+            event.code  = cpu_to_le16(keymap_button[evt->btn->button]);
+            event.value = cpu_to_le32(evt->btn->down ? 1 : 0);
+            virtio_input_send(vinput, &event);
+        } else {
+            if (evt->btn->down) {
+                fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
+                        evt->btn->button, InputButton_lookup[evt->btn->button]);
+            }
+        }
+        break;
+    case INPUT_EVENT_KIND_REL:
+        event.type  = cpu_to_le16(EV_REL);
+        event.code  = cpu_to_le16(axismap_rel[evt->rel->axis]);
+        event.value = cpu_to_le32(evt->rel->value);
+        virtio_input_send(vinput, &event);
+        break;
+    case INPUT_EVENT_KIND_ABS:
+        event.type  = cpu_to_le16(EV_ABS);
+        event.code  = cpu_to_le16(axismap_abs[evt->abs->axis]);
+        event.value = cpu_to_le32(evt->abs->value);
+        virtio_input_send(vinput, &event);
+        break;
+    default:
+        /* keep gcc happy */
+        break;
+    }
+}
+
+static void virtio_input_handle_sync(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOInput *vinput = VIRTIO_INPUT(dev);
+    virtio_input_event event = {
+        .type  = cpu_to_le16(EV_SYN),
+        .code  = cpu_to_le16(SYN_REPORT),
+        .value = 0,
+    };
+
+    virtio_input_send(vinput, &event);
+    virtio_notify(vdev, vinput->evt);
+}
+
+static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
+    vhid->hs = qemu_input_handler_register(dev, vhid->handler);
+}
+
+static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
+    qemu_input_handler_unregister(vhid->hs);
+}
+
+static void virtio_input_hid_change_active(VirtIOInput *vinput)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
+
+    if (vinput->active) {
+        qemu_input_handler_activate(vhid->hs);
+    } else {
+        qemu_input_handler_deactivate(vhid->hs);
+    }
+}
+
+static void virtio_input_hid_handle_status(VirtIOInput *vinput,
+                                           virtio_input_event *event)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
+    int ledbit = 0;
+
+    switch (le16_to_cpu(event->type)) {
+    case EV_LED:
+        if (event->code == LED_NUML) {
+            ledbit = QEMU_NUM_LOCK_LED;
+        } else if (event->code == LED_CAPSL) {
+            ledbit = QEMU_CAPS_LOCK_LED;
+        } else if (event->code == LED_SCROLLL) {
+            ledbit = QEMU_SCROLL_LOCK_LED;
+        }
+        if (event->value) {
+            vhid->ledstate |= ledbit;
+        } else {
+            vhid->ledstate &= ~ledbit;
+        }
+        kbd_put_ledstate(vhid->ledstate);
+        break;
+    default:
+        fprintf(stderr, "%s: unknown type %d\n", __func__,
+                le16_to_cpu(event->type));
+        break;
+    }
+}
+
+static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
+
+    vic->realize       = virtio_input_hid_realize;
+    vic->unrealize     = virtio_input_hid_unrealize;
+    vic->change_active = virtio_input_hid_change_active;
+    vic->handle_status = virtio_input_hid_handle_status;
+}
+
+static const TypeInfo virtio_input_hid_info = {
+    .name          = TYPE_VIRTIO_INPUT_HID,
+    .parent        = TYPE_VIRTIO_INPUT,
+    .instance_size = sizeof(VirtIOInputHID),
+    .class_init    = virtio_input_hid_class_init,
+    .abstract      = true,
+};
+
+/* ----------------------------------------------------------------- */
+
+static QemuInputHandler virtio_keyboard_handler = {
+    .name  = VIRTIO_ID_NAME_KEYBOARD,
+    .mask  = INPUT_EVENT_MASK_KEY,
+    .event = virtio_input_handle_event,
+    .sync  = virtio_input_handle_sync,
+};
+
+static struct virtio_input_config virtio_keyboard_config[] = {
+    {
+        .select    = VIRTIO_INPUT_CFG_ID_NAME,
+        .size      = sizeof(VIRTIO_ID_NAME_KEYBOARD),
+        .u.string  = VIRTIO_ID_NAME_KEYBOARD,
+    },{
+        .select    = VIRTIO_INPUT_CFG_EV_BITS,
+        .subsel    = EV_REP,
+        .size      = 1,
+    },{
+        .select    = VIRTIO_INPUT_CFG_EV_BITS,
+        .subsel    = EV_LED,
+        .size      = 1,
+        .u.bitmap  = {
+            (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
+        },
+    },
+    { /* end of list */ },
+};
+
+static void virtio_keyboard_init(Object *obj)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
+    VirtIOInput *vinput = VIRTIO_INPUT(obj);
+
+    vhid->handler = &virtio_keyboard_handler;
+    virtio_input_init_config(vinput, virtio_keyboard_config);
+    virtio_input_key_config(vinput, keymap_qcode,
+                            ARRAY_SIZE(keymap_qcode));
+}
+
+static const TypeInfo virtio_keyboard_info = {
+    .name          = TYPE_VIRTIO_KEYBOARD,
+    .parent        = TYPE_VIRTIO_INPUT_HID,
+    .instance_size = sizeof(VirtIOInputHID),
+    .instance_init = virtio_keyboard_init,
+};
+
+/* ----------------------------------------------------------------- */
+
+static QemuInputHandler virtio_mouse_handler = {
+    .name  = VIRTIO_ID_NAME_MOUSE,
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+    .event = virtio_input_handle_event,
+    .sync  = virtio_input_handle_sync,
+};
+
+static struct virtio_input_config virtio_mouse_config[] = {
+    {
+        .select    = VIRTIO_INPUT_CFG_ID_NAME,
+        .size      = sizeof(VIRTIO_ID_NAME_MOUSE),
+        .u.string  = VIRTIO_ID_NAME_MOUSE,
+    },{
+        .select    = VIRTIO_INPUT_CFG_EV_BITS,
+        .subsel    = EV_REL,
+        .size      = 1,
+        .u.bitmap  = {
+            (1 << REL_X) | (1 << REL_Y),
+        },
+    },
+    { /* end of list */ },
+};
+
+static void virtio_mouse_init(Object *obj)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
+    VirtIOInput *vinput = VIRTIO_INPUT(obj);
+
+    vhid->handler = &virtio_mouse_handler;
+    virtio_input_init_config(vinput, virtio_mouse_config);
+    virtio_input_key_config(vinput, keymap_button,
+                            ARRAY_SIZE(keymap_button));
+}
+
+static const TypeInfo virtio_mouse_info = {
+    .name          = TYPE_VIRTIO_MOUSE,
+    .parent        = TYPE_VIRTIO_INPUT_HID,
+    .instance_size = sizeof(VirtIOInputHID),
+    .instance_init = virtio_mouse_init,
+};
+
+/* ----------------------------------------------------------------- */
+
+static QemuInputHandler virtio_tablet_handler = {
+    .name  = VIRTIO_ID_NAME_TABLET,
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
+    .event = virtio_input_handle_event,
+    .sync  = virtio_input_handle_sync,
+};
+
+static struct virtio_input_config virtio_tablet_config[] = {
+    {
+        .select    = VIRTIO_INPUT_CFG_ID_NAME,
+        .size      = sizeof(VIRTIO_ID_NAME_TABLET),
+        .u.string  = VIRTIO_ID_NAME_TABLET,
+    },{
+        .select    = VIRTIO_INPUT_CFG_EV_BITS,
+        .subsel    = EV_ABS,
+        .size      = 1,
+        .u.bitmap  = {
+            (1 << ABS_X) | (1 << ABS_Y),
+        },
+    },{
+        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
+        .subsel    = ABS_X,
+        .size      = sizeof(virtio_input_absinfo),
+#if 0
+        /* FIXME */
+        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
+#else
+        .u.abs.max = INPUT_EVENT_ABS_SIZE,
+#endif
+    },{
+        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
+        .subsel    = ABS_Y,
+        .size      = sizeof(virtio_input_absinfo),
+#if 0
+        /* FIXME */
+        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
+#else
+        .u.abs.max = INPUT_EVENT_ABS_SIZE,
+#endif
+    },
+    { /* end of list */ },
+};
+
+static void virtio_tablet_init(Object *obj)
+{
+    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
+    VirtIOInput *vinput = VIRTIO_INPUT(obj);
+
+    vhid->handler = &virtio_tablet_handler;
+    virtio_input_init_config(vinput, virtio_tablet_config);
+    virtio_input_key_config(vinput, keymap_button,
+                            ARRAY_SIZE(keymap_button));
+}
+
+static const TypeInfo virtio_tablet_info = {
+    .name          = TYPE_VIRTIO_TABLET,
+    .parent        = TYPE_VIRTIO_INPUT_HID,
+    .instance_size = sizeof(VirtIOInputHID),
+    .instance_init = virtio_tablet_init,
+};
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_input_hid_info);
+    type_register_static(&virtio_keyboard_info);
+    type_register_static(&virtio_mouse_info);
+    type_register_static(&virtio_tablet_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 5518192..b421c01 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1534,6 +1534,13 @@ static const TypeInfo virtio_rng_pci_info = {
 
 /* virtio-input-pci */
 
+static Property virtio_input_hid_pci_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
 {
     VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
@@ -1558,6 +1565,34 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
     pcidev_k->class_id = PCI_CLASS_OTHERS;
 }
 
+static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = virtio_input_hid_pci_properties;
+}
+
+static void virtio_keyboard_initfn(Object *obj)
+{
+    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static void virtio_mouse_initfn(Object *obj)
+{
+    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static void virtio_tablet_initfn(Object *obj)
+{
+    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
 static const TypeInfo virtio_input_pci_info = {
     .name          = TYPE_VIRTIO_INPUT_PCI,
     .parent        = TYPE_VIRTIO_PCI,
@@ -1566,6 +1601,35 @@ static const TypeInfo virtio_input_pci_info = {
     .abstract      = true,
 };
 
+static const TypeInfo virtio_input_hid_pci_info = {
+    .name          = TYPE_VIRTIO_INPUT_HID_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_PCI,
+    .instance_size = sizeof(VirtIOInputHIDPCI),
+    .class_init    = virtio_input_hid_pci_class_init,
+    .abstract      = true,
+};
+
+static const TypeInfo virtio_keyboard_pci_info = {
+    .name          = TYPE_VIRTIO_KEYBOARD_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
+    .instance_size = sizeof(VirtIOInputHIDPCI),
+    .instance_init = virtio_keyboard_initfn,
+};
+
+static const TypeInfo virtio_mouse_pci_info = {
+    .name          = TYPE_VIRTIO_MOUSE_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
+    .instance_size = sizeof(VirtIOInputHIDPCI),
+    .instance_init = virtio_mouse_initfn,
+};
+
+static const TypeInfo virtio_tablet_pci_info = {
+    .name          = TYPE_VIRTIO_TABLET_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
+    .instance_size = sizeof(VirtIOInputHIDPCI),
+    .instance_init = virtio_tablet_initfn,
+};
+
 /* virtio-pci-bus */
 
 static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -1611,6 +1675,10 @@ 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_input_hid_pci_info);
+    type_register_static(&virtio_keyboard_pci_info);
+    type_register_static(&virtio_mouse_pci_info);
+    type_register_static(&virtio_tablet_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 f1e75ad..f615ae6 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -41,6 +41,7 @@ typedef struct VirtIONetPCI VirtIONetPCI;
 typedef struct VHostSCSIPCI VHostSCSIPCI;
 typedef struct VirtIORngPCI VirtIORngPCI;
 typedef struct VirtIOInputPCI VirtIOInputPCI;
+typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
 
 /* virtio-pci-bus */
 
@@ -213,6 +214,18 @@ struct VirtIOInputPCI {
     VirtIOInput vdev;
 };
 
+#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
+#define TYPE_VIRTIO_KEYBOARD_PCI  "virtio-keyboard-pci"
+#define TYPE_VIRTIO_MOUSE_PCI     "virtio-mouse-pci"
+#define TYPE_VIRTIO_TABLET_PCI    "virtio-tablet-pci"
+#define VIRTIO_INPUT_HID_PCI(obj) \
+        OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
+
+struct VirtIOInputHIDPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOInputHID 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
index 5d37a70..4b819c3 100644
--- a/include/hw/virtio/virtio-input.h
+++ b/include/hw/virtio/virtio-input.h
@@ -57,9 +57,24 @@ typedef struct virtio_input_event {
 #define VIRTIO_INPUT_CLASS(klass) \
         OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT)
 
+#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid"
+#define TYPE_VIRTIO_KEYBOARD  "virtio-keyboard"
+#define TYPE_VIRTIO_MOUSE     "virtio-mouse"
+#define TYPE_VIRTIO_TABLET    "virtio-tablet"
+
+#define VIRTIO_INPUT_HID(obj) \
+        OBJECT_CHECK(VirtIOInputHID, (obj), TYPE_VIRTIO_INPUT_HID)
+#define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
+        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
+
+#define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
+        DEFINE_PROP_STRING("serial", _state, _field.serial), \
+        DEFINE_PROP_STRING("seat", _state, _field.seat)
+
 typedef struct VirtIOInput VirtIOInput;
 typedef struct VirtIOInputClass VirtIOInputClass;
 typedef struct VirtIOInputConfig VirtIOInputConfig;
+typedef struct VirtIOInputHID VirtIOInputHID;
 
 struct virtio_input_conf {
     char *serial;
@@ -94,6 +109,13 @@ struct VirtIOInputClass {
     void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event);
 };
 
+struct VirtIOInputHID {
+    VirtIOInput                       parent_obj;
+    QemuInputHandler                  *handler;
+    QemuInputHandlerState             *hs;
+    int                               ledstate;
+};
+
 void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
 void virtio_input_init_config(VirtIOInput *vinput,
                               virtio_input_config *config);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10 11:05   ` Michael S. Tsirkin
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough Gerd Hoffmann
  7 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Device for sending non-input control messages to the guest.  For now
this is only a single event: shutdown requests are sent as power button
press to the guest.

Possible other use is signaling sound volume changes to the guest (via
EV_ABS / ABS_VOLUME).  I expect we'll find more over time.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/input/Makefile.objs           |   1 +
 hw/input/virtio-input-control.c  | 112 +++++++++++++++++++++++++++++++++++++++
 hw/virtio/virtio-pci.c           |  29 ++++++++++
 hw/virtio/virtio-pci.h           |  10 ++++
 include/hw/virtio/virtio-input.h |  12 +++++
 5 files changed, 164 insertions(+)
 create mode 100644 hw/input/virtio-input-control.c

diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index 0dae710..0179154 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -11,6 +11,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 ifeq ($(CONFIG_LINUX),y)
 common-obj-$(CONFIG_VIRTIO) += virtio-input.o
 common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
+common-obj-$(CONFIG_VIRTIO) += virtio-input-control.o
 endif
 
 obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
diff --git a/hw/input/virtio-input-control.c b/hw/input/virtio-input-control.c
new file mode 100644
index 0000000..3e439e6
--- /dev/null
+++ b/hw/input/virtio-input-control.c
@@ -0,0 +1,112 @@
+/*
+ * 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>
+
+#define VIRTIO_ID_NAME_CTRL "QEMU Virtio Control Panel"
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_input_key_config(VirtIOInput *vinput)
+{
+    static const int keylist[] = { KEY_POWER };
+    virtio_input_config keys;
+    int i, bit, byte, bmax = 0;
+
+    memset(&keys, 0, sizeof(keys));
+    for (i = 0; i < ARRAY_SIZE(keylist); i++) {
+        byte = keylist[i] / 8;
+        bit  = keylist[i] % 8;
+        keys.u.bitmap[byte] |= (1 << bit);
+        if (bmax < byte+1) {
+            bmax = byte+1;
+        }
+    }
+    keys.select = VIRTIO_INPUT_CFG_EV_BITS;
+    keys.subsel = EV_KEY;
+    keys.size   = bmax;
+    virtio_input_add_config(vinput, &keys);
+}
+
+static void virtio_input_ctrl_keypress(VirtIOInput *vinput, int keycode)
+{
+    virtio_input_event key_down = {
+        .type  = cpu_to_le16(EV_KEY),
+        .code  = cpu_to_le16(keycode),
+        .value = 1,
+    };
+    virtio_input_event key_up = {
+        .type  = cpu_to_le16(EV_KEY),
+        .code  = cpu_to_le16(keycode),
+        .value = 0,
+    };
+    virtio_input_event sync = {
+        .type  = cpu_to_le16(EV_SYN),
+        .code  = cpu_to_le16(SYN_REPORT),
+        .value = 0,
+    };
+
+    virtio_input_send(vinput, &key_down);
+    virtio_input_send(vinput, &sync);
+    virtio_input_send(vinput, &key_up);
+    virtio_input_send(vinput, &sync);
+    virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
+}
+
+static void virtio_input_ctrl_powerdown(Notifier *n, void *opaque)
+{
+    VirtIOInputCtrl *vctrl =
+        container_of(n, VirtIOInputCtrl, powerdown);
+
+    virtio_input_ctrl_keypress(VIRTIO_INPUT(vctrl), KEY_POWER);
+}
+
+/* ----------------------------------------------------------------- */
+
+static struct virtio_input_config virtio_ctrl_config[] = {
+    {
+        .select    = VIRTIO_INPUT_CFG_ID_NAME,
+        .size      = sizeof(VIRTIO_ID_NAME_CTRL),
+        .u.string  = VIRTIO_ID_NAME_CTRL,
+    },
+    { /* end of list */ },
+};
+
+static void virtio_ctrl_init(Object *obj)
+{
+    VirtIOInput *vinput = VIRTIO_INPUT(obj);
+    VirtIOInputCtrl *vctrl = VIRTIO_INPUT_CTRL(obj);
+
+    virtio_input_init_config(vinput, virtio_ctrl_config);
+    virtio_input_key_config(vinput);
+
+    vctrl->powerdown.notify = virtio_input_ctrl_powerdown;
+    qemu_register_powerdown_notifier(&vctrl->powerdown);
+}
+
+static const TypeInfo virtio_ctrl_info = {
+    .name          = TYPE_VIRTIO_INPUT_CTRL,
+    .parent        = TYPE_VIRTIO_INPUT,
+    .instance_size = sizeof(VirtIOInputCtrl),
+    .instance_init = virtio_ctrl_init,
+};
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_ctrl_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index b421c01..9446d45 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1541,6 +1541,12 @@ static Property virtio_input_hid_pci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static Property virtio_input_ctrl_pci_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
 {
     VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
@@ -1572,6 +1578,13 @@ static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
     dc->props = virtio_input_hid_pci_properties;
 }
 
+static void virtio_input_ctrl_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = virtio_input_ctrl_pci_properties;
+}
+
 static void virtio_keyboard_initfn(Object *obj)
 {
     VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
@@ -1593,6 +1606,13 @@ static void virtio_tablet_initfn(Object *obj)
     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
 }
 
+static void virtio_ctrl_initfn(Object *obj)
+{
+    VirtIOInputCtrlPCI *dev = VIRTIO_INPUT_CTRL_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_INPUT_CTRL);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
 static const TypeInfo virtio_input_pci_info = {
     .name          = TYPE_VIRTIO_INPUT_PCI,
     .parent        = TYPE_VIRTIO_PCI,
@@ -1630,6 +1650,14 @@ static const TypeInfo virtio_tablet_pci_info = {
     .instance_init = virtio_tablet_initfn,
 };
 
+static const TypeInfo virtio_ctrl_pci_info = {
+    .name          = TYPE_VIRTIO_INPUT_CTRL_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_PCI,
+    .instance_size = sizeof(VirtIOInputCtrlPCI),
+    .instance_init = virtio_ctrl_initfn,
+    .class_init    = virtio_input_ctrl_pci_class_init,
+};
+
 /* virtio-pci-bus */
 
 static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -1679,6 +1707,7 @@ static void virtio_pci_register_types(void)
     type_register_static(&virtio_keyboard_pci_info);
     type_register_static(&virtio_mouse_pci_info);
     type_register_static(&virtio_tablet_pci_info);
+    type_register_static(&virtio_ctrl_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 f615ae6..0c26e64 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -42,6 +42,7 @@ typedef struct VHostSCSIPCI VHostSCSIPCI;
 typedef struct VirtIORngPCI VirtIORngPCI;
 typedef struct VirtIOInputPCI VirtIOInputPCI;
 typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
+typedef struct VirtIOInputCtrlPCI VirtIOInputCtrlPCI;
 
 /* virtio-pci-bus */
 
@@ -226,6 +227,15 @@ struct VirtIOInputHIDPCI {
     VirtIOInputHID vdev;
 };
 
+#define TYPE_VIRTIO_INPUT_CTRL_PCI "virtio-input-control-pci"
+#define VIRTIO_INPUT_CTRL_PCI(obj) \
+        OBJECT_CHECK(VirtIOInputCtrlPCI, (obj), TYPE_VIRTIO_INPUT_CTRL_PCI)
+
+struct VirtIOInputCtrlPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOInputCtrl 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
index 4b819c3..d753834 100644
--- a/include/hw/virtio/virtio-input.h
+++ b/include/hw/virtio/virtio-input.h
@@ -67,6 +67,12 @@ typedef struct virtio_input_event {
 #define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
         OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
 
+#define TYPE_VIRTIO_INPUT_CTRL   "virtio-input-control"
+#define VIRTIO_INPUT_CTRL(obj) \
+        OBJECT_CHECK(VirtIOInputCtrl, (obj), TYPE_VIRTIO_INPUT_CTRL)
+#define VIRTIO_INPUT_CTRL_GET_PARENT_CLASS(obj) \
+        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_CTRL)
+
 #define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
         DEFINE_PROP_STRING("serial", _state, _field.serial), \
         DEFINE_PROP_STRING("seat", _state, _field.seat)
@@ -75,6 +81,7 @@ typedef struct VirtIOInput VirtIOInput;
 typedef struct VirtIOInputClass VirtIOInputClass;
 typedef struct VirtIOInputConfig VirtIOInputConfig;
 typedef struct VirtIOInputHID VirtIOInputHID;
+typedef struct VirtIOInputCtrl VirtIOInputCtrl;
 
 struct virtio_input_conf {
     char *serial;
@@ -116,6 +123,11 @@ struct VirtIOInputHID {
     int                               ledstate;
 };
 
+struct VirtIOInputCtrl {
+    VirtIOInput                       parent_obj;
+    Notifier                          powerdown;
+};
+
 void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
 void virtio_input_init_config(VirtIOInput *vinput,
                               virtio_input_config *config);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough
  2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device Gerd Hoffmann
@ 2014-04-10  9:07 ` Gerd Hoffmann
  2014-04-10 11:05   ` Michael S. Tsirkin
  7 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10  9:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: virtio-dev, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

This allows to assign host input devices to the guest:

qemu -device virto-input-host-pci,evdev=/dev/input/event<nr>

The guest gets exclusive access to the input device, so be careful
with assigning the keyboard if you have only one connected to your
machine.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/input/Makefile.objs           |   1 +
 hw/input/virtio-input-host.c     | 174 +++++++++++++++++++++++++++++++++++++++
 hw/virtio/virtio-pci.c           |  31 +++++++
 hw/virtio/virtio-pci.h           |  10 +++
 include/hw/virtio/virtio-input.h |  13 +++
 5 files changed, 229 insertions(+)
 create mode 100644 hw/input/virtio-input-host.c

diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index 0179154..9461b37 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -12,6 +12,7 @@ ifeq ($(CONFIG_LINUX),y)
 common-obj-$(CONFIG_VIRTIO) += virtio-input.o
 common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
 common-obj-$(CONFIG_VIRTIO) += virtio-input-control.o
+common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
 endif
 
 obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
new file mode 100644
index 0000000..663d967
--- /dev/null
+++ b/hw/input/virtio-input-host.c
@@ -0,0 +1,174 @@
+/*
+ * 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-common.h"
+#include "qemu/sockets.h"
+
+#include "hw/qdev.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-input.h"
+
+#include "ui/console.h"
+
+#include <linux/input.h>
+
+/* ----------------------------------------------------------------- */
+
+static struct virtio_input_config virtio_input_host_config[] = {
+    { /* empty list */ },
+};
+
+static void virtio_input_host_event(void *opaque)
+{
+    VirtIOInputHost *vhost = opaque;
+    VirtIOInput *vinput = VIRTIO_INPUT(vhost);
+    struct virtio_input_event virtio;
+    struct input_event evdev;
+    bool notify = false;
+    int rc;
+
+    for (;;) {
+        rc = read(vhost->fd, &evdev, sizeof(evdev));
+        if (rc != sizeof(evdev)) {
+            break;
+        }
+
+        virtio.type  = cpu_to_le16(evdev.type);
+        virtio.code  = cpu_to_le16(evdev.code);
+        virtio.value = cpu_to_le32(evdev.value);
+        virtio_input_send(vinput, &virtio);
+
+        if (evdev.type == EV_SYN) {
+            notify = true;
+        }
+    }
+
+    if (notify) {
+        virtio_notify(VIRTIO_DEVICE(vhost), vinput->evt);
+    }
+}
+
+static void virtio_input_bits_config(VirtIOInputHost *vhost,
+                                     int type, int count)
+{
+    virtio_input_config bits;
+    int rc, i, size = 0;
+
+    memset(&bits, 0, sizeof(bits));
+    rc = ioctl(vhost->fd, EVIOCGBIT(type, count/8), bits.u.bitmap);
+    if (rc < 0) {
+        return;
+    }
+
+    for (i = 0; i < count/8; i++) {
+        if (bits.u.bitmap[i]) {
+            size = i+1;
+        }
+    }
+    if (size == 0) {
+        return;
+    }
+
+    bits.select = VIRTIO_INPUT_CFG_EV_BITS;
+    bits.subsel = type;
+    bits.size   = size;
+    virtio_input_add_config(VIRTIO_INPUT(vhost), &bits);
+}
+
+static void virtio_input_host_realize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputHost *vhost = VIRTIO_INPUT_HOST(dev);
+    VirtIOInput *vinput = VIRTIO_INPUT(dev);
+    virtio_input_config id;
+    int rc, ver;
+
+    if (!vhost->evdev) {
+        error_setg(errp, "evdev property is required");
+        return;
+    }
+
+    vhost->fd = open(vhost->evdev, O_RDWR);
+    if (vhost->fd < 0)  {
+        error_setg_file_open(errp, errno, vhost->evdev);
+        return;
+    }
+    qemu_set_nonblock(vhost->fd);
+
+    rc = ioctl(vhost->fd, EVIOCGVERSION, &ver);
+    if (rc < 0) {
+        error_setg(errp, "%s: is not an evdev device", vhost->evdev);
+        goto err_close;
+    }
+
+    rc = ioctl(vhost->fd, EVIOCGRAB, 1);
+    if (rc < 0) {
+        error_setg_errno(errp, errno, "%s: failed to get exclusive access",
+                         vhost->evdev);
+        goto err_close;
+    }
+
+    memset(&id, 0, sizeof(id));
+    ioctl(vhost->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string);
+    id.select = VIRTIO_INPUT_CFG_ID_NAME;
+    id.size = strlen(id.u.string);
+    virtio_input_add_config(vinput, &id);
+
+    virtio_input_bits_config(vhost, EV_KEY, KEY_CNT);
+    virtio_input_bits_config(vhost, EV_REL, REL_CNT);
+    virtio_input_bits_config(vhost, EV_ABS, ABS_CNT);
+    virtio_input_bits_config(vhost, EV_MSC, MSC_CNT);
+    virtio_input_bits_config(vhost, EV_SW,  SW_CNT);
+
+    qemu_set_fd_handler(vhost->fd, virtio_input_host_event, NULL, vhost);
+    return;
+
+err_close:
+    close(vhost->fd);
+    vhost->fd = -1;
+    return;
+}
+
+static void virtio_input_host_unrealize(DeviceState *dev, Error **errp)
+{
+    VirtIOInputHost *vhost = VIRTIO_INPUT_HOST(dev);
+
+    if (vhost->fd > 0) {
+        qemu_set_fd_handler(vhost->fd, NULL, NULL, NULL);
+        close(vhost->fd);
+    }
+}
+
+static void virtio_input_host_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
+
+    vic->realize       = virtio_input_host_realize;
+    vic->unrealize     = virtio_input_host_unrealize;
+}
+
+static void virtio_input_host_init(Object *obj)
+{
+    VirtIOInput *vinput = VIRTIO_INPUT(obj);
+
+    virtio_input_init_config(vinput, virtio_input_host_config);
+}
+
+static const TypeInfo virtio_input_host_info = {
+    .name          = TYPE_VIRTIO_INPUT_HOST,
+    .parent        = TYPE_VIRTIO_INPUT,
+    .instance_size = sizeof(VirtIOInputHost),
+    .instance_init = virtio_input_host_init,
+    .class_init    = virtio_input_host_class_init,
+};
+
+/* ----------------------------------------------------------------- */
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_input_host_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 9446d45..9f81fc0 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1547,6 +1547,14 @@ static Property virtio_input_ctrl_pci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static Property virtio_input_host_pci_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
+    DEFINE_PROP_STRING("evdev", VirtIOInputHostPCI, vdev.evdev),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
 {
     VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
@@ -1585,6 +1593,13 @@ static void virtio_input_ctrl_pci_class_init(ObjectClass *klass, void *data)
     dc->props = virtio_input_ctrl_pci_properties;
 }
 
+static void virtio_input_host_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = virtio_input_host_pci_properties;
+}
+
 static void virtio_keyboard_initfn(Object *obj)
 {
     VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
@@ -1613,6 +1628,13 @@ static void virtio_ctrl_initfn(Object *obj)
     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
 }
 
+static void virtio_host_initfn(Object *obj)
+{
+    VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_INPUT_HOST);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
 static const TypeInfo virtio_input_pci_info = {
     .name          = TYPE_VIRTIO_INPUT_PCI,
     .parent        = TYPE_VIRTIO_PCI,
@@ -1658,6 +1680,14 @@ static const TypeInfo virtio_ctrl_pci_info = {
     .class_init    = virtio_input_ctrl_pci_class_init,
 };
 
+static const TypeInfo virtio_host_pci_info = {
+    .name          = TYPE_VIRTIO_INPUT_HOST_PCI,
+    .parent        = TYPE_VIRTIO_INPUT_PCI,
+    .instance_size = sizeof(VirtIOInputHostPCI),
+    .instance_init = virtio_host_initfn,
+    .class_init    = virtio_input_host_pci_class_init,
+};
+
 /* virtio-pci-bus */
 
 static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -1708,6 +1738,7 @@ static void virtio_pci_register_types(void)
     type_register_static(&virtio_mouse_pci_info);
     type_register_static(&virtio_tablet_pci_info);
     type_register_static(&virtio_ctrl_pci_info);
+    type_register_static(&virtio_host_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 0c26e64..4c12770 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -43,6 +43,7 @@ typedef struct VirtIORngPCI VirtIORngPCI;
 typedef struct VirtIOInputPCI VirtIOInputPCI;
 typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
 typedef struct VirtIOInputCtrlPCI VirtIOInputCtrlPCI;
+typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
 
 /* virtio-pci-bus */
 
@@ -236,6 +237,15 @@ struct VirtIOInputCtrlPCI {
     VirtIOInputCtrl vdev;
 };
 
+#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
+#define VIRTIO_INPUT_HOST_PCI(obj) \
+        OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
+
+struct VirtIOInputHostPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOInputHost 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
index d753834..94ea405 100644
--- a/include/hw/virtio/virtio-input.h
+++ b/include/hw/virtio/virtio-input.h
@@ -73,6 +73,12 @@ typedef struct virtio_input_event {
 #define VIRTIO_INPUT_CTRL_GET_PARENT_CLASS(obj) \
         OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_CTRL)
 
+#define TYPE_VIRTIO_INPUT_HOST   "virtio-input-host"
+#define VIRTIO_INPUT_HOST(obj) \
+        OBJECT_CHECK(VirtIOInputHost, (obj), TYPE_VIRTIO_INPUT_HOST)
+#define VIRTIO_INPUT_HOST_GET_PARENT_CLASS(obj) \
+        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HOST)
+
 #define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
         DEFINE_PROP_STRING("serial", _state, _field.serial), \
         DEFINE_PROP_STRING("seat", _state, _field.seat)
@@ -82,6 +88,7 @@ typedef struct VirtIOInputClass VirtIOInputClass;
 typedef struct VirtIOInputConfig VirtIOInputConfig;
 typedef struct VirtIOInputHID VirtIOInputHID;
 typedef struct VirtIOInputCtrl VirtIOInputCtrl;
+typedef struct VirtIOInputHost VirtIOInputHost;
 
 struct virtio_input_conf {
     char *serial;
@@ -128,6 +135,12 @@ struct VirtIOInputCtrl {
     Notifier                          powerdown;
 };
 
+struct VirtIOInputHost {
+    VirtIOInput                       parent_obj;
+    char                              *evdev;
+    int                               fd;
+};
+
 void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
 void virtio_input_init_config(VirtIOInput *vinput,
                               virtio_input_config *config);
-- 
1.8.3.1

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

* Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices Gerd Hoffmann
@ 2014-04-10 10:55   ` Michael S. Tsirkin
  2014-04-10 11:47     ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 10:55 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 11:07:52AM +0200, Gerd Hoffmann wrote:
> This patch adds the virtio-input-hid base class and
> virtio-{keyboard,mouse,tablet} subclasses building on the base class.
> They are hooked up to the qemu input core and deliver input events
> to the guest like all other hid devices (ps/2 kbd, usb tablet, ...).
> 
> Using them is as simple as adding "-device virtio-tablet-pci" to your
> command line.  If you want add multiple devices but don't want waste
> a pci slot for each you can compose a multifunction device this way:
> 
> qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
>      -device virtio-tablet-pci,addr=0d.1,multifunction=on
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Hmm - that's interesting.
I was under the impression that a single pci function can be
a keyboard, mouse and tablet at the same time.

If they aren't why don't we assign distinct device IDs to them
after all?

> ---
>  hw/input/Makefile.objs           |   1 +
>  hw/input/virtio-input-hid.c      | 486 +++++++++++++++++++++++++++++++++++++++
>  hw/virtio/virtio-pci.c           |  68 ++++++
>  hw/virtio/virtio-pci.h           |  13 ++
>  include/hw/virtio/virtio-input.h |  22 ++
>  5 files changed, 590 insertions(+)
>  create mode 100644 hw/input/virtio-input-hid.c
> 
> diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
> index ee8bba9..0dae710 100644
> --- a/hw/input/Makefile.objs
> +++ b/hw/input/Makefile.objs
> @@ -10,6 +10,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
>  
>  ifeq ($(CONFIG_LINUX),y)
>  common-obj-$(CONFIG_VIRTIO) += virtio-input.o
> +common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
>  endif
>  
>  obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
> diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
> new file mode 100644
> index 0000000..2db993e
> --- /dev/null
> +++ b/hw/input/virtio-input-hid.c
> @@ -0,0 +1,486 @@
> +/*
> + * 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>
> +
> +#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard"
> +#define VIRTIO_ID_NAME_MOUSE    "QEMU Virtio Mouse"
> +#define VIRTIO_ID_NAME_TABLET   "QEMU Virtio Tablet"
> +
> +/* ----------------------------------------------------------------- */
> +
> +static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
> +    [Q_KEY_CODE_ESC]                 = KEY_ESC,
> +    [Q_KEY_CODE_1]                   = KEY_1,
> +    [Q_KEY_CODE_2]                   = KEY_2,
> +    [Q_KEY_CODE_3]                   = KEY_3,
> +    [Q_KEY_CODE_4]                   = KEY_4,
> +    [Q_KEY_CODE_5]                   = KEY_5,
> +    [Q_KEY_CODE_6]                   = KEY_6,
> +    [Q_KEY_CODE_7]                   = KEY_7,
> +    [Q_KEY_CODE_8]                   = KEY_8,
> +    [Q_KEY_CODE_9]                   = KEY_9,
> +    [Q_KEY_CODE_0]                   = KEY_0,
> +    [Q_KEY_CODE_MINUS]               = KEY_MINUS,
> +    [Q_KEY_CODE_EQUAL]               = KEY_EQUAL,
> +    [Q_KEY_CODE_BACKSPACE]           = KEY_BACKSPACE,
> +
> +    [Q_KEY_CODE_TAB]                 = KEY_TAB,
> +    [Q_KEY_CODE_Q]                   = KEY_Q,
> +    [Q_KEY_CODE_W]                   = KEY_W,
> +    [Q_KEY_CODE_E]                   = KEY_E,
> +    [Q_KEY_CODE_R]                   = KEY_R,
> +    [Q_KEY_CODE_T]                   = KEY_T,
> +    [Q_KEY_CODE_Y]                   = KEY_Y,
> +    [Q_KEY_CODE_U]                   = KEY_U,
> +    [Q_KEY_CODE_I]                   = KEY_I,
> +    [Q_KEY_CODE_O]                   = KEY_O,
> +    [Q_KEY_CODE_P]                   = KEY_P,
> +    [Q_KEY_CODE_BRACKET_LEFT]        = KEY_LEFTBRACE,
> +    [Q_KEY_CODE_BRACKET_RIGHT]       = KEY_RIGHTBRACE,
> +    [Q_KEY_CODE_RET]                 = KEY_ENTER,
> +
> +    [Q_KEY_CODE_CTRL]                = KEY_LEFTCTRL,
> +    [Q_KEY_CODE_A]                   = KEY_A,
> +    [Q_KEY_CODE_S]                   = KEY_S,
> +    [Q_KEY_CODE_D]                   = KEY_D,
> +    [Q_KEY_CODE_F]                   = KEY_F,
> +    [Q_KEY_CODE_G]                   = KEY_G,
> +    [Q_KEY_CODE_H]                   = KEY_H,
> +    [Q_KEY_CODE_J]                   = KEY_J,
> +    [Q_KEY_CODE_K]                   = KEY_K,
> +    [Q_KEY_CODE_L]                   = KEY_L,
> +    [Q_KEY_CODE_SEMICOLON]           = KEY_SEMICOLON,
> +    [Q_KEY_CODE_APOSTROPHE]          = KEY_APOSTROPHE,
> +    [Q_KEY_CODE_GRAVE_ACCENT]        = KEY_GRAVE,
> +
> +    [Q_KEY_CODE_SHIFT]               = KEY_LEFTSHIFT,
> +    [Q_KEY_CODE_BACKSLASH]           = KEY_BACKSLASH,
> +    [Q_KEY_CODE_LESS]                = KEY_102ND,
> +    [Q_KEY_CODE_Z]                   = KEY_Z,
> +    [Q_KEY_CODE_X]                   = KEY_X,
> +    [Q_KEY_CODE_C]                   = KEY_C,
> +    [Q_KEY_CODE_V]                   = KEY_V,
> +    [Q_KEY_CODE_B]                   = KEY_B,
> +    [Q_KEY_CODE_N]                   = KEY_N,
> +    [Q_KEY_CODE_M]                   = KEY_M,
> +    [Q_KEY_CODE_COMMA]               = KEY_COMMA,
> +    [Q_KEY_CODE_DOT]                 = KEY_DOT,
> +    [Q_KEY_CODE_SLASH]               = KEY_SLASH,
> +    [Q_KEY_CODE_SHIFT_R]             = KEY_RIGHTSHIFT,
> +
> +    [Q_KEY_CODE_ALT]                 = KEY_LEFTALT,
> +    [Q_KEY_CODE_SPC]                 = KEY_SPACE,
> +    [Q_KEY_CODE_CAPS_LOCK]           = KEY_CAPSLOCK,
> +
> +    [Q_KEY_CODE_F1]                  = KEY_F1,
> +    [Q_KEY_CODE_F2]                  = KEY_F2,
> +    [Q_KEY_CODE_F3]                  = KEY_F3,
> +    [Q_KEY_CODE_F4]                  = KEY_F4,
> +    [Q_KEY_CODE_F5]                  = KEY_F5,
> +    [Q_KEY_CODE_F6]                  = KEY_F6,
> +    [Q_KEY_CODE_F7]                  = KEY_F7,
> +    [Q_KEY_CODE_F8]                  = KEY_F8,
> +    [Q_KEY_CODE_F9]                  = KEY_F9,
> +    [Q_KEY_CODE_F10]                 = KEY_F10,
> +    [Q_KEY_CODE_NUM_LOCK]            = KEY_NUMLOCK,
> +    [Q_KEY_CODE_SCROLL_LOCK]         = KEY_SCROLLLOCK,
> +
> +    [Q_KEY_CODE_KP_0]                = KEY_KP0,
> +    [Q_KEY_CODE_KP_1]                = KEY_KP1,
> +    [Q_KEY_CODE_KP_2]                = KEY_KP2,
> +    [Q_KEY_CODE_KP_3]                = KEY_KP3,
> +    [Q_KEY_CODE_KP_4]                = KEY_KP4,
> +    [Q_KEY_CODE_KP_5]                = KEY_KP5,
> +    [Q_KEY_CODE_KP_6]                = KEY_KP6,
> +    [Q_KEY_CODE_KP_7]                = KEY_KP7,
> +    [Q_KEY_CODE_KP_8]                = KEY_KP8,
> +    [Q_KEY_CODE_KP_9]                = KEY_KP9,
> +    [Q_KEY_CODE_KP_SUBTRACT]         = KEY_KPMINUS,
> +    [Q_KEY_CODE_KP_ADD]              = KEY_KPPLUS,
> +    [Q_KEY_CODE_KP_DECIMAL]          = KEY_KPDOT,
> +    [Q_KEY_CODE_KP_ENTER]            = KEY_KPENTER,
> +    [Q_KEY_CODE_KP_DIVIDE]           = KEY_KPSLASH,
> +    [Q_KEY_CODE_KP_MULTIPLY]         = KEY_KPASTERISK,
> +
> +    [Q_KEY_CODE_F11]                 = KEY_F11,
> +    [Q_KEY_CODE_F12]                 = KEY_F12,
> +
> +    [Q_KEY_CODE_CTRL_R]              = KEY_RIGHTCTRL,
> +    [Q_KEY_CODE_SYSRQ]               = KEY_SYSRQ,
> +    [Q_KEY_CODE_ALT_R]               = KEY_RIGHTALT,
> +
> +    [Q_KEY_CODE_HOME]                = KEY_HOME,
> +    [Q_KEY_CODE_UP]                  = KEY_UP,
> +    [Q_KEY_CODE_PGUP]                = KEY_PAGEUP,
> +    [Q_KEY_CODE_LEFT]                = KEY_LEFT,
> +    [Q_KEY_CODE_RIGHT]               = KEY_RIGHT,
> +    [Q_KEY_CODE_END]                 = KEY_END,
> +    [Q_KEY_CODE_DOWN]                = KEY_DOWN,
> +    [Q_KEY_CODE_PGDN]                = KEY_PAGEDOWN,
> +    [Q_KEY_CODE_INSERT]              = KEY_INSERT,
> +    [Q_KEY_CODE_DELETE]              = KEY_DELETE,
> +
> +    [Q_KEY_CODE_META_L]              = KEY_LEFTMETA,
> +    [Q_KEY_CODE_META_R]              = KEY_RIGHTMETA,
> +    [Q_KEY_CODE_MENU]                = KEY_MENU,
> +};

OK these are values send to guest, right?
And they are from linux/input.h, right? But are these
reasonable in a cross-platform device?

E.g. Linux is pretty good at backwards compatibility
but less good at versioning.

That header says "Most of the keys/buttons are modeled after USB HUT
1.12" but as far as I could see the codes are not from HUT, correct?

Would it be a good idea to use codes from HUT directly?
This way we could extend functionality without adding lots of
text to the spec, simply by referring to HUT.

Also what defines the subset selected?
I'm a bit worried that we'll get into an endless cycle of spec
updates with each new button missing above.

> +
> +static const unsigned int keymap_button[INPUT_BUTTON_MAX] = {
> +    [INPUT_BUTTON_LEFT]              = BTN_LEFT,
> +    [INPUT_BUTTON_RIGHT]             = BTN_RIGHT,
> +    [INPUT_BUTTON_MIDDLE]            = BTN_MIDDLE,
> +    [INPUT_BUTTON_WHEEL_UP]          = BTN_GEAR_UP,
> +    [INPUT_BUTTON_WHEEL_DOWN]        = BTN_GEAR_DOWN,
> +};
> +
> +static const unsigned int axismap_rel[INPUT_AXIS_MAX] = {
> +    [INPUT_AXIS_X]                   = REL_X,
> +    [INPUT_AXIS_Y]                   = REL_Y,
> +};
> +
> +static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
> +    [INPUT_AXIS_X]                   = ABS_X,
> +    [INPUT_AXIS_Y]                   = ABS_Y,
> +};
> +

In the future, it seems like a good idea to report raw
multi-touch events to guests - this would need a different
interface along the lines of
Documentation/input/multi-touch-protocol.txt

How would we handle such an extension?
Do MT devices generate ST events as well so it's ok to just
filter out everything we don't recognize?


> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_input_key_config(VirtIOInput *vinput,
> +                                    const unsigned int *keymap,
> +                                    size_t mapsize)
> +{
> +    virtio_input_config keys;
> +    int i, bit, byte, bmax = 0;
> +
> +    memset(&keys, 0, sizeof(keys));
> +    for (i = 0; i < mapsize; i++) {
> +        bit = keymap[i];
> +        if (!bit) {
> +            continue;
> +        }
> +        byte = bit / 8;
> +        bit  = bit % 8;
> +        keys.u.bitmap[byte] |= (1 << bit);
> +        if (bmax < byte+1) {
> +            bmax = byte+1;
> +        }
> +    }
> +    keys.select = VIRTIO_INPUT_CFG_EV_BITS;
> +    keys.subsel = EV_KEY;
> +    keys.size   = bmax;
> +    virtio_input_add_config(vinput, &keys);
> +}
> +
> +static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
> +                                      InputEvent *evt)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    virtio_input_event event;
> +    int qcode;
> +
> +    switch (evt->kind) {
> +    case INPUT_EVENT_KIND_KEY:
> +        qcode = qemu_input_key_value_to_qcode(evt->key->key);
> +        if (qcode && keymap_qcode[qcode]) {
> +            event.type  = cpu_to_le16(EV_KEY);
> +            event.code  = cpu_to_le16(keymap_qcode[qcode]);
> +            event.value = cpu_to_le32(evt->key->down ? 1 : 0);
> +            virtio_input_send(vinput, &event);
> +        } else {
> +            if (evt->key->down) {
> +                fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
> +                        qcode, QKeyCode_lookup[qcode]);
> +            }
> +        }
> +        break;
> +    case INPUT_EVENT_KIND_BTN:
> +        if (keymap_button[evt->btn->button]) {
> +            event.type  = cpu_to_le16(EV_KEY);
> +            event.code  = cpu_to_le16(keymap_button[evt->btn->button]);
> +            event.value = cpu_to_le32(evt->btn->down ? 1 : 0);
> +            virtio_input_send(vinput, &event);
> +        } else {
> +            if (evt->btn->down) {
> +                fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
> +                        evt->btn->button, InputButton_lookup[evt->btn->button]);
> +            }
> +        }
> +        break;
> +    case INPUT_EVENT_KIND_REL:
> +        event.type  = cpu_to_le16(EV_REL);
> +        event.code  = cpu_to_le16(axismap_rel[evt->rel->axis]);
> +        event.value = cpu_to_le32(evt->rel->value);
> +        virtio_input_send(vinput, &event);
> +        break;
> +    case INPUT_EVENT_KIND_ABS:
> +        event.type  = cpu_to_le16(EV_ABS);
> +        event.code  = cpu_to_le16(axismap_abs[evt->abs->axis]);
> +        event.value = cpu_to_le32(evt->abs->value);
> +        virtio_input_send(vinput, &event);
> +        break;
> +    default:
> +        /* keep gcc happy */
> +        break;
> +    }
> +}
> +
> +static void virtio_input_handle_sync(DeviceState *dev)
> +{
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    virtio_input_event event = {
> +        .type  = cpu_to_le16(EV_SYN),
> +        .code  = cpu_to_le16(SYN_REPORT),
> +        .value = 0,
> +    };
> +
> +    virtio_input_send(vinput, &event);
> +    virtio_notify(vdev, vinput->evt);
> +}
> +
> +static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
> +    vhid->hs = qemu_input_handler_register(dev, vhid->handler);
> +}
> +
> +static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
> +    qemu_input_handler_unregister(vhid->hs);
> +}
> +
> +static void virtio_input_hid_change_active(VirtIOInput *vinput)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> +
> +    if (vinput->active) {
> +        qemu_input_handler_activate(vhid->hs);
> +    } else {
> +        qemu_input_handler_deactivate(vhid->hs);
> +    }
> +}
> +
> +static void virtio_input_hid_handle_status(VirtIOInput *vinput,
> +                                           virtio_input_event *event)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> +    int ledbit = 0;
> +
> +    switch (le16_to_cpu(event->type)) {
> +    case EV_LED:
> +        if (event->code == LED_NUML) {
> +            ledbit = QEMU_NUM_LOCK_LED;
> +        } else if (event->code == LED_CAPSL) {
> +            ledbit = QEMU_CAPS_LOCK_LED;
> +        } else if (event->code == LED_SCROLLL) {
> +            ledbit = QEMU_SCROLL_LOCK_LED;
> +        }
> +        if (event->value) {
> +            vhid->ledstate |= ledbit;
> +        } else {
> +            vhid->ledstate &= ~ledbit;
> +        }
> +        kbd_put_ledstate(vhid->ledstate);


What does this do? notice led light up on one keyboard and propagate
state to all keyboards?

> +        break;
> +    default:
> +        fprintf(stderr, "%s: unknown type %d\n", __func__,
> +                le16_to_cpu(event->type));
> +        break;
> +    }
> +}
> +
> +static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
> +
> +    vic->realize       = virtio_input_hid_realize;
> +    vic->unrealize     = virtio_input_hid_unrealize;
> +    vic->change_active = virtio_input_hid_change_active;
> +    vic->handle_status = virtio_input_hid_handle_status;
> +}
> +
> +static const TypeInfo virtio_input_hid_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HID,
> +    .parent        = TYPE_VIRTIO_INPUT,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .class_init    = virtio_input_hid_class_init,
> +    .abstract      = true,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_keyboard_handler = {
> +    .name  = VIRTIO_ID_NAME_KEYBOARD,
> +    .mask  = INPUT_EVENT_MASK_KEY,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_keyboard_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_KEYBOARD),
> +        .u.string  = VIRTIO_ID_NAME_KEYBOARD,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_REP,
> +        .size      = 1,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_LED,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
> +        },
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_keyboard_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_keyboard_handler;
> +    virtio_input_init_config(vinput, virtio_keyboard_config);
> +    virtio_input_key_config(vinput, keymap_qcode,
> +                            ARRAY_SIZE(keymap_qcode));
> +}
> +
> +static const TypeInfo virtio_keyboard_info = {
> +    .name          = TYPE_VIRTIO_KEYBOARD,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_keyboard_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_mouse_handler = {
> +    .name  = VIRTIO_ID_NAME_MOUSE,
> +    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_mouse_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_MOUSE),
> +        .u.string  = VIRTIO_ID_NAME_MOUSE,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_REL,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << REL_X) | (1 << REL_Y),
> +        },
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_mouse_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_mouse_handler;
> +    virtio_input_init_config(vinput, virtio_mouse_config);
> +    virtio_input_key_config(vinput, keymap_button,
> +                            ARRAY_SIZE(keymap_button));
> +}
> +
> +static const TypeInfo virtio_mouse_info = {
> +    .name          = TYPE_VIRTIO_MOUSE,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_mouse_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_tablet_handler = {
> +    .name  = VIRTIO_ID_NAME_TABLET,
> +    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_tablet_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_TABLET),
> +        .u.string  = VIRTIO_ID_NAME_TABLET,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_ABS,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << ABS_X) | (1 << ABS_Y),
> +        },
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
> +        .subsel    = ABS_X,
> +        .size      = sizeof(virtio_input_absinfo),
> +#if 0
> +        /* FIXME */
> +        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
> +#else
> +        .u.abs.max = INPUT_EVENT_ABS_SIZE,
> +#endif
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
> +        .subsel    = ABS_Y,
> +        .size      = sizeof(virtio_input_absinfo),
> +#if 0
> +        /* FIXME */
> +        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
> +#else
> +        .u.abs.max = INPUT_EVENT_ABS_SIZE,
> +#endif
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_tablet_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_tablet_handler;
> +    virtio_input_init_config(vinput, virtio_tablet_config);
> +    virtio_input_key_config(vinput, keymap_button,
> +                            ARRAY_SIZE(keymap_button));
> +}
> +
> +static const TypeInfo virtio_tablet_info = {
> +    .name          = TYPE_VIRTIO_TABLET,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_tablet_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_input_hid_info);
> +    type_register_static(&virtio_keyboard_info);
> +    type_register_static(&virtio_mouse_info);
> +    type_register_static(&virtio_tablet_info);
> +}
> +
> +type_init(virtio_register_types)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 5518192..b421c01 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1534,6 +1534,13 @@ static const TypeInfo virtio_rng_pci_info = {
>  
>  /* virtio-input-pci */
>  
> +static Property virtio_input_hid_pci_properties[] = {
> +    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
> +    DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
> +    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
>  {
>      VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
> @@ -1558,6 +1565,34 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
>      pcidev_k->class_id = PCI_CLASS_OTHERS;
>  }
>  
> +static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = virtio_input_hid_pci_properties;
> +}
> +
> +static void virtio_keyboard_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
> +static void virtio_mouse_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
> +static void virtio_tablet_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
>  static const TypeInfo virtio_input_pci_info = {
>      .name          = TYPE_VIRTIO_INPUT_PCI,
>      .parent        = TYPE_VIRTIO_PCI,
> @@ -1566,6 +1601,35 @@ static const TypeInfo virtio_input_pci_info = {
>      .abstract      = true,
>  };
>  
> +static const TypeInfo virtio_input_hid_pci_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .class_init    = virtio_input_hid_pci_class_init,
> +    .abstract      = true,
> +};
> +
> +static const TypeInfo virtio_keyboard_pci_info = {
> +    .name          = TYPE_VIRTIO_KEYBOARD_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_keyboard_initfn,
> +};
> +
> +static const TypeInfo virtio_mouse_pci_info = {
> +    .name          = TYPE_VIRTIO_MOUSE_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_mouse_initfn,
> +};
> +
> +static const TypeInfo virtio_tablet_pci_info = {
> +    .name          = TYPE_VIRTIO_TABLET_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_tablet_initfn,
> +};
> +
>  /* virtio-pci-bus */
>  
>  static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
> @@ -1611,6 +1675,10 @@ 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_input_hid_pci_info);
> +    type_register_static(&virtio_keyboard_pci_info);
> +    type_register_static(&virtio_mouse_pci_info);
> +    type_register_static(&virtio_tablet_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 f1e75ad..f615ae6 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -41,6 +41,7 @@ typedef struct VirtIONetPCI VirtIONetPCI;
>  typedef struct VHostSCSIPCI VHostSCSIPCI;
>  typedef struct VirtIORngPCI VirtIORngPCI;
>  typedef struct VirtIOInputPCI VirtIOInputPCI;
> +typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
>  
>  /* virtio-pci-bus */
>  
> @@ -213,6 +214,18 @@ struct VirtIOInputPCI {
>      VirtIOInput vdev;
>  };
>  
> +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
> +#define TYPE_VIRTIO_KEYBOARD_PCI  "virtio-keyboard-pci"
> +#define TYPE_VIRTIO_MOUSE_PCI     "virtio-mouse-pci"
> +#define TYPE_VIRTIO_TABLET_PCI    "virtio-tablet-pci"
> +#define VIRTIO_INPUT_HID_PCI(obj) \
> +        OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
> +
> +struct VirtIOInputHIDPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOInputHID 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
> index 5d37a70..4b819c3 100644
> --- a/include/hw/virtio/virtio-input.h
> +++ b/include/hw/virtio/virtio-input.h
> @@ -57,9 +57,24 @@ typedef struct virtio_input_event {
>  #define VIRTIO_INPUT_CLASS(klass) \
>          OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT)
>  
> +#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid"
> +#define TYPE_VIRTIO_KEYBOARD  "virtio-keyboard"
> +#define TYPE_VIRTIO_MOUSE     "virtio-mouse"
> +#define TYPE_VIRTIO_TABLET    "virtio-tablet"
> +
> +#define VIRTIO_INPUT_HID(obj) \
> +        OBJECT_CHECK(VirtIOInputHID, (obj), TYPE_VIRTIO_INPUT_HID)
> +#define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
> +        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
> +
> +#define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
> +        DEFINE_PROP_STRING("serial", _state, _field.serial), \
> +        DEFINE_PROP_STRING("seat", _state, _field.seat)
> +
>  typedef struct VirtIOInput VirtIOInput;
>  typedef struct VirtIOInputClass VirtIOInputClass;
>  typedef struct VirtIOInputConfig VirtIOInputConfig;
> +typedef struct VirtIOInputHID VirtIOInputHID;
>  
>  struct virtio_input_conf {
>      char *serial;
> @@ -94,6 +109,13 @@ struct VirtIOInputClass {
>      void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event);
>  };
>  
> +struct VirtIOInputHID {
> +    VirtIOInput                       parent_obj;
> +    QemuInputHandler                  *handler;
> +    QemuInputHandlerState             *hs;
> +    int                               ledstate;
> +};
> +
>  void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
>  void virtio_input_init_config(VirtIOInput *vinput,
>                                virtio_input_config *config);
> -- 
> 1.8.3.1

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

* Re: [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough Gerd Hoffmann
@ 2014-04-10 11:05   ` Michael S. Tsirkin
  2014-04-10 11:57     ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 11:05 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 11:07:54AM +0200, Gerd Hoffmann wrote:
> This allows to assign host input devices to the guest:
> 
> qemu -device virto-input-host-pci,evdev=/dev/input/event<nr>
> 
> The guest gets exclusive access to the input device, so be careful
> with assigning the keyboard if you have only one connected to your
> machine.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  hw/input/Makefile.objs           |   1 +
>  hw/input/virtio-input-host.c     | 174 +++++++++++++++++++++++++++++++++++++++
>  hw/virtio/virtio-pci.c           |  31 +++++++
>  hw/virtio/virtio-pci.h           |  10 +++
>  include/hw/virtio/virtio-input.h |  13 +++
>  5 files changed, 229 insertions(+)
>  create mode 100644 hw/input/virtio-input-host.c
> 
> diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
> index 0179154..9461b37 100644
> --- a/hw/input/Makefile.objs
> +++ b/hw/input/Makefile.objs
> @@ -12,6 +12,7 @@ ifeq ($(CONFIG_LINUX),y)
>  common-obj-$(CONFIG_VIRTIO) += virtio-input.o
>  common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
>  common-obj-$(CONFIG_VIRTIO) += virtio-input-control.o
> +common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
>  endif
>  
>  obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
> diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
> new file mode 100644
> index 0000000..663d967
> --- /dev/null
> +++ b/hw/input/virtio-input-host.c
> @@ -0,0 +1,174 @@
> +/*
> + * 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-common.h"
> +#include "qemu/sockets.h"
> +
> +#include "hw/qdev.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-input.h"
> +
> +#include "ui/console.h"
> +
> +#include <linux/input.h>
> +
> +/* ----------------------------------------------------------------- */
> +
> +static struct virtio_input_config virtio_input_host_config[] = {
> +    { /* empty list */ },
> +};
> +
> +static void virtio_input_host_event(void *opaque)
> +{
> +    VirtIOInputHost *vhost = opaque;

I'd prefer a name that does not imply
vhost infrastructure - which is an out of process QEMU backend
(kernel or another userspace process) accessing guest
memory directly.
This one is completely in-process.

> +    VirtIOInput *vinput = VIRTIO_INPUT(vhost);
> +    struct virtio_input_event virtio;
> +    struct input_event evdev;
> +    bool notify = false;
> +    int rc;
> +
> +    for (;;) {

You might want to limit this, requeue if there's
a storm of events.

> +        rc = read(vhost->fd, &evdev, sizeof(evdev));
> +        if (rc != sizeof(evdev)) {
> +            break;
> +        }
> +
> +        virtio.type  = cpu_to_le16(evdev.type);
> +        virtio.code  = cpu_to_le16(evdev.code);
> +        virtio.value = cpu_to_le32(evdev.value);
> +        virtio_input_send(vinput, &virtio);
> +
> +        if (evdev.type == EV_SYN) {
> +            notify = true;
> +        }
> +    }
> +
> +    if (notify) {
> +        virtio_notify(VIRTIO_DEVICE(vhost), vinput->evt);
> +    }
> +}
> +
> +static void virtio_input_bits_config(VirtIOInputHost *vhost,
> +                                     int type, int count)
> +{
> +    virtio_input_config bits;
> +    int rc, i, size = 0;
> +
> +    memset(&bits, 0, sizeof(bits));
> +    rc = ioctl(vhost->fd, EVIOCGBIT(type, count/8), bits.u.bitmap);
> +    if (rc < 0) {
> +        return;
> +    }
> +
> +    for (i = 0; i < count/8; i++) {
> +        if (bits.u.bitmap[i]) {
> +            size = i+1;
> +        }
> +    }
> +    if (size == 0) {
> +        return;
> +    }
> +
> +    bits.select = VIRTIO_INPUT_CFG_EV_BITS;
> +    bits.subsel = type;
> +    bits.size   = size;
> +    virtio_input_add_config(VIRTIO_INPUT(vhost), &bits);
> +}
> +
> +static void virtio_input_host_realize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHost *vhost = VIRTIO_INPUT_HOST(dev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    virtio_input_config id;
> +    int rc, ver;
> +
> +    if (!vhost->evdev) {
> +        error_setg(errp, "evdev property is required");
> +        return;
> +    }
> +
> +    vhost->fd = open(vhost->evdev, O_RDWR);
> +    if (vhost->fd < 0)  {
> +        error_setg_file_open(errp, errno, vhost->evdev);
> +        return;
> +    }
> +    qemu_set_nonblock(vhost->fd);
> +
> +    rc = ioctl(vhost->fd, EVIOCGVERSION, &ver);
> +    if (rc < 0) {
> +        error_setg(errp, "%s: is not an evdev device", vhost->evdev);
> +        goto err_close;
> +    }

Hmm is that all?
Don't we want to report versioning info to guests?


> +
> +    rc = ioctl(vhost->fd, EVIOCGRAB, 1);
> +    if (rc < 0) {
> +        error_setg_errno(errp, errno, "%s: failed to get exclusive access",
> +                         vhost->evdev);
> +        goto err_close;
> +    }
> +
> +    memset(&id, 0, sizeof(id));
> +    ioctl(vhost->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string);
> +    id.select = VIRTIO_INPUT_CFG_ID_NAME;
> +    id.size = strlen(id.u.string);
> +    virtio_input_add_config(vinput, &id);
> +
> +    virtio_input_bits_config(vhost, EV_KEY, KEY_CNT);
> +    virtio_input_bits_config(vhost, EV_REL, REL_CNT);
> +    virtio_input_bits_config(vhost, EV_ABS, ABS_CNT);
> +    virtio_input_bits_config(vhost, EV_MSC, MSC_CNT);
> +    virtio_input_bits_config(vhost, EV_SW,  SW_CNT);
> +
> +    qemu_set_fd_handler(vhost->fd, virtio_input_host_event, NULL, vhost);
> +    return;
> +
> +err_close:
> +    close(vhost->fd);
> +    vhost->fd = -1;
> +    return;
> +}
> +
> +static void virtio_input_host_unrealize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHost *vhost = VIRTIO_INPUT_HOST(dev);
> +
> +    if (vhost->fd > 0) {
> +        qemu_set_fd_handler(vhost->fd, NULL, NULL, NULL);
> +        close(vhost->fd);
> +    }
> +}
> +
> +static void virtio_input_host_class_init(ObjectClass *klass, void *data)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
> +
> +    vic->realize       = virtio_input_host_realize;
> +    vic->unrealize     = virtio_input_host_unrealize;
> +}
> +
> +static void virtio_input_host_init(Object *obj)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    virtio_input_init_config(vinput, virtio_input_host_config);
> +}
> +
> +static const TypeInfo virtio_input_host_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HOST,
> +    .parent        = TYPE_VIRTIO_INPUT,
> +    .instance_size = sizeof(VirtIOInputHost),
> +    .instance_init = virtio_input_host_init,
> +    .class_init    = virtio_input_host_class_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_input_host_info);
> +}
> +
> +type_init(virtio_register_types)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 9446d45..9f81fc0 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1547,6 +1547,14 @@ static Property virtio_input_ctrl_pci_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> +static Property virtio_input_host_pci_properties[] = {
> +    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
> +    DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
> +    DEFINE_PROP_STRING("evdev", VirtIOInputHostPCI, vdev.evdev),
> +    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
>  {
>      VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
> @@ -1585,6 +1593,13 @@ static void virtio_input_ctrl_pci_class_init(ObjectClass *klass, void *data)
>      dc->props = virtio_input_ctrl_pci_properties;
>  }
>  
> +static void virtio_input_host_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = virtio_input_host_pci_properties;
> +}
> +
>  static void virtio_keyboard_initfn(Object *obj)
>  {
>      VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> @@ -1613,6 +1628,13 @@ static void virtio_ctrl_initfn(Object *obj)
>      object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
>  }
>  
> +static void virtio_host_initfn(Object *obj)
> +{
> +    VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_INPUT_HOST);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
>  static const TypeInfo virtio_input_pci_info = {
>      .name          = TYPE_VIRTIO_INPUT_PCI,
>      .parent        = TYPE_VIRTIO_PCI,
> @@ -1658,6 +1680,14 @@ static const TypeInfo virtio_ctrl_pci_info = {
>      .class_init    = virtio_input_ctrl_pci_class_init,
>  };
>  
> +static const TypeInfo virtio_host_pci_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HOST_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_PCI,
> +    .instance_size = sizeof(VirtIOInputHostPCI),
> +    .instance_init = virtio_host_initfn,
> +    .class_init    = virtio_input_host_pci_class_init,
> +};
> +
>  /* virtio-pci-bus */
>  
>  static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
> @@ -1708,6 +1738,7 @@ static void virtio_pci_register_types(void)
>      type_register_static(&virtio_mouse_pci_info);
>      type_register_static(&virtio_tablet_pci_info);
>      type_register_static(&virtio_ctrl_pci_info);
> +    type_register_static(&virtio_host_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 0c26e64..4c12770 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -43,6 +43,7 @@ typedef struct VirtIORngPCI VirtIORngPCI;
>  typedef struct VirtIOInputPCI VirtIOInputPCI;
>  typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
>  typedef struct VirtIOInputCtrlPCI VirtIOInputCtrlPCI;
> +typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
>  
>  /* virtio-pci-bus */
>  
> @@ -236,6 +237,15 @@ struct VirtIOInputCtrlPCI {
>      VirtIOInputCtrl vdev;
>  };
>  
> +#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
> +#define VIRTIO_INPUT_HOST_PCI(obj) \
> +        OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
> +
> +struct VirtIOInputHostPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOInputHost 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
> index d753834..94ea405 100644
> --- a/include/hw/virtio/virtio-input.h
> +++ b/include/hw/virtio/virtio-input.h
> @@ -73,6 +73,12 @@ typedef struct virtio_input_event {
>  #define VIRTIO_INPUT_CTRL_GET_PARENT_CLASS(obj) \
>          OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_CTRL)
>  
> +#define TYPE_VIRTIO_INPUT_HOST   "virtio-input-host"
> +#define VIRTIO_INPUT_HOST(obj) \
> +        OBJECT_CHECK(VirtIOInputHost, (obj), TYPE_VIRTIO_INPUT_HOST)
> +#define VIRTIO_INPUT_HOST_GET_PARENT_CLASS(obj) \
> +        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HOST)
> +
>  #define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
>          DEFINE_PROP_STRING("serial", _state, _field.serial), \
>          DEFINE_PROP_STRING("seat", _state, _field.seat)
> @@ -82,6 +88,7 @@ typedef struct VirtIOInputClass VirtIOInputClass;
>  typedef struct VirtIOInputConfig VirtIOInputConfig;
>  typedef struct VirtIOInputHID VirtIOInputHID;
>  typedef struct VirtIOInputCtrl VirtIOInputCtrl;
> +typedef struct VirtIOInputHost VirtIOInputHost;
>  
>  struct virtio_input_conf {
>      char *serial;
> @@ -128,6 +135,12 @@ struct VirtIOInputCtrl {
>      Notifier                          powerdown;
>  };
>  
> +struct VirtIOInputHost {
> +    VirtIOInput                       parent_obj;
> +    char                              *evdev;
> +    int                               fd;
> +};
> +
>  void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
>  void virtio_input_init_config(VirtIOInput *vinput,
>                                virtio_input_config *config);
> -- 
> 1.8.3.1

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

* Re: [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device Gerd Hoffmann
@ 2014-04-10 11:05   ` Michael S. Tsirkin
  2014-04-10 12:10     ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 11:05 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 11:07:53AM +0200, Gerd Hoffmann wrote:
> Device for sending non-input control messages to the guest.  For now
> this is only a single event: shutdown requests are sent as power button
> press to the guest.
> 
> Possible other use is signaling sound volume changes to the guest (via
> EV_ABS / ABS_VOLUME).  I expect we'll find more over time.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Why not use a keyboard device for this?

> ---
>  hw/input/Makefile.objs           |   1 +
>  hw/input/virtio-input-control.c  | 112 +++++++++++++++++++++++++++++++++++++++
>  hw/virtio/virtio-pci.c           |  29 ++++++++++
>  hw/virtio/virtio-pci.h           |  10 ++++
>  include/hw/virtio/virtio-input.h |  12 +++++
>  5 files changed, 164 insertions(+)
>  create mode 100644 hw/input/virtio-input-control.c
> 
> diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
> index 0dae710..0179154 100644
> --- a/hw/input/Makefile.objs
> +++ b/hw/input/Makefile.objs
> @@ -11,6 +11,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
>  ifeq ($(CONFIG_LINUX),y)
>  common-obj-$(CONFIG_VIRTIO) += virtio-input.o
>  common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
> +common-obj-$(CONFIG_VIRTIO) += virtio-input-control.o
>  endif
>  
>  obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
> diff --git a/hw/input/virtio-input-control.c b/hw/input/virtio-input-control.c
> new file mode 100644
> index 0000000..3e439e6
> --- /dev/null
> +++ b/hw/input/virtio-input-control.c
> @@ -0,0 +1,112 @@
> +/*
> + * 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>
> +
> +#define VIRTIO_ID_NAME_CTRL "QEMU Virtio Control Panel"
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_input_key_config(VirtIOInput *vinput)
> +{
> +    static const int keylist[] = { KEY_POWER };
> +    virtio_input_config keys;
> +    int i, bit, byte, bmax = 0;
> +
> +    memset(&keys, 0, sizeof(keys));
> +    for (i = 0; i < ARRAY_SIZE(keylist); i++) {
> +        byte = keylist[i] / 8;
> +        bit  = keylist[i] % 8;
> +        keys.u.bitmap[byte] |= (1 << bit);
> +        if (bmax < byte+1) {
> +            bmax = byte+1;
> +        }
> +    }
> +    keys.select = VIRTIO_INPUT_CFG_EV_BITS;
> +    keys.subsel = EV_KEY;
> +    keys.size   = bmax;
> +    virtio_input_add_config(vinput, &keys);
> +}
> +
> +static void virtio_input_ctrl_keypress(VirtIOInput *vinput, int keycode)
> +{
> +    virtio_input_event key_down = {
> +        .type  = cpu_to_le16(EV_KEY),
> +        .code  = cpu_to_le16(keycode),
> +        .value = 1,
> +    };
> +    virtio_input_event key_up = {
> +        .type  = cpu_to_le16(EV_KEY),
> +        .code  = cpu_to_le16(keycode),
> +        .value = 0,
> +    };
> +    virtio_input_event sync = {
> +        .type  = cpu_to_le16(EV_SYN),
> +        .code  = cpu_to_le16(SYN_REPORT),
> +        .value = 0,
> +    };
> +
> +    virtio_input_send(vinput, &key_down);
> +    virtio_input_send(vinput, &sync);
> +    virtio_input_send(vinput, &key_up);
> +    virtio_input_send(vinput, &sync);
> +    virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
> +}
> +
> +static void virtio_input_ctrl_powerdown(Notifier *n, void *opaque)
> +{
> +    VirtIOInputCtrl *vctrl =
> +        container_of(n, VirtIOInputCtrl, powerdown);
> +
> +    virtio_input_ctrl_keypress(VIRTIO_INPUT(vctrl), KEY_POWER);
> +}
> +
> +/* ----------------------------------------------------------------- */
> +
> +static struct virtio_input_config virtio_ctrl_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_CTRL),
> +        .u.string  = VIRTIO_ID_NAME_CTRL,
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_ctrl_init(Object *obj)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +    VirtIOInputCtrl *vctrl = VIRTIO_INPUT_CTRL(obj);
> +
> +    virtio_input_init_config(vinput, virtio_ctrl_config);
> +    virtio_input_key_config(vinput);
> +
> +    vctrl->powerdown.notify = virtio_input_ctrl_powerdown;
> +    qemu_register_powerdown_notifier(&vctrl->powerdown);
> +}
> +
> +static const TypeInfo virtio_ctrl_info = {
> +    .name          = TYPE_VIRTIO_INPUT_CTRL,
> +    .parent        = TYPE_VIRTIO_INPUT,
> +    .instance_size = sizeof(VirtIOInputCtrl),
> +    .instance_init = virtio_ctrl_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_ctrl_info);
> +}
> +
> +type_init(virtio_register_types)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index b421c01..9446d45 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1541,6 +1541,12 @@ static Property virtio_input_hid_pci_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> +static Property virtio_input_ctrl_pci_properties[] = {
> +    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
> +    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
>  {
>      VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
> @@ -1572,6 +1578,13 @@ static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
>      dc->props = virtio_input_hid_pci_properties;
>  }
>  
> +static void virtio_input_ctrl_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = virtio_input_ctrl_pci_properties;
> +}
> +
>  static void virtio_keyboard_initfn(Object *obj)
>  {
>      VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> @@ -1593,6 +1606,13 @@ static void virtio_tablet_initfn(Object *obj)
>      object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
>  }
>  
> +static void virtio_ctrl_initfn(Object *obj)
> +{
> +    VirtIOInputCtrlPCI *dev = VIRTIO_INPUT_CTRL_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_INPUT_CTRL);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
>  static const TypeInfo virtio_input_pci_info = {
>      .name          = TYPE_VIRTIO_INPUT_PCI,
>      .parent        = TYPE_VIRTIO_PCI,
> @@ -1630,6 +1650,14 @@ static const TypeInfo virtio_tablet_pci_info = {
>      .instance_init = virtio_tablet_initfn,
>  };
>  
> +static const TypeInfo virtio_ctrl_pci_info = {
> +    .name          = TYPE_VIRTIO_INPUT_CTRL_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_PCI,
> +    .instance_size = sizeof(VirtIOInputCtrlPCI),
> +    .instance_init = virtio_ctrl_initfn,
> +    .class_init    = virtio_input_ctrl_pci_class_init,
> +};
> +
>  /* virtio-pci-bus */
>  
>  static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
> @@ -1679,6 +1707,7 @@ static void virtio_pci_register_types(void)
>      type_register_static(&virtio_keyboard_pci_info);
>      type_register_static(&virtio_mouse_pci_info);
>      type_register_static(&virtio_tablet_pci_info);
> +    type_register_static(&virtio_ctrl_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 f615ae6..0c26e64 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -42,6 +42,7 @@ typedef struct VHostSCSIPCI VHostSCSIPCI;
>  typedef struct VirtIORngPCI VirtIORngPCI;
>  typedef struct VirtIOInputPCI VirtIOInputPCI;
>  typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
> +typedef struct VirtIOInputCtrlPCI VirtIOInputCtrlPCI;
>  
>  /* virtio-pci-bus */
>  
> @@ -226,6 +227,15 @@ struct VirtIOInputHIDPCI {
>      VirtIOInputHID vdev;
>  };
>  
> +#define TYPE_VIRTIO_INPUT_CTRL_PCI "virtio-input-control-pci"
> +#define VIRTIO_INPUT_CTRL_PCI(obj) \
> +        OBJECT_CHECK(VirtIOInputCtrlPCI, (obj), TYPE_VIRTIO_INPUT_CTRL_PCI)
> +
> +struct VirtIOInputCtrlPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOInputCtrl 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
> index 4b819c3..d753834 100644
> --- a/include/hw/virtio/virtio-input.h
> +++ b/include/hw/virtio/virtio-input.h
> @@ -67,6 +67,12 @@ typedef struct virtio_input_event {
>  #define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
>          OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
>  
> +#define TYPE_VIRTIO_INPUT_CTRL   "virtio-input-control"
> +#define VIRTIO_INPUT_CTRL(obj) \
> +        OBJECT_CHECK(VirtIOInputCtrl, (obj), TYPE_VIRTIO_INPUT_CTRL)
> +#define VIRTIO_INPUT_CTRL_GET_PARENT_CLASS(obj) \
> +        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_CTRL)
> +
>  #define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
>          DEFINE_PROP_STRING("serial", _state, _field.serial), \
>          DEFINE_PROP_STRING("seat", _state, _field.seat)
> @@ -75,6 +81,7 @@ typedef struct VirtIOInput VirtIOInput;
>  typedef struct VirtIOInputClass VirtIOInputClass;
>  typedef struct VirtIOInputConfig VirtIOInputConfig;
>  typedef struct VirtIOInputHID VirtIOInputHID;
> +typedef struct VirtIOInputCtrl VirtIOInputCtrl;
>  
>  struct virtio_input_conf {
>      char *serial;
> @@ -116,6 +123,11 @@ struct VirtIOInputHID {
>      int                               ledstate;
>  };
>  
> +struct VirtIOInputCtrl {
> +    VirtIOInput                       parent_obj;
> +    Notifier                          powerdown;
> +};
> +
>  void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
>  void virtio_input_init_config(VirtIOInput *vinput,
>                                virtio_input_config *config);
> -- 
> 1.8.3.1

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

* Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
  2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class Gerd Hoffmann
@ 2014-04-10 11:06   ` Michael S. Tsirkin
  2014-04-10 12:22     ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 11:06 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 11:07:51AM +0200, Gerd Hoffmann wrote:
> 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;

Looks scary.

> +    }
> +    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

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

* Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
  2014-04-10 10:55   ` Michael S. Tsirkin
@ 2014-04-10 11:47     ` Gerd Hoffmann
  2014-04-10 15:14       ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10 11:47 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Do, 2014-04-10 at 13:55 +0300, Michael S. Tsirkin wrote:
> On Thu, Apr 10, 2014 at 11:07:52AM +0200, Gerd Hoffmann wrote:
> > This patch adds the virtio-input-hid base class and
> > virtio-{keyboard,mouse,tablet} subclasses building on the base class.
> > They are hooked up to the qemu input core and deliver input events
> > to the guest like all other hid devices (ps/2 kbd, usb tablet, ...).
> > 
> > Using them is as simple as adding "-device virtio-tablet-pci" to your
> > command line.  If you want add multiple devices but don't want waste
> > a pci slot for each you can compose a multifunction device this way:
> > 
> > qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
> >      -device virtio-tablet-pci,addr=0d.1,multifunction=on
> > 
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> Hmm - that's interesting.
> I was under the impression that a single pci function can be
> a keyboard, mouse and tablet at the same time.

It is possible to create a device supporting both keyboard and
mouse/tablet events.  Which will also show up as single input device in
the guest then.  People and software tends to not expect that though, so
I think it is better to keep them separate.

> If they aren't why don't we assign distinct device IDs to them
> after all?

pci device ids I assume?  Sure, we can do that.  Will make lspci output
a bit more informative (no need to check /proc/bus/input/devices to
figure what kind of input device it is).

> > +    [Q_KEY_CODE_META_L]              = KEY_LEFTMETA,
> > +    [Q_KEY_CODE_META_R]              = KEY_RIGHTMETA,
> > +    [Q_KEY_CODE_MENU]                = KEY_MENU,
> > +};
> 
> OK these are values send to guest, right?

Yes.

> And they are from linux/input.h, right? But are these
> reasonable in a cross-platform device?

Can't see strong reasons speaking against it.  It's kernel/userspace
API, therefore stable.  There are keycodes defined for pretty much
anything you can think of.

linux guest code is dead simple.  For other guests supporting it
shouldn't be that hard too, they basically need a mapping table to map
the linux KEY_* codes into their internal representation.

> E.g. Linux is pretty good at backwards compatibility
> but less good at versioning.

--verbose please.

> That header says "Most of the keys/buttons are modeled after USB HUT
> 1.12" but as far as I could see the codes are not from HUT, correct?

No, the codes are different.

> Would it be a good idea to use codes from HUT directly?
> This way we could extend functionality without adding lots of
> text to the spec, simply by referring to HUT.

I want to simply refer to linux/input.h in the spec.

> Also what defines the subset selected?

All keys in linux/input.h are supported by the virtio input protocol.

The current qemu kbd emulation covers all keys qemu knows (see QKeyCode
in qapi-schema.json).

> > +static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
> > +    [INPUT_AXIS_X]                   = ABS_X,
> > +    [INPUT_AXIS_Y]                   = ABS_Y,
> > +};
> > +
> 
> In the future, it seems like a good idea to report raw
> multi-touch events to guests - this would need a different
> interface along the lines of
> Documentation/input/multi-touch-protocol.txt

Should be no big deal.  Not looked at that deeply yet due to lack of
test hardware, but I think all we need is mapping the info from
EVIOCGMTSLOTS into config space, simliar to how it is done for
EVIOCGABS.

> Do MT devices generate ST events as well so it's ok to just
> filter out everything we don't recognize?

Yes, as far I know both mt and st events are generated.

> > +static void virtio_input_hid_handle_status(VirtIOInput *vinput,
> > +                                           virtio_input_event *event)
> > +{
> > +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> > +    int ledbit = 0;
> > +
> > +    switch (le16_to_cpu(event->type)) {
> > +    case EV_LED:
> > +        if (event->code == LED_NUML) {
> > +            ledbit = QEMU_NUM_LOCK_LED;
> > +        } else if (event->code == LED_CAPSL) {
> > +            ledbit = QEMU_CAPS_LOCK_LED;
> > +        } else if (event->code == LED_SCROLLL) {
> > +            ledbit = QEMU_SCROLL_LOCK_LED;
> > +        }
> > +        if (event->value) {
> > +            vhid->ledstate |= ledbit;
> > +        } else {
> > +            vhid->ledstate &= ~ledbit;
> > +        }
> > +        kbd_put_ledstate(vhid->ledstate);
> 
> What does this do? notice led light up on one keyboard and propagate
> state to all keyboards?

Notify everybody interested in about kbd led changes.  ps/2+usb kbd
emulations do the same.

It is used by vnc for example, to make sure capslock/numlock state
between guest and host stay in sync.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough
  2014-04-10 11:05   ` Michael S. Tsirkin
@ 2014-04-10 11:57     ` Gerd Hoffmann
  2014-04-10 15:16       ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10 11:57 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

  Hi,

> > +static void virtio_input_host_event(void *opaque)
> > +{
> > +    VirtIOInputHost *vhost = opaque;
> 
> I'd prefer a name that does not imply
> vhost infrastructure

ok.

> > +    rc = ioctl(vhost->fd, EVIOCGVERSION, &ver);
> > +    if (rc < 0) {
> > +        error_setg(errp, "%s: is not an evdev device", vhost->evdev);
> > +        goto err_close;
> > +    }
> 
> Hmm is that all?
> Don't we want to report versioning info to guests?

I guess the only thing we might want to here is bail out in case the
major version is != 1 (which implies a incompatible change).  The major
version didn't change so far though, and I think it is highly unlikely
that it'll ever happen.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device
  2014-04-10 11:05   ` Michael S. Tsirkin
@ 2014-04-10 12:10     ` Gerd Hoffmann
  2014-04-10 15:20       ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10 12:10 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Do, 2014-04-10 at 14:05 +0300, Michael S. Tsirkin wrote:
> On Thu, Apr 10, 2014 at 11:07:53AM +0200, Gerd Hoffmann wrote:
> > Device for sending non-input control messages to the guest.  For now
> > this is only a single event: shutdown requests are sent as power button
> > press to the guest.
> > 
> > Possible other use is signaling sound volume changes to the guest (via
> > EV_ABS / ABS_VOLUME).  I expect we'll find more over time.
> > 
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> Why not use a keyboard device for this?

>From the guests point of view this is looks like a keyboard.  A keyboard
with a single key: power.

I prefer a clear separation between devices being feed from user input
and the control device which monitors other event sources (powerdown
notifier).

There is no fundamental reason why this can't live in the emulated
keyboard though.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
  2014-04-10 11:06   ` Michael S. Tsirkin
@ 2014-04-10 12:22     ` Gerd Hoffmann
  2014-04-10 14:56       ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-10 12:22 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Do, 2014-04-10 at 14:06 +0300, Michael S. Tsirkin wrote:
> > +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;
> 
> Looks scary.
> 

It's not different from other input devices.  No buffer space -> drop
event.  What else do you think should happen?  We could signal "you lost
events" to the guest, but I suspect that buys us nothing.  Other input
devices don't have that capability, so guests are likely not prepared to
handle the situation.  Also, there isn't much they can actually do about
it.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
  2014-04-10 12:22     ` Gerd Hoffmann
@ 2014-04-10 14:56       ` Michael S. Tsirkin
  2014-04-11  7:17         ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 14:56 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 02:22:17PM +0200, Gerd Hoffmann wrote:
> On Do, 2014-04-10 at 14:06 +0300, Michael S. Tsirkin wrote:
> > > +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;
> > 
> > Looks scary.
> > 
> 
> It's not different from other input devices.  No buffer space -> drop
> event.  What else do you think should happen?  We could signal "you lost
> events" to the guest, but I suspect that buys us nothing.  Other input
> devices don't have that capability, so guests are likely not prepared to
> handle the situation.

For assigned device input events, how about we don't read events off the
input device file if there's nowhere to put them?

For things like sync that qemu generates, I suspect it's a good idea
to buffer them in QEMU otherwise guest will get out of sync, right?

I'm also pretty sure whoever's running the hypervisor does not
want to see the fprintf.

> Also, there isn't much they can actually do about
> it.
> 
> cheers,
>   Gerd



-- 
MST

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

* Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
  2014-04-10 11:47     ` Gerd Hoffmann
@ 2014-04-10 15:14       ` Michael S. Tsirkin
  2014-04-11  8:01         ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 15:14 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 01:47:08PM +0200, Gerd Hoffmann wrote:
> On Do, 2014-04-10 at 13:55 +0300, Michael S. Tsirkin wrote:
> > On Thu, Apr 10, 2014 at 11:07:52AM +0200, Gerd Hoffmann wrote:
> > > This patch adds the virtio-input-hid base class and
> > > virtio-{keyboard,mouse,tablet} subclasses building on the base class.
> > > They are hooked up to the qemu input core and deliver input events
> > > to the guest like all other hid devices (ps/2 kbd, usb tablet, ...).
> > > 
> > > Using them is as simple as adding "-device virtio-tablet-pci" to your
> > > command line.  If you want add multiple devices but don't want waste
> > > a pci slot for each you can compose a multifunction device this way:
> > > 
> > > qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
> > >      -device virtio-tablet-pci,addr=0d.1,multifunction=on
> > > 
> > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > 
> > Hmm - that's interesting.
> > I was under the impression that a single pci function can be
> > a keyboard, mouse and tablet at the same time.
> 
> It is possible to create a device supporting both keyboard and
> mouse/tablet events.  Which will also show up as single input device in
> the guest then.  People and software tends to not expect that though, so
> I think it is better to keep them separate.
> 
> > If they aren't why don't we assign distinct device IDs to them
> > after all?
> 
> pci device ids I assume?  Sure, we can do that.  Will make lspci output
> a bit more informative (no need to check /proc/bus/input/devices to
> figure what kind of input device it is).

It's up to you I am just asking.

If drivers don't expect a mix of functionality, then separate IDs
seem better.
OTOH an advantage to using a custom identification scheme would be
if you want to allow a single device to change type
dynamically.

E.g. if guest knows about MT, act as an MT device otherwise
act as a mouse.

Or more interestingly, as we migrate from host with a mouse
to an MT one, switch from a mouse to a touch device?


> > > +    [Q_KEY_CODE_META_L]              = KEY_LEFTMETA,
> > > +    [Q_KEY_CODE_META_R]              = KEY_RIGHTMETA,
> > > +    [Q_KEY_CODE_MENU]                = KEY_MENU,
> > > +};
> > 
> > OK these are values send to guest, right?
> 
> Yes.
> 
> > And they are from linux/input.h, right? But are these
> > reasonable in a cross-platform device?
> 
> Can't see strong reasons speaking against it.  It's kernel/userspace
> API, therefore stable.  There are keycodes defined for pretty much
> anything you can think of.
> 
> linux guest code is dead simple.  For other guests supporting it
> shouldn't be that hard too, they basically need a mapping table to map
> the linux KEY_* codes into their internal representation.
> > E.g. Linux is pretty good at backwards compatibility
> > but less good at versioning.
> 
> --verbose please.

See below.


> > That header says "Most of the keys/buttons are modeled after USB HUT
> > 1.12" but as far as I could see the codes are not from HUT, correct?
> 
> No, the codes are different.
> 
> > Would it be a good idea to use codes from HUT directly?
> > This way we could extend functionality without adding lots of
> > text to the spec, simply by referring to HUT.
> 
> I want to simply refer to linux/input.h in the spec.


That's exactly the question.  Which version of linux/input.h?

> > Also what defines the subset selected?
> 
> All keys in linux/input.h are supported by the virtio input protocol.

I'm asking how is this versioned: assume that linux adds
a new keycode, existing guests don't expect it.
Don't we need any negotiation? Is it really always safe to
ignore keypresses?

> The current qemu kbd emulation covers all keys qemu knows (see QKeyCode
> in qapi-schema.json).

Hmm SDL can give us a bunch of codes like volume up/down
that you don't seem to include.



> > > +static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
> > > +    [INPUT_AXIS_X]                   = ABS_X,
> > > +    [INPUT_AXIS_Y]                   = ABS_Y,
> > > +};
> > > +
> > 
> > In the future, it seems like a good idea to report raw
> > multi-touch events to guests - this would need a different
> > interface along the lines of
> > Documentation/input/multi-touch-protocol.txt
> 
> Should be no big deal.  Not looked at that deeply yet due to lack of
> test hardware, but I think all we need is mapping the info from
> EVIOCGMTSLOTS into config space, simliar to how it is done for
> EVIOCGABS.
> > Do MT devices generate ST events as well so it's ok to just
> > filter out everything we don't recognize?
> 
> Yes, as far I know both mt and st events are generated.
> 
> > > +static void virtio_input_hid_handle_status(VirtIOInput *vinput,
> > > +                                           virtio_input_event *event)
> > > +{
> > > +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> > > +    int ledbit = 0;
> > > +
> > > +    switch (le16_to_cpu(event->type)) {
> > > +    case EV_LED:
> > > +        if (event->code == LED_NUML) {
> > > +            ledbit = QEMU_NUM_LOCK_LED;
> > > +        } else if (event->code == LED_CAPSL) {
> > > +            ledbit = QEMU_CAPS_LOCK_LED;
> > > +        } else if (event->code == LED_SCROLLL) {
> > > +            ledbit = QEMU_SCROLL_LOCK_LED;
> > > +        }
> > > +        if (event->value) {
> > > +            vhid->ledstate |= ledbit;
> > > +        } else {
> > > +            vhid->ledstate &= ~ledbit;
> > > +        }
> > > +        kbd_put_ledstate(vhid->ledstate);
> > 
> > What does this do? notice led light up on one keyboard and propagate
> > state to all keyboards?
> 
> Notify everybody interested in about kbd led changes.  ps/2+usb kbd
> emulations do the same.
> 
> It is used by vnc for example, to make sure capslock/numlock state
> between guest and host stay in sync.
> 
> cheers,
>   Gerd
> 

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

* Re: [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough
  2014-04-10 11:57     ` Gerd Hoffmann
@ 2014-04-10 15:16       ` Michael S. Tsirkin
  2014-04-11  8:02         ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 15:16 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 01:57:03PM +0200, Gerd Hoffmann wrote:
>   Hi,
> 
> > > +static void virtio_input_host_event(void *opaque)
> > > +{
> > > +    VirtIOInputHost *vhost = opaque;
> > 
> > I'd prefer a name that does not imply
> > vhost infrastructure
> 
> ok.
> 
> > > +    rc = ioctl(vhost->fd, EVIOCGVERSION, &ver);
> > > +    if (rc < 0) {
> > > +        error_setg(errp, "%s: is not an evdev device", vhost->evdev);
> > > +        goto err_close;
> > > +    }
> > 
> > Hmm is that all?
> > Don't we want to report versioning info to guests?
> 
> I guess the only thing we might want to here is bail out in case the
> major version is != 1 (which implies a incompatible change).  The major
> version didn't change so far though, and I think it is highly unlikely
> that it'll ever happen.
> 
> cheers,
>   Gerd

BTW this device should block migration, right?

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

* Re: [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device
  2014-04-10 12:10     ` Gerd Hoffmann
@ 2014-04-10 15:20       ` Michael S. Tsirkin
  2014-04-11  8:25         ` Gerd Hoffmann
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2014-04-10 15:20 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Thu, Apr 10, 2014 at 02:10:20PM +0200, Gerd Hoffmann wrote:
> On Do, 2014-04-10 at 14:05 +0300, Michael S. Tsirkin wrote:
> > On Thu, Apr 10, 2014 at 11:07:53AM +0200, Gerd Hoffmann wrote:
> > > Device for sending non-input control messages to the guest.  For now
> > > this is only a single event: shutdown requests are sent as power button
> > > press to the guest.
> > > 
> > > Possible other use is signaling sound volume changes to the guest (via
> > > EV_ABS / ABS_VOLUME).  I expect we'll find more over time.
> > > 
> > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > 
> > Why not use a keyboard device for this?
> 
> >From the guests point of view this is looks like a keyboard.  A keyboard
> with a single key: power.
> 
> I prefer a clear separation between devices being feed from user input
> and the control device which monitors other event sources (powerdown
> notifier).
> 
> There is no fundamental reason why this can't live in the emulated
> keyboard though.
> 
> cheers,
>   Gerd
>

Well I have a keyboard with volume keys - sleep and wakeup buttons too.
Not power but that's not out of the realm of possibility.
If we want to be able to pass that through, it should work as a
virtio keyboard right?
 
-- 
MST

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

* Re: [Qemu-devel] [PATCH spec] Add virtio input device specification
  2014-04-10  9:07 ` [Qemu-devel] [PATCH spec] Add virtio input device specification Gerd Hoffmann
@ 2014-04-10 15:36   ` Christopher Covington
  0 siblings, 0 replies; 26+ messages in thread
From: Christopher Covington @ 2014-04-10 15:36 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: virtio-dev, qemu-devel

Hi Gerd,

On 04/10/2014 05:07 AM, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  content.tex      |   2 +
>  virtio-input.tex | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 137 insertions(+)
>  create mode 100644 virtio-input.tex
> 
> diff --git a/content.tex b/content.tex
> index c31a99e..196950d 100644
> --- a/content.tex
> +++ b/content.tex
> @@ -4887,6 +4887,8 @@ descriptor for the \field{sense_len}, \field{residual},
>  \field{status_qualifier}, \field{status}, \field{response} and
>  \field{sense} fields.
>  
> +\input{virtio-input.tex}
> +
>  \chapter{Reserved Feature Bits}\label{sec:Reserved Feature Bits}
>  
>  Currently there are three device-independent feature bits defined:
> diff --git a/virtio-input.tex b/virtio-input.tex
> new file mode 100644
> index 0000000..3c34a52
> --- /dev/null
> +++ b/virtio-input.tex
> @@ -0,0 +1,135 @@
> +\section{Input Device}\label{sec:Device Types / Input Device}
> +
> +The virtio input device can be used to create virtual human interface
> +devices such as keyboards, mice and tables.  It basically sends linux

tablets

Christopher

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by the Linux Foundation.

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

* Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
  2014-04-10 14:56       ` Michael S. Tsirkin
@ 2014-04-11  7:17         ` Gerd Hoffmann
  0 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-11  7:17 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

  Hi,

> > It's not different from other input devices.  No buffer space -> drop
> > event.  What else do you think should happen?  We could signal "you lost
> > events" to the guest, but I suspect that buys us nothing.  Other input
> > devices don't have that capability, so guests are likely not prepared to
> > handle the situation.
> 
> For assigned device input events, how about we don't read events off the
> input device file if there's nowhere to put them?

That'll just offload the problem to the kernel.

> For things like sync that qemu generates, I suspect it's a good idea
> to buffer them in QEMU otherwise guest will get out of sync, right?

Grouping things makes sense indeed.  Mouse movements for example are
reported as three events:  one for the x axis, one for the y axis, and
the sync.  We should report either all three or none of them to the
guest to avoid confusion.  I'll think about how to do that best.

> I'm also pretty sure whoever's running the hypervisor does not
> want to see the fprintf.

I'll drop it.  Or maybe better make it a tracepoint.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
  2014-04-10 15:14       ` Michael S. Tsirkin
@ 2014-04-11  8:01         ` Gerd Hoffmann
  0 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-11  8:01 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

  Hi,

> If drivers don't expect a mix of functionality, then separate IDs
> seem better.

The linux kernel can deal with it just fine.  It's just that humans are
more used to have separate devices.  And I remember back in the dark xen
days the input channel for xenfb was a unified input device which
delivered both mouse and keyboard events, and it caused some grief with
the X11 configuration.

While thinking about it:  We could certainly make this
user-configurable.  So instead of adding three new devices we just add
one with config options.  Then we'll have

  -device virtio-input-emulated-pci,kbd=on

instead of

  -device virtio-keyboard-pci

Likewise for mouse and tablet.  And it'll be possible then to just do

  -device virtio-input-emulated-pci,kbd=on,tablet=on

to get a unified device.

> OTOH an advantage to using a custom identification scheme would be
> if you want to allow a single device to change type
> dynamically.

Changing dynamically isn't going to happen.

> Or more interestingly, as we migrate from host with a mouse
> to an MT one, switch from a mouse to a touch device?

Multitouch is tricky, especially the input side.  gtk+sdl ui could work
without too much trouble.  spice+vnc need protocol extensions for that.
Not investigated yet in detail.  Guess it's a good excuse to expense a
new, shiny and multi-touch capable monitor ;)

Singletouch is easy.  We'll basically send BTN_TOUCH instead of
BTN_LEFT.  And with some additional tweaks (such as filtering out any
move events with mousebutton/finger lifted) we can even use normal mouse
input to fake a touch screen.

> > All keys in linux/input.h are supported by the virtio input protocol.
> 
> I'm asking how is this versioned: assume that linux adds
> a new keycode, existing guests don't expect it.
> Don't we need any negotiation? Is it really always safe to
> ignore keypresses?

Worst case is a non-working key.  I also don't think you'll run into
this in practice.  All fundamental stuff is there.  Stuff which gets
added now is pretty exotic, like this:

=================== cut here ======================

commit 5a1bbf21325bd4f2641f6141fb8c47f6095578dd
Author: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Date:   Sat Feb 2 11:53:47 2013 -0800

    Input: add new keycodes for passenger control units
    
    Entertainment systems used in aircraft need additional keycodes
    for their Passenger Control Units, so let's add them.
    
    Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 5588285..6e4e3c6 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -702,6 +702,11 @@ struct input_keymap_entry {
 #define KEY_CAMERA_LEFT                0x219
 #define KEY_CAMERA_RIGHT       0x21a
 
+#define KEY_ATTENDANT_ON       0x21b
+#define KEY_ATTENDANT_OFF      0x21c
+#define KEY_ATTENDANT_TOGGLE   0x21d   /* Attendant call on or off */
+#define KEY_LIGHTS_TOGGLE      0x21e   /* Reading light on or off */
+
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
 #define BTN_TRIGGER_HAPPY2             0x2c1

=================== cut here ======================

And if you really care about this you'll probably make sure your guests
do know what these key codes are for anyway ;)

> > The current qemu kbd emulation covers all keys qemu knows (see QKeyCode
> > in qapi-schema.json).
> 
> Hmm SDL can give us a bunch of codes like volume up/down
> that you don't seem to include.

Disclaimer: I havn't added QkeyCode, it was there already.

I expect QKeyCode learn more keys in the future.  The input layer
rewrite in the 2.0 devel cycle moved QKeyCode into the focus as it is
used more widely in qemu now.  Until recently it was used only for the
sendkey monitor command.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough
  2014-04-10 15:16       ` Michael S. Tsirkin
@ 2014-04-11  8:02         ` Gerd Hoffmann
  0 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-11  8:02 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

  Hi,

> > I guess the only thing we might want to here is bail out in case the
> > major version is != 1 (which implies a incompatible change).  The major
> > version didn't change so far though, and I think it is highly unlikely
> > that it'll ever happen.
> > 
> > cheers,
> >   Gerd
> 
> BTW this device should block migration, right?

Yes.  I'll add it.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device
  2014-04-10 15:20       ` Michael S. Tsirkin
@ 2014-04-11  8:25         ` Gerd Hoffmann
  0 siblings, 0 replies; 26+ messages in thread
From: Gerd Hoffmann @ 2014-04-11  8:25 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtio-dev, qemu-devel, Anthony Liguori

On Do, 2014-04-10 at 18:20 +0300, Michael S. Tsirkin wrote:
> On Thu, Apr 10, 2014 at 02:10:20PM +0200, Gerd Hoffmann wrote:
> > On Do, 2014-04-10 at 14:05 +0300, Michael S. Tsirkin wrote:
> > > On Thu, Apr 10, 2014 at 11:07:53AM +0200, Gerd Hoffmann wrote:
> > > > Device for sending non-input control messages to the guest.  For now
> > > > this is only a single event: shutdown requests are sent as power button
> > > > press to the guest.
> > > > 
> > > > Possible other use is signaling sound volume changes to the guest (via
> > > > EV_ABS / ABS_VOLUME).  I expect we'll find more over time.
> > > > 
> > > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > > 
> > > Why not use a keyboard device for this?
> > 
> > >From the guests point of view this is looks like a keyboard.  A keyboard
> > with a single key: power.
> > 
> > I prefer a clear separation between devices being feed from user input
> > and the control device which monitors other event sources (powerdown
> > notifier).
> > 
> > There is no fundamental reason why this can't live in the emulated
> > keyboard though.
> > 
> > cheers,
> >   Gerd
> >
> 
> Well I have a keyboard with volume keys - sleep and wakeup buttons too.
> Not power but that's not out of the realm of possibility.
> If we want to be able to pass that through, it should work as a
> virtio keyboard right?

Sure.  That is another story though.  QKeyCode needs to learn those
keys, they need to be added to the mappings, and then they'll be handled
like any other key.


What I was thinking about is sending feedback about volume changes to
the guest is something completely different, let me explain in detail:

What we have in spice today is that the guests volume change request is
passed to the spice client, which in turn forwards it to pulseaudio,
which then actually applies the volume setting to the audio stream.  And
you can see the guests volume changes in the hosts mixer UI (sound
settings -> applications):  change the volume in the guest and watch the
slider move.

Today this is a one-way ticket.  If you fiddle with the volume in the
hosts mixer ui the guest doesn't notice.  A emulated volume wheel would
be a possible way to feedback volume changes on the host to the guest.
Note that it isn't that simple to implement as it need a spice protocol
extension too (and support in spice server + client of course).

cheers,
  Gerd

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

end of thread, other threads:[~2014-04-11  8:26 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-10  9:07 [Qemu-devel] [PATCHES] add virtio input device Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH spec] Add virtio input device specification Gerd Hoffmann
2014-04-10 15:36   ` Christopher Covington
2014-04-10  9:07 ` [Qemu-devel] [PATCH linux] Add virtio-input driver Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 1/6] pci: add virtio input pci device id Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 2/6] pci: add virtio gpu " Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class Gerd Hoffmann
2014-04-10 11:06   ` Michael S. Tsirkin
2014-04-10 12:22     ` Gerd Hoffmann
2014-04-10 14:56       ` Michael S. Tsirkin
2014-04-11  7:17         ` Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices Gerd Hoffmann
2014-04-10 10:55   ` Michael S. Tsirkin
2014-04-10 11:47     ` Gerd Hoffmann
2014-04-10 15:14       ` Michael S. Tsirkin
2014-04-11  8:01         ` Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 5/6] virtio-input: control device Gerd Hoffmann
2014-04-10 11:05   ` Michael S. Tsirkin
2014-04-10 12:10     ` Gerd Hoffmann
2014-04-10 15:20       ` Michael S. Tsirkin
2014-04-11  8:25         ` Gerd Hoffmann
2014-04-10  9:07 ` [Qemu-devel] [PATCH qemu 6/6] virtio-input: evdev passthrough Gerd Hoffmann
2014-04-10 11:05   ` Michael S. Tsirkin
2014-04-10 11:57     ` Gerd Hoffmann
2014-04-10 15:16       ` Michael S. Tsirkin
2014-04-11  8:02         ` Gerd Hoffmann

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.