]> xenbits.xensource.com Git - people/pauldu/demu.git/commitdiff
Wire up keyboard.
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 7 Mar 2014 16:59:01 +0000 (16:59 +0000)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 7 Mar 2014 17:00:11 +0000 (17:00 +0000)
Do the necessary key sym to scancode translation and wire this into the PS/2
keyboard emulation.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
12 files changed:
Makefile
demu.c
kbd.c [new file with mode: 0644]
kbd.h [new file with mode: 0644]
keymaps/common [new file with mode: 0644]
keymaps/en-us [new file with mode: 0644]
keymaps/modifiers [new file with mode: 0644]
ps2.c
ps2.h
roms/vgabios-stdvga.bin [new file with mode: 0644]
vga.c
vgabios-stdvga.bin [deleted file]

index 9d4494eb171e0b80331bad56e0f43563e269f87b..46b271e04a8202b59986fa29b20ef8c3e42e05a4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
 TARGET = demu
 
 OBJS :=        vga.o \
+       kbd.o \
        ps2.o \
        pci.o \
        mapcache.o \
diff --git a/demu.c b/demu.c
index 331621e47591aab3f3b7d40657c4e3be134a4426..c68567a06f6cd7e972a21d46b7712032e3617ef8 100644 (file)
--- a/demu.c
+++ b/demu.c
@@ -67,6 +67,7 @@
 #include "debug.h"
 #include "mapcache.h"
 #include "ps2.h"
+#include "kbd.h"
 #include "vga.h"
 #include "pci.h"
 #include "surface.h"
@@ -130,6 +131,7 @@ typedef enum {
     DEMU_SEQ_EVTCHN_OPEN,
     DEMU_SEQ_PORTS_BOUND,
     DEMU_SEQ_BUF_PORT_BOUND,
+    DEMU_SEQ_KBD_INITIALIZED,
     DEMU_SEQ_VNC_INITIALIZED,
     DEMU_SEQ_VGA_INITIALIZED,
     DEMU_SEQ_PS2_INITIALIZED,
@@ -839,9 +841,9 @@ done:
     rfbDefaultPtrAddEvent(buttonMask, x, y, client);
 }
 
-static void demu_vnc_key(rfbBool down, rfbKeySym keySym, rfbClientPtr client)
+static void demu_vnc_key(rfbBool down, rfbKeySym sym, rfbClientPtr client)
 {
-    DBG("%08X\n", keySym);
+    kbd_event(sym, down);
 }
 
 static void demu_vnc_remove_client(rfbClientPtr client)
@@ -1041,6 +1043,10 @@ demu_seq_next(void)
             demu_state.buf_ioreq_local_port);
         break;
 
+    case DEMU_SEQ_KBD_INITIALIZED:
+        DBG(">KBD_INITIALIZED\n");
+        break;
+
     case DEMU_SEQ_VNC_INITIALIZED:
         DBG(">VNC_INITIALIZED\n");
         break;
@@ -1113,6 +1119,13 @@ demu_teardown(void)
         DBG("<VNC_INITIALIZED\n");
         demu_vnc_teardown();
 
+        demu_state.seq = DEMU_SEQ_KBD_INITIALIZED;
+    }
+
+    if (demu_state.seq == DEMU_SEQ_KBD_INITIALIZED) {
+        DBG("<KBD_INITIALIZED\n");
+        kbd_teardown();
+
         demu_state.seq = DEMU_SEQ_PORTS_BOUND;
     }
 
@@ -1347,35 +1360,41 @@ demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned i
 
     demu_seq_next();
 
-    rc = demu_vnc_initialize();
+    rc = kbd_initialize("en-us");
     if (rc < 0)
         goto fail11;
 
     demu_seq_next();
 
+    rc = demu_vnc_initialize();
+    if (rc < 0)
+        goto fail12;
+
+    demu_seq_next();
+
     rc = vga_initialize(bus, device, function,
                         DEMU_VRAM_SIZE,
                         (rom) ? rom : DEMU_ROM_FILE);
     if (rc < 0)
-        goto fail12;
+        goto fail13;
 
     demu_seq_next();
 
     rc = ps2_initialize();
     if (rc < 0)
-        goto fail13;
+        goto fail14;
 
     demu_seq_next();
 
     rc = surface_initialize();
     if (rc < 0)
-        goto fail14;
+        goto fail15;
 
     demu_seq_next();
 
     rc = pthread_create(&demu_state.thread, NULL, demu_thread, NULL);
     if (rc != 0)
-        goto fail15;
+        goto fail16;
 
     demu_seq_next();
 
@@ -1384,6 +1403,9 @@ demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned i
     assert(demu_state.seq == DEMU_SEQ_INITIALIZED);
     return 0;
 
