I’ve been working on a pair of drivers to support the PV mouse and keyboard protocol exposed by the public/io/kbdif.h header.
With these drivers, it is possible to disable QEMU’s USB tablet device and USB emulation, saving a large amount of CPU time which is used to poll emulated USB devices.
During development, I did not add the “usb=true” and “usbdevice=[‘tablet’]” directives to the xl config files, so before the drivers installed, I was using an emulated ps/2 keyboard and ps/2 (relative) mouse, which would have tracking issues
leading to the local mouse pointer not matching the movements or position of the VMs mouse pointer correctly. After the drivers installed, the VMs mouse pointer would follow the local mouse pointer correctly.
This splits into 2 drivers and a small change to QEMUs backend:
XenVkbd (https://github.com/OwenSmith/xenvkbd)
- Binds to a device enumerated by XenBus when the appropriate changes are made
- “VKBD” needs to be added to the “SupportedClasses” REG_MULTI_SZ, either in the INF or post-installation.
These changes have not been posted made, though it is a minor XenBus inf file change when the drivers are accepted.
- Enumerates a PDO for each entry made under xenstore device/vkbd
- The PDO includes an implementation of the kbdif interface, and accepts relative or absolute mouse position, mouse button and keyboard keypress events.
- Exposes an interface to a driver above that contains various query methods as used by the HID class driver. The interface has methods to retrieve descriptors, strings and data reports,
as well as a callback that’s called when new report data is available.
- Future improvements may include adding a multi-touch capable tablet/digitizer endpoint and/or overrides to the various descriptors (and vkbd protocol extensions) to allow any HID device
to be passed through.
XenHid (https://github.com/OwenSmith/xenhid)
- XenHid is intentionally kept as simple as possible.
- Binds to the PDO of XenVkbd and interfaces with the standard Microsoft provided HID-Class driver.
- Queries for the interface exposed by XenVkbd, and passes most of the HID class calls directly to the protocol driver. The exception is the read report call, which is queued until the
interface callback is called, due to the design of the HID class interface.
QEMU Patch
- A small change to QEMUs implementation of the vkbd backend is required. A separate patch series will be submitted to QEMU. I’ve included the bare minimum patch to this mail, though
the patch series submitted to QEMU will make the same changes, it will be cleaned up.
(copy-paste from git format-patch)
From f49ce475c70604d5bad6b83412c85e7e1f8bb13e Mon Sep 17 00:00:00 2001
From:
Date: Tue, 30 May 2017 10:43:44 +0000
Subject: [PATCH] Fix xenfb for PV-HID
Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
hw/display/xenfb.c | 31 ++++++++++++++++++++-----------
1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 7a8727a..4060fb3 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -307,18 +307,22 @@ static void xenfb_mouse_event(void *opaque,
int dx, int dy, int dz, int button_state)
{
struct XenInput *xenfb = opaque;
- DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
- int dw = surface_width(surface);
- int dh = surface_height(surface);
- int i;
+ int i, x, y;
+ if (xenfb->c.con) {
+ DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
+ int dw = surface_width(surface);
+ int dh = surface_height(surface);
+ x = dx * (dh - 1) / 0x7fff;
+ y = dy * (dw - 1) / 0x7fff;
+ } else {
+ x = dx;
+ y = dy;
+ }
trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
xenfb->abs_pointer_wanted);
if (xenfb->abs_pointer_wanted)
- xenfb_send_position(xenfb,
- dx * (dw - 1) / 0x7fff,
- dy * (dh - 1) / 0x7fff,
- dz);
+ xenfb_send_position(xenfb, x, y, dz);
else
xenfb_send_motion(xenfb, dx, dy, dz);
@@ -346,15 +350,18 @@ static int input_initialise(struct XenDevice *xendev)
int rc;
if (!in->c.con) {
- xen_pv_printf(xendev, 1, "ds not set (yet)\n");
- return -1;
+ char *vfb = xenstore_read_str(NULL, "device/vfb");
+ if (vfb != NULL) {
+ free(vfb);
+ xen_pv_printf(xendev, 1, "ds not set (yet)\n");
+ return -1;
+ }
}
rc = common_bind(&in->c);
if (rc != 0)
return rc;
- qemu_add_kbd_event_handler(xenfb_key_event, in);
return 0;
}
@@ -367,6 +374,7 @@ static void input_connected(struct XenDevice *xendev)
in->abs_pointer_wanted = 0;
}
+ qemu_add_kbd_event_handler(xenfb_key_event, in);
if (in->qmouse) {
qemu_remove_mouse_event_handler(in->qmouse);
}
@@ -374,6 +382,7 @@ static void input_connected(struct XenDevice *xendev)
in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
in->abs_pointer_wanted,
"Xen PVFB Mouse");
+ qemu_activate_mouse_event_handler(in->qmouse);
}
static void input_disconnect(struct XenDevice *xendev)
--
2.1.4