* [PATCH] Simple emulation of host keyboard and mouse for gfx_passthru.
@ 2010-03-24 10:57 Dietmar Hahn
0 siblings, 0 replies; 2+ messages in thread
From: Dietmar Hahn @ 2010-03-24 10:57 UTC (permalink / raw)
To: xen-devel@lists.xensource.com
[-- Attachment #1: Type: text/plain, Size: 684 bytes --]
Hi,
to use the host keyboard and touchpad of my laptop while running a HVM guest
with passthroughed primary gfx-card I wrote a simple emulation.
To activate it change
gfx_passthru=1 -> gfx_passthru=1001
in the domU config file. This was done this way to have a small footprint.
Also the embedding in helper2.c is a little bit awkward.
Another problem using this way is that the VT in dom0 is not reset when the
domU gets destroyed.
I wrote this as a workaround until the announced comfortable solution from
Jean Guyader is accessible.
http://lists.xensource.com/archives/html/xen-devel/2010-03/msg00979.html
Thanks.
Dietmar.
--
Company details: http://ts.fujitsu.com/imprint.html
[-- Attachment #2: kbdmouse.patch --]
[-- Type: text/x-patch, Size: 13124 bytes --]
From 4808b8cb1c76a79439b24baf47bd60779b434ecf Mon Sep 17 00:00:00 2001
From: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Date: Wed, 24 Mar 2010 11:14:51 +0100
Subject: [PATCH] Simple emulation of host keyboard and mouse for gfx_passthru.
Currently the input to HVM guest using gfx_passthru with primary gfx-card
is only possible via usb kbd/mouse.
This patch adds a simple emulation of the host PS/2 kbd/mouse.
To activate set gfx_passthru=1001 in config file.
Signed-off-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
i386-dm/gfx_host_kbdmouse.c | 331 +++++++++++++++++++++++++++++++++++++++++++
i386-dm/helper2.c | 7 +
vl.c | 5 +-
3 files changed, 342 insertions(+), 1 deletions(-)
create mode 100644 i386-dm/gfx_host_kbdmouse.c
diff --git a/i386-dm/gfx_host_kbdmouse.c b/i386-dm/gfx_host_kbdmouse.c
new file mode 100644
index 0000000..5e5fd1a
--- /dev/null
+++ b/i386-dm/gfx_host_kbdmouse.c
@@ -0,0 +1,331 @@
+/*
+ * Emulation of PS/2 - keyboard and mouse for gfx_passthru.
+ * Keyboard:
+ * The emulation opens the next free VT device and set it to active.
+ * This device is used for keyboard input. The keyboard events are
+ * sent to the i8042 emulation in the qemu.
+ * Mouse:
+ * In this simple version /dev/mice is used as input for mouse events
+ * sent to the i8042 emulation too.
+ *
+ * Some code is taken from xorg-server-1.7.1 and xorg-x11-driver-input-7.4.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <termios.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+
+#include "console.h"
+
+/* In vl.c together with gfx_passthru. */
+extern int gfx_host_kbdmouse;
+
+static fd_set gfx_host_fdset, gfx_host_rset;
+static int maxfd=0;
+
+static int sleep_cnt;
+
+static int gfx_host_kbd_fd = -1;
+static int gfx_host_kbd_mode_save;
+static struct termios gfx_host_kbd_termios_save;
+int gfx_host_kbd_vtno, gfx_host_kbd_old_vtno;
+
+static int gfx_host_mouse_fd = -1;
+
+static int
+gfx_host_file_set_nonblock(int fd)
+{
+ int flags;
+ flags = fcntl (fd, F_GETFL);
+ flags |= O_ASYNC | O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ fprintf(logfile, "fcntl(F_SETFL) failed: %d\n", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static void gfx_host_file_reset_nonblock(int fd)
+{
+ int flags;
+ flags = fcntl(fd, F_GETFL);
+ flags &= ~(O_ASYNC | O_NONBLOCK);
+ fcntl(fd, F_SETFL, flags);
+}
+
+static void gfx_host_fd_add(int fd)
+{
+ FD_SET(fd, &gfx_host_fdset);
+ if (fd > maxfd)
+ maxfd = fd; /* max fd for select() */
+}
+
+static void gfx_host_fd_remove(int fd)
+{
+ FD_CLR(fd, &gfx_host_fdset);
+}
+
+/* Keyboard/mouse signal handler */
+static void gfx_host_kbd_mouse_read(int sig)
+{
+ unsigned char buf[256];
+ int n, i;
+ sleep_cnt = 5;
+ errno = 0;
+
+ gfx_host_rset = gfx_host_fdset; /* gfx_host_rset gets modified each time around */
+ if ( (n = select(maxfd + 1, &gfx_host_rset, NULL, NULL, NULL)) < 0) {
+ fprintf(logfile, "%s: select() failed: errno: %d\n", __func__, errno);
+ return;
+ }
+ if (FD_ISSET(gfx_host_kbd_fd, &gfx_host_rset)) { /* read kbd buffer */
+ if ((n = read (gfx_host_kbd_fd, buf, sizeof (buf))) == -1) {
+ if (errno != EAGAIN)
+ fprintf(logfile, "%s-kbd: read failed: %d\n", __func__, errno);
+ }
+ if (n != 0) {
+ for (i=0; i<n; i++) {
+ kbd_put_keycode((int)buf[i]);
+ }
+ }
+ }
+ if (FD_ISSET(gfx_host_mouse_fd, &gfx_host_rset))
+ { /* read mouse buffer */
+ char *cp;
+ if ((n = read (gfx_host_mouse_fd, buf, sizeof (buf))) == -1) {
+ if (errno != EAGAIN) {
+ fprintf(logfile, "%s-mouse: read failed: %d\n", __func__,errno);
+ return;
+ }
+ }
+ if (n == 0)
+ return;
+ if (n % 3)
+ fprintf(logfile, "%s-mouse: n (%d) not multiple of 3\n",
+ __func__, n);
+ for (i=0; i<n; i+=3) {
+ int buttons = 0;
+ char c;
+ cp = &buf[i];
+ //buttons = (1 << ((cp[0] & 0x3) - 1));
+ switch (cp[0] & 0x3) {
+ case 1: buttons |= MOUSE_EVENT_LBUTTON; break;
+ case 2: buttons |= MOUSE_EVENT_RBUTTON; break;
+ case 3: buttons |= MOUSE_EVENT_MBUTTON; break;
+ }
+ c = ~cp[2] + 1;
+ kbd_mouse_event(cp[1], c, 0, buttons);
+ }
+ }
+}
+
+static int gfx_host_kbd_enable(void)
+{
+ unsigned char buf[256];
+ int n;
+ struct sigaction act;
+ struct termios ntty;
+
+ ioctl(gfx_host_kbd_fd, KDGKBMODE, &gfx_host_kbd_mode_save);
+ ioctl(gfx_host_kbd_fd, KDSKBMODE, K_RAW);
+
+ tcgetattr(gfx_host_kbd_fd, &gfx_host_kbd_termios_save);
+ ntty = gfx_host_kbd_termios_save;
+ ntty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
+ ntty.c_oflag = 0;
+ ntty.c_cflag = CREAD | CS8;
+ ntty.c_lflag = 0;
+ ntty.c_cc[VTIME]=0;
+ ntty.c_cc[VMIN]=1;
+ cfsetispeed(&ntty, 9600);
+ cfsetospeed(&ntty, 9600);
+ tcsetattr(gfx_host_kbd_fd, TCSANOW, &ntty);
+
+ if (fcntl(gfx_host_kbd_fd, F_SETOWN, getpid()) == -1) {
+ fprintf(logfile, "%s: fcntl(F_SETOWN) failed: %d\n", __func__, errno);
+ return 0;
+ }
+ memset(&act, '\0', sizeof act);
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = gfx_host_kbd_mouse_read;
+ sigaction(SIGIO, &act, NULL);
+
+ if (!gfx_host_file_set_nonblock(gfx_host_kbd_fd))
+ return 0;
+
+ while ((n = read (gfx_host_kbd_fd, buf, sizeof (buf))) > 0)
+ ;
+ gfx_host_fd_add(gfx_host_kbd_fd);
+ return 1;
+}
+
+static int gfx_host_mouse_enable(void)
+{
+ unsigned char buf[256];
+
+ if (fcntl (gfx_host_mouse_fd, F_SETOWN, getpid()) == -1) {
+ fprintf(logfile, "%s: fcntl(F_SETOWN) failed: %d\n", __func__, errno);
+ return 0;
+ }
+ if (!gfx_host_file_set_nonblock(gfx_host_mouse_fd))
+ return 0;
+
+ while (read(gfx_host_mouse_fd, buf, sizeof (buf)) > 0)
+ ;
+ gfx_host_fd_add(gfx_host_mouse_fd);
+ return 1;
+}
+
+static void gfx_host_mouse_disable(void)
+{
+ gfx_host_file_reset_nonblock(gfx_host_mouse_fd);
+ gfx_host_fd_remove(gfx_host_mouse_fd);
+}
+
+static void gfx_host_kbd_disable(void)
+{
+ struct sigaction act;
+
+ gfx_host_file_reset_nonblock(gfx_host_kbd_fd);
+ memset (&act, '\0', sizeof act);
+ act.sa_handler = SIG_IGN;
+ sigemptyset (&act.sa_mask);
+ sigaction (SIGIO, &act, 0);
+ gfx_host_fd_remove(gfx_host_kbd_fd);
+ tcsetattr(gfx_host_kbd_fd, TCSANOW, &gfx_host_kbd_termios_save);
+ ioctl(gfx_host_kbd_fd, KDSKBMODE, gfx_host_kbd_mode_save);
+}
+
+static void gfx_host_kbd_alloc(void)
+{
+ struct vt_mode VT;
+ struct vt_stat vts;
+ const char* chktty = "/dev/tty0";
+ const char* mytty = "/dev/tty%d";
+ static char vtname[11];
+
+ if ((gfx_host_kbd_fd = open(chktty, O_RDWR|O_NDELAY, 0)) == -1) {
+ fprintf(logfile, "open(%s) failed: %d\n", chktty, errno);
+ exit(2);
+ }
+ if (ioctl(gfx_host_kbd_fd, VT_GETSTATE, &vts) < 0) {
+ fprintf(logfile, "ioctl daneben");
+ goto failed;
+ }
+ gfx_host_kbd_old_vtno = vts.v_active;
+
+ if ((ioctl(gfx_host_kbd_fd, VT_OPENQRY, &gfx_host_kbd_vtno) < 0) ||
+ (gfx_host_kbd_vtno == -1)) {
+ fprintf(logfile, "No free VT");
+ goto failed;
+ }
+
+ close(gfx_host_kbd_fd);
+ sprintf(vtname, mytty, gfx_host_kbd_vtno);
+
+ if ((gfx_host_kbd_fd = open(vtname, O_RDWR|O_NDELAY, 0)) == -1) {
+ fprintf(logfile, "open(%s) failed: %d\n", vtname, errno);
+ exit(2);
+ }
+ if (ioctl(gfx_host_kbd_fd, VT_ACTIVATE, gfx_host_kbd_vtno) < 0) {
+ fprintf(logfile, "ioctl(VT_ACTIVATE) failed: %d\n", errno);
+ goto failed;
+ }
+ if (ioctl(gfx_host_kbd_fd, VT_WAITACTIVE, gfx_host_kbd_vtno) < 0) {
+ printf("ioctl(VT_WAITACTIVE) failed: %d\n", errno);
+ fprintf(logfile, "ioctl(VT_WAITACTIVE) failed: %d\n", errno);
+ goto failed;
+ }
+ fprintf(logfile, "gfx_host_kbdmous runs on tty%d\n", gfx_host_kbd_vtno);
+ return;
+failed:
+ close(gfx_host_kbd_fd);
+ exit(2);
+}
+
+static void gfx_host_kbd_release(void)
+{
+ struct vt_stat vts;
+ /* Restore old VT */
+ if (ioctl(gfx_host_kbd_fd, VT_ACTIVATE, gfx_host_kbd_old_vtno) < 0) {
+ fprintf(logfile, "%s: ioctl(VT_ACTIVATE) failed: %d\n",
+ __func__, errno);
+ close(gfx_host_kbd_fd);
+ exit(2);
+ }
+ if (ioctl(gfx_host_kbd_fd, VT_WAITACTIVE, gfx_host_kbd_old_vtno) < 0) {
+ fprintf(logfile, "%s: ioctl(VT_WAITACTIVE) failed: %d\n",
+ __func__, errno);
+ close(gfx_host_kbd_fd);
+ exit(2);
+ }
+ close(gfx_host_kbd_fd);
+ gfx_host_kbd_fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0);
+ if (gfx_host_kbd_fd < 0)
+ fprintf(logfile, "%s: open(dev/tty0) failed: %d\n", __func__, errno);
+ else {
+ if (gfx_host_kbd_fd >= 0) {
+ if (ioctl(gfx_host_kbd_fd, VT_DISALLOCATE, gfx_host_kbd_vtno) < 0)
+ fprintf(logfile, "%s: ioctl(VT_DISALLOCATE) failed: %d\n",
+ __func__, errno);
+ close (gfx_host_kbd_fd);
+ }
+ }
+ fprintf(logfile, "gfx_host_kbdmouse: restored orig active tty%d\n",
+ gfx_host_kbd_old_vtno);
+}
+
+static int
+gfx_host_mouse_alloc(void)
+{
+ const char *name = "/dev/input/mice";
+ int i;
+
+ if ((gfx_host_mouse_fd = open(name, O_RDWR|O_NDELAY, 0)) == -1) {
+ fprintf(logfile, "open(%s) failed: %d\n", name, errno);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+gfx_host_mouse_release(void)
+{
+ close(gfx_host_mouse_fd);
+}
+
+static void
+gfx_host_kbdmouse_init(void)
+{
+ FD_ZERO(&gfx_host_fdset);
+ gfx_host_kbd_alloc();
+ if (!gfx_host_mouse_alloc()) {
+ gfx_host_kbd_release();
+ return;
+ }
+ if (! gfx_host_kbd_enable()) {
+ gfx_host_kbd_release();
+ gfx_host_mouse_release();
+ return;
+ }
+ gfx_host_mouse_enable(); /* Ignore failing mouse. */
+}
+
+static void gfx_host_kbdmouse_close(void)
+{
+ gfx_host_mouse_disable();
+ gfx_host_kbd_disable();
+ gfx_host_mouse_release();
+ gfx_host_kbd_release();
+}
+
diff --git a/i386-dm/helper2.c b/i386-dm/helper2.c
index 986df3c..9ce1da3 100644
--- a/i386-dm/helper2.c
+++ b/i386-dm/helper2.c
@@ -61,6 +61,8 @@
#include "sysemu.h"
#include "qemu-xen.h"
+#include "gfx_host_kbdmouse.c"
+
//#define DEBUG_MMU
#ifdef USE_CODE_COPY
@@ -536,6 +538,8 @@ static void cpu_handle_ioreq(void *opaque)
if (qemu_shutdown_requested()) {
fprintf(logfile, "shutdown requested in cpu_handle_ioreq\n");
destroy_hvm_domain();
+ if (gfx_host_kbdmouse)
+ gfx_host_kbdmouse_close();
}
if (qemu_reset_requested()) {
fprintf(logfile, "reset requested in cpu_handle_ioreq.\n");
@@ -566,6 +570,9 @@ int main_loop(void)
if (evtchn_fd != -1)
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
+ if (gfx_host_kbdmouse)
+ gfx_host_kbdmouse_init();
+
xenstore_record_dm_state("running");
qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL);
diff --git a/vl.c b/vl.c
index 16de102..510a4f0 100644
--- a/vl.c
+++ b/vl.c
@@ -216,6 +216,7 @@ int cirrus_vga_enabled = 1;
int std_vga_enabled = 0;
int vmsvga_enabled = 0;
int gfx_passthru = 0;
+int gfx_host_kbdmouse = 0;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
@@ -4452,7 +4453,7 @@ static const QEMUOption qemu_options[] = {
#endif
{ "acpi", 0, QEMU_OPTION_acpi }, /* deprecated, for xend compatibility */
{ "direct_pci", HAS_ARG, QEMU_OPTION_direct_pci },
- { "gfx_passthru", 0, QEMU_OPTION_gfx_passthru},
+ { "gfx_passthru", HAS_ARG, QEMU_OPTION_gfx_passthru},
{ "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
{ "vncunused", 0, QEMU_OPTION_vncunused },
{ "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
@@ -5548,6 +5549,8 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_gfx_passthru:
select_vgahw("passthrough");
+ if (atoi(optarg) >= 1000)
+ gfx_host_kbdmouse = 1;
break;
}
}
--
1.6.4.2
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH] Simple emulation of host keyboard and mouse for gfx_passthru.
@ 2012-08-17 14:24 Lenar Shakirov
0 siblings, 0 replies; 2+ messages in thread
From: Lenar Shakirov @ 2012-08-17 14:24 UTC (permalink / raw)
To: xen-devel; +Cc: Linux
Hi,
See http://lists.xen.org/archives/html/xen-devel/2010-03/msg01292.html.
I compiled XEN with patch listed above and get passthrough of PS/2
keyboard and mouse (touchpad) works very well!
I have the same situation: laptop with VT-d and PS/2 keyboard and touchpad.
P.S.: thanks to Dietmar Hahn!
--
Best regards,
Lenar Shakirov
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2012-08-17 14:24 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-17 14:24 [PATCH] Simple emulation of host keyboard and mouse for gfx_passthru Lenar Shakirov
-- strict thread matches above, loose matches on Subject: below --
2010-03-24 10:57 Dietmar Hahn
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.