All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.