+fail16:
+    DBG("fail16\n");
+
 fail15:
     DBG("fail15\n");
 
diff --git a/kbd.c b/kbd.c
new file mode 100644 (file)
index 0000000..3fd684c
--- /dev/null
+++ b/kbd.c
@@ -0,0 +1,804 @@
+/*  
+ * Copyright (c) 2014, Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * 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.
+ * 
+ * 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 THE COPYRIGHT
+ * HOLDER 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <rfb/rfb.h>
+#include <rfb/keysym.h>
+
+#include "debug.h"
+#include "kbd.h"
+#include "ps2.h"
+
+//#define DEBUG_LAYOUT
+
+#define SCANCODE_GREY       0x80
+#define SCANCODE_EMUL0      0xE0
+#define SCANCODE_KEYMASK    0x7F
+#define SCANCODE_UP         0x80
+
+#define SCANCODE_SHIFT  0x100
+#define SCANCODE_CTRL   0x200
+#define SCANCODE_ALT    0x400
+#define SCANCODE_ALTGR  0x800
+
+#define MAX_NORMAL_SYM  512
+#define MAX_EXTRA_SYM   256
+
+typedef struct kbd_extra {
+    rfbKeySym   sym;
+    uint16_t    code;
+} kbd_extra_t;
+
+typedef struct kbd_range {
+    struct kbd_range    *next;
+    int                 start;
+    int                 end;
+} kbd_range_t;
+
+typedef struct kbd_layout {
+    uint16_t        sym2code[MAX_NORMAL_SYM];
+    kbd_extra_t     sym2code_extra[MAX_EXTRA_SYM];
+    int             extra;
+    kbd_range_t     *numlock_range;
+} kbd_layout_t;
+
+typedef struct kbd {
+    kbd_layout_t    layout;
+    int             shift;
+    int             numlock;
+    int             capslock;
+} kbd_t;
+
+static kbd_t    kbd_state;
+
+typedef struct kbd_name2sym_entry_t {
+    const char  *name;
+    rfbKeySym   value;
+} kbd_name2sym_entry_t;
+
+#define _ENTRY(_name)    { #_name, XK_ ## _name }
+
+static kbd_name2sym_entry_t   name2keysym[] = {
+    _ENTRY(Select),
+    _ENTRY(Print),
+    _ENTRY(Execute),
+    _ENTRY(Insert),
+    _ENTRY(Undo),
+    _ENTRY(Redo),
+    _ENTRY(Menu),
+    _ENTRY(Find),
+    _ENTRY(Cancel),
+    _ENTRY(Help),
+    _ENTRY(Break),
+    _ENTRY(Num_Lock),
+    _ENTRY(KP_Enter),
+    _ENTRY(KP_Home),
+    _ENTRY(KP_Left),
+    _ENTRY(KP_Up),
+    _ENTRY(KP_Right),
+    _ENTRY(KP_Down),
+    _ENTRY(KP_Prior),
+    _ENTRY(KP_Page_Up),
+    _ENTRY(KP_Next),
+    _ENTRY(KP_Page_Down),
+    _ENTRY(KP_End),
+    _ENTRY(KP_Begin),
+    _ENTRY(KP_Insert),
+    _ENTRY(KP_Delete),
+    _ENTRY(KP_Equal),
+    _ENTRY(KP_Multiply),
+    _ENTRY(KP_Add),
+    _ENTRY(KP_Separator),
+    _ENTRY(KP_Subtract),
+    _ENTRY(KP_Decimal),
+    _ENTRY(KP_Divide),
+    _ENTRY(KP_0),
+    _ENTRY(KP_1),
+    _ENTRY(KP_2),
+    _ENTRY(KP_3),
+    _ENTRY(KP_4),
+    _ENTRY(KP_5),
+    _ENTRY(KP_6),
+    _ENTRY(KP_7),
+    _ENTRY(KP_8),
+    _ENTRY(KP_9),
+    _ENTRY(Shift_L),
+    _ENTRY(Shift_R),
+    _ENTRY(Control_L),
+    _ENTRY(Control_R),
+    _ENTRY(Caps_Lock),
+    _ENTRY(Shift_Lock),
+    _ENTRY(Meta_L),
+    _ENTRY(Meta_R),
+    _ENTRY(Alt_L),
+    _ENTRY(Alt_R),
+    _ENTRY(Super_L),
+    _ENTRY(Super_R),
+    _ENTRY(Hyper_L),
+    _ENTRY(Hyper_R),
+    _ENTRY(space),
+    _ENTRY(exclam),
+    _ENTRY(quotedbl),
+    _ENTRY(numbersign),
+    _ENTRY(dollar),
+    _ENTRY(percent),
+    _ENTRY(ampersand),
+    _ENTRY(apostrophe),
+    _ENTRY(parenleft),
+    _ENTRY(parenright),
+    _ENTRY(asterisk),
+    _ENTRY(plus),
+    _ENTRY(comma),
+    _ENTRY(minus),
+    _ENTRY(period),
+    _ENTRY(slash),
+    _ENTRY(0),
+    _ENTRY(1),
+    _ENTRY(2),
+    _ENTRY(3),
+    _ENTRY(4),
+    _ENTRY(5),
+    _ENTRY(6),
+    _ENTRY(7),
+    _ENTRY(8),
+    _ENTRY(9),
+    _ENTRY(colon),
+    _ENTRY(semicolon),
+    _ENTRY(less),
+    _ENTRY(equal),
+    _ENTRY(greater),
+    _ENTRY(question),
+    _ENTRY(at),
+    _ENTRY(A),
+    _ENTRY(B),
+    _ENTRY(C),
+    _ENTRY(D),
+    _ENTRY(E),
+    _ENTRY(F),
+    _ENTRY(G),
+    _ENTRY(H),
+    _ENTRY(I),
+    _ENTRY(J),
+    _ENTRY(K),
+    _ENTRY(L),
+    _ENTRY(M),
+    _ENTRY(N),
+    _ENTRY(O),
+    _ENTRY(P),
+    _ENTRY(Q),
+    _ENTRY(R),
+    _ENTRY(S),
+    _ENTRY(T),
+    _ENTRY(U),
+    _ENTRY(V),
+    _ENTRY(W),
+    _ENTRY(X),
+    _ENTRY(Y),
+    _ENTRY(Z),
+    _ENTRY(bracketleft),
+    _ENTRY(backslash),
+    _ENTRY(bracketright),
+    _ENTRY(asciicircum),
+    _ENTRY(underscore),
+    _ENTRY(grave),
+    _ENTRY(a),
+    _ENTRY(b),
+    _ENTRY(c),
+    _ENTRY(d),
+    _ENTRY(e),
+    _ENTRY(f),
+    _ENTRY(g),
+    _ENTRY(h),
+    _ENTRY(i),
+    _ENTRY(j),
+    _ENTRY(k),
+    _ENTRY(l),
+    _ENTRY(m),
+    _ENTRY(n),
+    _ENTRY(o),
+    _ENTRY(p),
+    _ENTRY(q),
+    _ENTRY(r),
+    _ENTRY(s),
+    _ENTRY(t),
+    _ENTRY(u),
+    _ENTRY(v),
+    _ENTRY(w),
+    _ENTRY(x),
+    _ENTRY(y),
+    _ENTRY(z),
+    _ENTRY(braceleft),
+    _ENTRY(bar),
+    _ENTRY(braceright),
+    _ENTRY(asciitilde),
+    _ENTRY(nobreakspace),
+    _ENTRY(exclamdown),
+    _ENTRY(cent),
+    _ENTRY(sterling),
+    _ENTRY(currency),
+    _ENTRY(yen),
+    _ENTRY(brokenbar),
+    _ENTRY(section),
+    _ENTRY(diaeresis),
+    _ENTRY(copyright),
+    _ENTRY(ordfeminine),
+    _ENTRY(guillemotleft),
+    _ENTRY(notsign),
+    _ENTRY(hyphen),
+    _ENTRY(registered),
+    _ENTRY(macron),
+    _ENTRY(degree),
+    _ENTRY(plusminus),
+    _ENTRY(twosuperior),
+    _ENTRY(threesuperior),
+    _ENTRY(acute),
+    _ENTRY(mu),
+    _ENTRY(paragraph),
+    _ENTRY(periodcentered),
+    _ENTRY(cedilla),
+    _ENTRY(onesuperior),
+    _ENTRY(masculine),
+    _ENTRY(guillemotright),
+    _ENTRY(onequarter),
+    _ENTRY(onehalf),
+    _ENTRY(threequarters),
+    _ENTRY(questiondown),
+    _ENTRY(Agrave),
+    _ENTRY(Aacute),
+    _ENTRY(Acircumflex),
+    _ENTRY(Atilde),
+    _ENTRY(Adiaeresis),
+    _ENTRY(Aring),
+    _ENTRY(AE),
+    _ENTRY(Ccedilla),
+    _ENTRY(Egrave),
+    _ENTRY(Eacute),
+    _ENTRY(Ecircumflex),
+    _ENTRY(Ediaeresis),
+    _ENTRY(Igrave),
+    _ENTRY(Iacute),
+    _ENTRY(Icircumflex),
+    _ENTRY(Idiaeresis),
+    _ENTRY(ETH),
+    _ENTRY(Eth),
+    _ENTRY(Ntilde),
+    _ENTRY(Ograve),
+    _ENTRY(Oacute),
+    _ENTRY(Ocircumflex),
+    _ENTRY(Otilde),
+    _ENTRY(Odiaeresis),
+    _ENTRY(multiply),
+    _ENTRY(Ooblique),
+    _ENTRY(Ugrave),
+    _ENTRY(Uacute),
+    _ENTRY(Ucircumflex),
+    _ENTRY(Udiaeresis),
+    _ENTRY(Yacute),
+    _ENTRY(THORN),
+    _ENTRY(Thorn),
+    _ENTRY(ssharp),
+    _ENTRY(agrave),
+    _ENTRY(aacute),
+    _ENTRY(acircumflex),
+    _ENTRY(atilde),
+    _ENTRY(adiaeresis),
+    _ENTRY(aring),
+    _ENTRY(ae),
+    _ENTRY(ccedilla),
+    _ENTRY(egrave),
+    _ENTRY(eacute),
+    _ENTRY(ecircumflex),
+    _ENTRY(ediaeresis),
+    _ENTRY(igrave),
+    _ENTRY(iacute),
+    _ENTRY(icircumflex),
+    _ENTRY(idiaeresis),
+    _ENTRY(eth),
+    _ENTRY(ntilde),
+    _ENTRY(ograve),
+    _ENTRY(oacute),
+    _ENTRY(ocircumflex),
+    _ENTRY(otilde),
+    _ENTRY(odiaeresis),
+    _ENTRY(division),
+    _ENTRY(oslash),
+    _ENTRY(ugrave),
+    _ENTRY(uacute),
+    _ENTRY(ucircumflex),
+    _ENTRY(udiaeresis),
+    _ENTRY(yacute),
+    _ENTRY(thorn),
+    _ENTRY(ydiaeresis),
+    _ENTRY(BackSpace),
+    _ENTRY(Tab),
+    _ENTRY(Return),
+    _ENTRY(Right),
+    _ENTRY(Left),
+    _ENTRY(Up),
+    _ENTRY(Down),
+    _ENTRY(Page_Down),
+    _ENTRY(Page_Up),
+    _ENTRY(Insert),
+    _ENTRY(Delete),
+    _ENTRY(Home),
+    _ENTRY(End),
+    _ENTRY(F1),
+    _ENTRY(F2),
+    _ENTRY(F3),
+    _ENTRY(F4),
+    _ENTRY(F5),
+    _ENTRY(F6),
+    _ENTRY(F7),
+    _ENTRY(F8),
+    _ENTRY(F9),
+    _ENTRY(F10),
+    _ENTRY(F11),
+    _ENTRY(F12),
+    _ENTRY(F13),
+    _ENTRY(F14),
+    _ENTRY(F15),
+    _ENTRY(F16),
+    _ENTRY(F17),
+    _ENTRY(F18),
+    _ENTRY(F19),
+    _ENTRY(F20),
+    _ENTRY(F21),
+    _ENTRY(F22),
+    _ENTRY(F23),
+    _ENTRY(F24),
+    _ENTRY(Escape),
+    _ENTRY(Mode_switch),
+    _ENTRY(ISO_Level3_Shift),
+    _ENTRY(ISO_Left_Tab),
+    _ENTRY(Sys_Req),
+    _ENTRY(Scroll_Lock),
+    _ENTRY(Multi_key),
+};
+
+#undef  _ENTRY
+
+#ifdef  DEBUG_LAYOUT
+static const char *
+kbd_sym2name(rfbKeySym keySym)
+{
+    int i;
+
+    for (i = 0; i < sizeof (name2keysym) / sizeof (name2keysym[0]); i++) {
+        kbd_name2sym_entry_t *entry = &name2keysym[i];
+
+        if (entry->value == keySym)
+            return entry->name;
+    }
+
+    return NULL;
+}
+#endif
+
+static rfbKeySym
+kbd_name2sym(const char *name)
+{
+    int i;
+
+    for (i = 0; i < sizeof (name2keysym) / sizeof (name2keysym[0]); i++) {
+        kbd_name2sym_entry_t *entry = &name2keysym[i];
+
+        if (!strcmp(entry->name, name))
+            return entry->value;
+    }
+
+    return XK_VoidSymbol;
+}
+
+static int
+kbd_range_add(kbd_range_t **rangep, int val)
+{
+    kbd_range_t *range;
+
+    for (range = *rangep; range != NULL; range = range->next) {
+        if (val >= range->start && val <= range->end)
+            break;
+
+        if (val == range->start - 1) {
+            range->start--;
+            break;
+        } else if (val == range->end + 1) {
+            range->end++;
+            break;
+        }
+    }
+
+    if (range != NULL)
+        goto done;
+
+       range = malloc(sizeof(kbd_range_t));
+    if (range == NULL)
+        goto fail1;
+
+    range->start = range->end = val;
+    range->next = *rangep;
+    *rangep = range;
+
+done:
+    return 0;
+
+fail1:
+    DBG("fail1\n");
+    warn("fail");
+
+    return -1;
+}
+
+static void
+kbd_range_free(kbd_range_t **rangep)
+{
+    kbd_range_t *range;
+
+    while ((range = *rangep) != NULL) {
+        *rangep = range->next;
+        free(range);
+    }
+}
+
+static void
+kbd_sym2code_add(const char *name, rfbKeySym sym, uint16_t code)
+{
+    kbd_layout_t    *layout = &kbd_state.layout;
+
+#ifdef  DEBUG_LAYOUT
+    DBG("%08X(%s) -> %04X\n", sym, name, code);
+#endif
+
+    if (sym < MAX_NORMAL_SYM) {
+        layout->sym2code[sym] = code;
+        goto done;
+    }
+
+    assert(layout->extra <= MAX_EXTRA_SYM);
+    if (layout->extra == MAX_EXTRA_SYM)
+        goto fail1;
+
+    layout->sym2code_extra[layout->extra].sym = sym;
+    layout->sym2code_extra[layout->extra].code = code;
+    layout->extra++;
+
+done:
+    return;
+
+fail1:
+    DBG("fail1\n");
+}
+
+static uint16_t
+kbd_sym2code(rfbKeySym sym)
+{
+    kbd_layout_t    *layout = &kbd_state.layout;
+    uint16_t        code;
+
+    if (sym < MAX_NORMAL_SYM) {
+        code = layout->sym2code[sym];
+    } else {
+        int i;
+
+        code = 0xFFFF;
+        for (i = 0; i < layout->extra; i++) {
+            if (sym == layout->sym2code_extra[i].sym) {
+                code = layout->sym2code_extra[i].code;
+                break;
+            }
+        }
+    }
+
+    return code;
+}
+
+
+#define MAX_LINE_LENGTH 1024
+
+static int
+kbd_parse_layout(const char *language)
+{
+    char    *name;
+    FILE    *f;
+    int     rc;
+
+    rc = asprintf(&name, "keymaps/%s", language);
+    if (rc < 0)
+        goto fail1;
+
+    f = fopen(name, "r");
+    if (f == NULL)
+        goto fail2;
+
+    for (;;) {
+        char        line[MAX_LINE_LENGTH];
+        const char  *delim = " \t\n";
+        char        *tok;
+        char        *name;
+        const char  *modifier;
+        rfbKeySym   sym;
+        uint16_t    code;
+        int         addupper;
+
+        memset(line, 0, sizeof (line));
+
+        if (fgets(line, sizeof (line), f) == NULL)
+            break;
+
+        if (line[0] == '#')
+            continue;
+
+        tok = strtok(line, delim);
+        if (tok == NULL)
+            continue;
+
+        if (!strcmp(tok, "map"))
+            continue;
+
+        if (!strcmp(tok, "include")) {
+            kbd_parse_layout(strtok(NULL, delim));
+            continue;
+        }
+
+        name = tok;
+
+        if (!strcmp(name, "ISO_Left_Tab"))
+            name = "Tab";
+
+        sym = kbd_name2sym(name);
+        if (sym == XK_VoidSymbol) {
+            DBG("unknown keysym %s\n", name);
+            continue;
+        }
+
+        tok = strtok(NULL, delim);
+        if (tok == NULL)
+            continue;
+
+        code = strtol(tok, NULL, 0);
+
+        tok = strtok(NULL, delim);
+
+        modifier = tok;
+
+        addupper = FALSE;
+        if (modifier != NULL) {
+            if (!strcmp(tok, "numlock")) {
+                rc = kbd_range_add(&kbd_state.layout.numlock_range, sym);
+                if (rc < 0)
+                    goto fail3;
+            }
+
+            if (!strcmp(tok, "shift")) {
+                code |= SCANCODE_SHIFT;
+            } else if (!strcmp(tok, "altgr")) {
+                code |= SCANCODE_ALTGR;
+            } else if (!strcmp(tok, "ctrl")) {
+                code |= SCANCODE_CTRL;
+            } else if (!strcmp(modifier, "addupper")) {
+                addupper = TRUE;
+            }
+        }
+
+        kbd_sym2code_add(name, sym, code);
+
+        if (addupper) {
+            char *c;
+
+            for (c = name; *c != '\0'; c++)
+                *c = toupper(*c);
+
+            sym = kbd_name2sym(name);
+            if (sym != XK_VoidSymbol)
+                kbd_sym2code_add(name, sym, code | SCANCODE_SHIFT);
+
+        }
+    }
+
+    fclose(f);
+    free(name);
+
+    return 0;
+
+fail3:
+    DBG("fail3\n");
+
+    kbd_range_free(&kbd_state.layout.numlock_range);
+
+    fclose(f);
+
+fail2:
+    DBG("fail2\n");
+
+    free(name);
+
+fail1:
+    DBG("fail1\n");
+
+    return -1;
+}
+
+static int
+kbd_sym_is_numlocked(rfbKeySym sym)
+{
+    kbd_range_t *range; 
+
+    for (range = kbd_state.layout.numlock_range;
+         range != NULL;
+         range = range->next) {
+        if (sym >= range->start && sym <= range->end)
+            return 1;
+    }
+
+    return 0;
+}
+
+static int
+kbd_sym_is_uppercase(rfbKeySym sym)
+{
+    return !!(sym >= XK_A && sym <= XK_Z);
+}
+
+static void
+kbd_press(rfbKeySym sym)
+{
+    uint16_t    code = kbd_sym2code(sym);
+
+    if (code & SCANCODE_GREY)
+        ps2_kbd_event(SCANCODE_EMUL0);
+
+    ps2_kbd_event(code & SCANCODE_KEYMASK);
+}
+
+static void
+kbd_release(rfbKeySym sym)
+{
+    uint16_t    code = kbd_sym2code(sym);
+
+    if (code & SCANCODE_GREY)
+        ps2_kbd_event(SCANCODE_EMUL0);
+
+    ps2_kbd_event((code & SCANCODE_KEYMASK) | SCANCODE_UP);
+}
+
+void
+kbd_event(rfbKeySym sym, int down)
+{
+    switch (sym) {
+    case XK_Shift_L:
+    case XK_Shift_R:
+        kbd_state.shift = !!down;
+        break;
+
+    case XK_Num_Lock:
+        kbd_state.numlock ^= !!down;
+        break;
+
+    case XK_Caps_Lock:
+        kbd_state.capslock ^= !!down;
+        break;
+    }
+
+    /* Check whether we missed a numlock or capslock press */
+    if (down) {
+        int numlock = kbd_sym_is_numlocked(sym);
+        int capslock = kbd_sym_is_uppercase(sym) && !kbd_state.shift;
+
+        if (kbd_state.numlock != numlock) {
+            kbd_press(XK_Num_Lock);
+            kbd_release(XK_Num_Lock);
+            kbd_state.numlock = numlock;
+        }
+        
+        if (kbd_state.capslock != capslock) {
+            kbd_press(XK_Caps_Lock);
+            kbd_release(XK_Caps_Lock);
+            kbd_state.capslock = capslock;
+        }
+
+        kbd_press(sym);
+    } else {
+        kbd_release(sym);
+    }
+}
+
+int
+kbd_initialize(const char *language)
+{
+    int rc;
+
+    memset(kbd_state.layout.sym2code,
+           0xFF,
+           sizeof (kbd_state.layout.sym2code));
+
+    rc = kbd_parse_layout(language);
+    if (rc < 0)
+        goto fail1;
+
+    return 0;
+
+fail1:
+    DBG("fail1\n");
+
+    return -1;
+}
+
+void
+kbd_teardown(void)
+{
+    kbd_range_free(&kbd_state.layout.numlock_range);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/kbd.h b/kbd.h
new file mode 100644 (file)
index 0000000..df7533e
--- /dev/null
+++ b/kbd.h
@@ -0,0 +1,54 @@
+/*  
+ * Copyright (c) 2014, Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * 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.
+ * 
+ * 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 THE COPYRIGHT
+ * HOLDER 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 <rfb/keysym.h>
+
+#ifndef  _KBD_H
+#define  _KBD_H
+
+int     kbd_initialize(const char *name);
+void    kbd_teardown(void);
+
+void    kbd_event(rfbKeySym sym, int down);
+
+#endif  /*_KBD_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
+
diff --git a/keymaps/common b/keymaps/common
new file mode 100644 (file)
index 0000000..adc56c7
--- /dev/null
@@ -0,0 +1,157 @@
+include modifiers
+
+#
+# Top row
+#
+1 0x2
+2 0x3
+3 0x4
+4 0x5
+5 0x6
+6 0x7
+7 0x8
+8 0x9
+9 0xa
+0 0xb
+BackSpace 0xe
+
+#
+# QWERTY first row
+#
+Tab 0xf localstate
+ISO_Left_Tab 0xf shift
+q 0x10 addupper
+w 0x11 addupper
+e 0x12 addupper
+r 0x13 addupper
+t 0x14 addupper
+y 0x15 addupper
+u 0x16 addupper
+i 0x17 addupper
+o 0x18 addupper
+p 0x19 addupper
+
+#
+# QWERTY second row
+#
+a 0x1e addupper
+s 0x1f addupper
+d 0x20 addupper
+f 0x21 addupper
+g 0x22 addupper
+h 0x23 addupper
+j 0x24 addupper
+k 0x25 addupper
+l 0x26 addupper
+Return 0x1c localstate
+
+#
+# QWERTY third row
+#
+z 0x2c addupper
+x 0x2d addupper
+c 0x2e addupper
+v 0x2f addupper
+b 0x30 addupper
+n 0x31 addupper
+m 0x32 addupper
+
+space 0x39 localstate
+
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+brokenbar 0x56 shift altgr
+
+#
+# Esc and Function keys
+#
+Escape 0x1 localstate
+F1 0x3b localstate
+F2 0x3c localstate
+F3 0x3d localstate
+F4 0x3e localstate
+F5 0x3f localstate
+F6 0x40 localstate
+F7 0x41 localstate
+F8 0x42 localstate
+F9 0x43 localstate
+F10 0x44 localstate
+F11 0x57 localstate
+F12 0x58 localstate
+
+# Printscreen, Scrollock and Pause
+# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
+# but (0xe0, 0x37) seems to work.
+Print 0xb7 localstate
+Sys_Req 0xb7 localstate
+Execute 0xb7 localstate
+Scroll_Lock 0x46
+
+#
+# Insert - PgDown
+#
+Insert 0xd2 localstate
+Delete 0xd3 localstate
+Home 0xc7 localstate
+End 0xcf localstate
+Page_Up 0xc9 localstate
+Page_Down 0xd1 localstate
+
+#
+# Arrow keys
+#
+Left 0xcb localstate
+Up 0xc8 localstate
+Down 0xd0 localstate
+Right 0xcd localstate
+
+#
+# Numpad
+#
+Num_Lock 0x45
+KP_Divide 0xb5
+KP_Multiply 0x37
+KP_Subtract 0x4a
+KP_Add 0x4e
+KP_Enter 0x9c
+
+KP_Decimal 0x53 numlock
+KP_Separator 0x53 numlock
+KP_Delete 0x53
+
+KP_0 0x52 numlock
+KP_Insert 0x52
+
+KP_1 0x4f numlock
+KP_End 0x4f
+
+KP_2 0x50 numlock
+KP_Down 0x50
+
+KP_3 0x51 numlock
+KP_Next 0x51
+
+KP_4 0x4b numlock
+KP_Left 0x4b
+
+KP_5 0x4c numlock
+KP_Begin 0x4c
+
+KP_6 0x4d numlock
+KP_Right 0x4d
+
+KP_7 0x47 numlock
+KP_Home 0x47
+
+KP_8 0x48 numlock
+KP_Up 0x48
+
+KP_9 0x49 numlock
+KP_Prior 0x49
+
+Caps_Lock 0x3a
+#
+# Inhibited keys
+#
+Multi_key 0x0 inhibit
diff --git a/keymaps/en-us b/keymaps/en-us
new file mode 100644 (file)
index 0000000..f5784bb
--- /dev/null
@@ -0,0 +1,35 @@
+# generated from XKB map us
+include common
+map 0x409
+exclam 0x02 shift
+at 0x03 shift
+numbersign 0x04 shift
+dollar 0x05 shift
+percent 0x06 shift
+asciicircum 0x07 shift
+ampersand 0x08 shift
+asterisk 0x09 shift
+parenleft 0x0a shift
+parenright 0x0b shift
+minus 0x0c
+underscore 0x0c shift
+equal 0x0d
+plus 0x0d shift
+bracketleft 0x1a
+braceleft 0x1a shift
+bracketright 0x1b
+braceright 0x1b shift
+semicolon 0x27
+colon 0x27 shift
+apostrophe 0x28
+quotedbl 0x28 shift
+grave 0x29
+asciitilde 0x29 shift
+backslash 0x2b
+bar 0x2b shift
+comma 0x33
+less 0x33 shift
+period 0x34
+greater 0x34 shift
+slash 0x35
+question 0x35 shift
diff --git a/keymaps/modifiers b/keymaps/modifiers
new file mode 100644 (file)
index 0000000..d73b7a6
--- /dev/null
@@ -0,0 +1,18 @@
+Shift_R 0x36
+Shift_L 0x2a
+
+Alt_R 0xb8
+Mode_switch 0xb8
+ISO_Level3_Shift 0xb8
+Alt_L 0x38
+
+Control_R 0x9d
+Control_L 0x1d
+
+# Translate Super to Windows keys.
+# This is hardcoded. See documentation for details.
+Super_R 0xdc
+Super_L 0xdb
+
+# Translate Menu to the Windows Application key.
+Menu 0xdd
diff --git a/ps2.c b/ps2.c
index 17227f5fac8f6bd55e033d88be1c094290efd61f..8743aaf4cdfb0fe02e8ab975abfd92cad302a74f 100644 (file)
--- a/ps2.c
+++ b/ps2.c
@@ -71,7 +71,7 @@
 #include "demu.h"
 
 //#define DEBUG_PS2
-#define DEBUG_KBD
+//#define DEBUG_KBD
 //#define DEBUG_AUX
 
 #define PS2_CMD_READ_MODE          0x20        /* Read mode bits */
@@ -483,6 +483,9 @@ ps2_read_data(void *priv, uint64_t addr)
 static void
 kbd_put_keycode(uint8_t keycode)
 {
+    if (!kbd_state.scan_enabled)
+        return;
+
     if (!kbd_state.translate &&
         keycode < 0xe0 &&
         kbd_state.scancode_set > 1) {
@@ -493,6 +496,7 @@ kbd_put_keycode(uint8_t keycode)
         else if (kbd_state.scancode_set == 3)
             keycode = ps2_raw_keycode_set3[keycode & 0x7f];
     }
+
     kbd_putq(keycode);
 }
 
@@ -1059,6 +1063,12 @@ ps2_mouse_event(int dx, int dy, int dz, int lb, int mb, int rb)
     aux_state.rb = rb;
 }
 
+void
+ps2_kbd_event(uint8_t keycode)
+{
+    kbd_put_keycode(keycode);
+}
+
 void
 ps2_teardown(void)
 {
diff --git a/ps2.h b/ps2.h
index a56925d212569e211c92bfc83803db15be3048bb..17d19c890e6b59897761c447a29922a3e4b940ee 100644 (file)
--- a/ps2.h
+++ b/ps2.h
@@ -32,6 +32,7 @@
 
 int         ps2_initialize(void);
 void        ps2_mouse_event(int dx, int dy, int dz, int lb, int mb, int rb);
+void        ps2_kbd_event(uint8_t keycode);
 void        ps2_teardown(void);
 
 #endif  /*_PS2_H */
diff --git a/roms/vgabios-stdvga.bin b/roms/vgabios-stdvga.bin
new file mode 100644 (file)
index 0000000..d329e24
Binary files /dev/null and b/roms/vgabios-stdvga.bin differ
diff --git a/vga.c b/vga.c
index a9862ebc1647e7b57708116776d5d17c6549028e..4f6496b85a826914b2af113926f993e0eead04e8 100644 (file)
--- a/vga.c
+++ b/vga.c
@@ -1339,6 +1339,7 @@ vga_initialize(unsigned int bus, unsigned int device, unsigned int function,
                uint64_t vram_size, char *romfile)
 {
     pci_info_t  info;
+    char        *name;
     struct stat st;
     int         rc;
 
@@ -1401,13 +1402,17 @@ vga_initialize(unsigned int bus, unsigned int device, unsigned int function,
     if (romfile == NULL)
         goto done;
 
-    vga_state.fd = open(romfile, O_RDONLY);
-    if (vga_state.fd < 0)
+    rc = asprintf(&name, "roms/%s", romfile);
+    if (rc < 0)
         goto fail6;
 
+    vga_state.fd = open(name, O_RDONLY);
+    if (vga_state.fd < 0)
+        goto fail7;
+
     rc = fstat(vga_state.fd, &st);
     if (rc < 0)
-        goto fail7;
+        goto fail8;
 
     vga_state.rom_size = P2ROUNDUP(st.st_size, TARGET_PAGE_SIZE);
 
@@ -1420,12 +1425,12 @@ vga_initialize(unsigned int bus, unsigned int device, unsigned int function,
                             vga_state.fd,
                             0);
     if (vga_state.rom == MAP_FAILED)
-        goto fail8;
+        goto fail9;
 
     if (vga_state.rom[0] != 0x55 &&
         vga_state.rom[1] != 0xAA) {
         errno = EINVAL;
-        goto fail9;
+        goto fail10;
     }
 
     rc = pci_bar_register(PCI_ROM_SLOT,
@@ -1435,28 +1440,35 @@ vga_initialize(unsigned int bus, unsigned int device, unsigned int function,
                           rom_bar_disable,
                           NULL);
     if (rc < 0)
-        goto fail10;
+        goto fail11;
+
+    free(name);
 
 done:
     pci_device_dump();
 
     return 0;
 
+fail11:
+    DBG("fail11\n");
+
 fail10:
     DBG("fail10\n");
 
+    munmap(vga_state.rom, vga_state.rom_size);
+
 fail9:
     DBG("fail9\n");
 
-    munmap(vga_state.rom, vga_state.rom_size);
-
 fail8:
     DBG("fail8\n");
 
+    close(vga_state.fd);
+
 fail7:
     DBG("fail7\n");
 
-    close(vga_state.fd);
+    free(name);
 
 fail6:
     DBG("fail6\n");
diff --git a/vgabios-stdvga.bin b/vgabios-stdvga.bin
deleted file mode 100644 (file)
index d329e24..0000000
Binary files a/vgabios-stdvga.bin and /dev/null differ