The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=e4643aa4c4ffd385a5be635a488cf10fb6d6cf68

commit e4643aa4c4ffd385a5be635a488cf10fb6d6cf68
Author:     Vladimir Kondratyev <w...@freebsd.org>
AuthorDate: 2021-04-11 23:08:36 +0000
Commit:     Vladimir Kondratyev <w...@freebsd.org>
CommitDate: 2021-04-11 23:14:12 +0000

    hv_kbd: Add support for K_XLATE and K_CODE modes for gen 2 VMs
    
    That fixes disabled keyboard input after Xorg server has been stopped.
    
    Reviewed by:    whu
    MFC after:      1 month
    Differential revision:  https://reviews.freebsd.org/D28171
---
 sys/dev/hyperv/input/hv_kbd.c  | 326 ++++++++++++++++++++++++++++++++++-------
 sys/dev/hyperv/input/hv_kbdc.h |   3 +
 2 files changed, 273 insertions(+), 56 deletions(-)

diff --git a/sys/dev/hyperv/input/hv_kbd.c b/sys/dev/hyperv/input/hv_kbd.c
index b1b0760ba13c..52ce621b2a89 100644
--- a/sys/dev/hyperv/input/hv_kbd.c
+++ b/sys/dev/hyperv/input/hv_kbd.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/module.h>
+#include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/taskqueue.h>
 #include <sys/selinfo.h>
@@ -81,6 +82,7 @@ __FBSDID("$FreeBSD$");
 #define        HVKBD_UNLOCK()          HVKBD_MTX_UNLOCK(&Giant)
 #define        HVKBD_LOCK_ASSERT()     HVKBD_MTX_ASSERT(&Giant, MA_OWNED)
 
+#define        HVKBD_FLAG_COMPOSE      0x00000001      /* compose char flag */
 #define HVKBD_FLAG_POLLING     0x00000002
 
 #ifdef EVDEV_SUPPORT
@@ -237,6 +239,8 @@ hvkbd_check_char_locked(keyboard_t *kbd)
                return (FALSE);
 
        hv_kbd_sc *sc = kbd->kb_data;
+       if (!(sc->sc_flags & HVKBD_FLAG_COMPOSE) && sc->sc_composed_char != 0)
+               return (TRUE);
        if (sc->sc_flags & HVKBD_FLAG_POLLING)
                hvkbd_do_poll(sc, 0);
        if (hv_kbd_prod_is_ready(sc)) {
@@ -262,6 +266,7 @@ static uint32_t
 hvkbd_read_char_locked(keyboard_t *kbd, int wait)
 {
        uint32_t scancode = NOKEY;
+       uint32_t action;
        keystroke ks;
        hv_kbd_sc *sc = kbd->kb_data;
 #ifdef EVDEV_SUPPORT
@@ -271,67 +276,268 @@ hvkbd_read_char_locked(keyboard_t *kbd, int wait)
 
        if (!KBD_IS_ACTIVE(kbd) || !hv_kbd_prod_is_ready(sc))
                return (NOKEY);
-       if (sc->sc_mode == K_RAW) {
-               if (hv_kbd_fetch_top(sc, &ks)) {
-                       return (NOKEY);
+
+next_code:
+
+       /* do we have a composed char to return? */
+       if (!(sc->sc_flags & HVKBD_FLAG_COMPOSE) && sc->sc_composed_char > 0) {
+               action = sc->sc_composed_char;
+               sc->sc_composed_char = 0;
+               if (action > UCHAR_MAX) {
+                       return (ERRKEY);
                }
-               if ((ks.info & IS_E0) || (ks.info & IS_E1)) {
-                       /**
-                        * Emulate the generation of E0 or E1 scancode,
-                        * the real scancode will be consumed next time.
-                        */
-                       if (ks.info & IS_E0) {
-                               scancode = XTKBD_EMUL0;
-                               ks.info &= ~IS_E0;
-                       } else if (ks.info & IS_E1) {
-                               scancode = XTKBD_EMUL1;
-                               ks.info &= ~IS_E1;
-                       }
-                       /**
-                        * Change the top item to avoid encountering
-                        * E0 or E1 twice.
-                        */
-                       hv_kbd_modify_top(sc, &ks);
-               } else if (ks.info & IS_UNICODE) {
-                       /**
-                        * XXX: Hyperv host send unicode to VM through
-                        * 'Type clipboard text', the mapping from
-                        * unicode to scancode depends on the keymap.
-                        * It is so complicated that we do not plan to
-                        * support it yet.
-                        */
-                       if (bootverbose)
-                               device_printf(sc->dev, "Unsupported unicode\n");
-                       hv_kbd_remove_top(sc);
-                       return (NOKEY);
-               } else {
-                       scancode = ks.makecode;
-                       if (ks.info & IS_BREAK) {
-                               scancode |= XTKBD_RELEASE;
-                       }
-                       hv_kbd_remove_top(sc);
+               return (action);
+       }
+
+       if (hv_kbd_fetch_top(sc, &ks)) {
+               return (NOKEY);
+       }
+       if ((ks.info & IS_E0) || (ks.info & IS_E1)) {
+               /**
+                * Emulate the generation of E0 or E1 scancode,
+                * the real scancode will be consumed next time.
+                */
+               if (ks.info & IS_E0) {
+                       scancode = XTKBD_EMUL0;
+                       ks.info &= ~IS_E0;
+               } else if (ks.info & IS_E1) {
+                       scancode = XTKBD_EMUL1;
+                       ks.info &= ~IS_E1;
                }
+               /**
+                * Change the top item to avoid encountering
+                * E0 or E1 twice.
+                */
+               hv_kbd_modify_top(sc, &ks);
+       } else if (ks.info & IS_UNICODE) {
+               /**
+                * XXX: Hyperv host send unicode to VM through
+                * 'Type clipboard text', the mapping from
+                * unicode to scancode depends on the keymap.
+                * It is so complicated that we do not plan to
+                * support it yet.
+                */
+               if (bootverbose)
+                       device_printf(sc->dev, "Unsupported unicode\n");
+               hv_kbd_remove_top(sc);
+               return (NOKEY);
+       } else {
+               scancode = ks.makecode;
+               if (ks.info & IS_BREAK) {
+                       scancode |= XTKBD_RELEASE;
+               }
+               hv_kbd_remove_top(sc);
+       }
 #ifdef EVDEV_SUPPORT
-               /* push evdev event */
-               if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD &&
-                   sc->ks_evdev != NULL) {
-                       keycode = evdev_scancode2key(&sc->ks_evdev_state,
-                           scancode);
-
-                       if (keycode != KEY_RESERVED) {
-                               evdev_push_event(sc->ks_evdev, EV_KEY,
-                                   (uint16_t)keycode, scancode & 0x80 ? 0 : 1);
-                               evdev_sync(sc->ks_evdev);
-                       }
+       /* push evdev event */
+       if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD &&
+           sc->ks_evdev != NULL) {
+               keycode = evdev_scancode2key(&sc->ks_evdev_state,
+                   scancode);
+
+               if (keycode != KEY_RESERVED) {
+                       evdev_push_event(sc->ks_evdev, EV_KEY,
+                           (uint16_t)keycode, scancode & 0x80 ? 0 : 1);
+                       evdev_sync(sc->ks_evdev);
                }
-#endif
-       } else {
-               if (bootverbose)
-                       device_printf(sc->dev, "Unsupported mode: %d\n", 
sc->sc_mode);
        }
+#endif
        ++kbd->kb_count;
        DEBUG_HVKBD(kbd, "read scan: 0x%x\n", scancode);
-       return scancode;
+
+       /* return the byte as is for the K_RAW mode */
+       if (sc->sc_mode == K_RAW)
+               return scancode;
+
+       /* translate the scan code into a keycode */
+       keycode = scancode & 0x7F;
+       switch (sc->sc_prefix) {
+       case 0x00:      /* normal scancode */
+               switch(scancode) {
+               case 0xB8:      /* left alt (compose key) released */
+                       if (sc->sc_flags & HVKBD_FLAG_COMPOSE) {
+                               sc->sc_flags &= ~HVKBD_FLAG_COMPOSE;
+                               if (sc->sc_composed_char > UCHAR_MAX)
+                                       sc->sc_composed_char = 0;
+                       }
+                       break;
+               case 0x38:      /* left alt (compose key) pressed */
+                       if (!(sc->sc_flags & HVKBD_FLAG_COMPOSE)) {
+                               sc->sc_flags |= HVKBD_FLAG_COMPOSE;
+                               sc->sc_composed_char = 0;
+                       }
+                       break;
+               case 0xE0:
+               case 0xE1:
+                       sc->sc_prefix = scancode;
+                       goto next_code;
+               }
+               break;
+       case 0xE0:              /* 0xE0 prefix */
+               sc->sc_prefix = 0;
+               switch (keycode) {
+               case 0x1C:      /* right enter key */
+                       keycode = 0x59;
+                       break;
+               case 0x1D:      /* right ctrl key */
+                       keycode = 0x5A;
+                       break;
+               case 0x35:      /* keypad divide key */
+                       keycode = 0x5B;
+                       break;
+               case 0x37:      /* print scrn key */
+                       keycode = 0x5C;
+                       break;
+               case 0x38:      /* right alt key (alt gr) */
+                       keycode = 0x5D;
+                       break;
+               case 0x46:      /* ctrl-pause/break on AT 101 (see below) */
+                       keycode = 0x68;
+                       break;
+               case 0x47:      /* grey home key */
+                       keycode = 0x5E;
+                       break;
+               case 0x48:      /* grey up arrow key */
+                       keycode = 0x5F;
+                       break;
+               case 0x49:      /* grey page up key */
+                       keycode = 0x60;
+                       break;
+               case 0x4B:      /* grey left arrow key */
+                       keycode = 0x61;
+                       break;
+               case 0x4D:      /* grey right arrow key */
+                       keycode = 0x62;
+                       break;
+               case 0x4F:      /* grey end key */
+                       keycode = 0x63;
+                       break;
+               case 0x50:      /* grey down arrow key */
+                       keycode = 0x64;
+                       break;
+               case 0x51:      /* grey page down key */
+                       keycode = 0x65;
+                       break;
+               case 0x52:      /* grey insert key */
+                       keycode = 0x66;
+                       break;
+               case 0x53:      /* grey delete key */
+                       keycode = 0x67;
+                       break;
+                       /* the following 3 are only used on the MS "Natural" 
keyboard */
+               case 0x5b:      /* left Window key */
+                       keycode = 0x69;
+                       break;
+               case 0x5c:      /* right Window key */
+                       keycode = 0x6a;
+                       break;
+               case 0x5d:      /* menu key */
+                       keycode = 0x6b;
+                       break;
+               case 0x5e:      /* power key */
+                       keycode = 0x6d;
+                       break;
+               case 0x5f:      /* sleep key */
+                       keycode = 0x6e;
+                       break;
+               case 0x63:      /* wake key */
+                       keycode = 0x6f;
+                       break;
+               default:        /* ignore everything else */
+                       goto next_code;
+               }
+               break;
+       case 0xE1:      /* 0xE1 prefix */
+               /*
+                * The pause/break key on the 101 keyboard produces:
+                * E1-1D-45 E1-9D-C5
+                * Ctrl-pause/break produces:
+                * E0-46 E0-C6 (See above.)
+                */
+               sc->sc_prefix = 0;
+               if (keycode == 0x1D)
+                       sc->sc_prefix = 0x1D;
+               goto next_code;
+               /* NOT REACHED */
+       case 0x1D:      /* pause / break */
+               sc->sc_prefix = 0;
+               if (keycode != 0x45)
+                       goto next_code;
+               keycode = 0x68;
+               break;
+       }
+
+       /* XXX assume 101/102 keys AT keyboard */
+       switch (keycode) {
+       case 0x5c:      /* print screen */
+               if (sc->sc_flags & ALTS)
+                       keycode = 0x54; /* sysrq */
+               break;
+       case 0x68:      /* pause/break */
+               if (sc->sc_flags & CTLS)
+                       keycode = 0x6c; /* break */
+               break;
+       }
+
+       /* return the key code in the K_CODE mode */
+       if (sc->sc_mode == K_CODE)
+               return (keycode | (scancode & 0x80));
+
+       /* compose a character code */
+       if (sc->sc_flags &  HVKBD_FLAG_COMPOSE) {
+               switch (keycode | (scancode & 0x80)) {
+               /* key pressed, process it */
+               case 0x47: case 0x48: case 0x49:        /* keypad 7,8,9 */
+                       sc->sc_composed_char *= 10;
+                       sc->sc_composed_char += keycode - 0x40;
+                       if (sc->sc_composed_char > UCHAR_MAX)
+                               return ERRKEY;
+                       goto next_code;
+               case 0x4B: case 0x4C: case 0x4D:        /* keypad 4,5,6 */
+                       sc->sc_composed_char *= 10;
+                       sc->sc_composed_char += keycode - 0x47;
+                       if (sc->sc_composed_char > UCHAR_MAX)
+                               return ERRKEY;
+                       goto next_code;
+               case 0x4F: case 0x50: case 0x51:        /* keypad 1,2,3 */
+                       sc->sc_composed_char *= 10;
+                       sc->sc_composed_char += keycode - 0x4E;
+                       if (sc->sc_composed_char > UCHAR_MAX)
+                               return ERRKEY;
+                       goto next_code;
+               case 0x52:                              /* keypad 0 */
+                       sc->sc_composed_char *= 10;
+                       if (sc->sc_composed_char > UCHAR_MAX)
+                               return ERRKEY;
+                       goto next_code;
+
+               /* key released, no interest here */
+               case 0xC7: case 0xC8: case 0xC9:        /* keypad 7,8,9 */
+               case 0xCB: case 0xCC: case 0xCD:        /* keypad 4,5,6 */
+               case 0xCF: case 0xD0: case 0xD1:        /* keypad 1,2,3 */
+               case 0xD2:                              /* keypad 0 */
+                       goto next_code;
+
+               case 0x38:                              /* left alt key */
+                       break;
+
+               default:
+                       if (sc->sc_composed_char > 0) {
+                               sc->sc_flags &= ~HVKBD_FLAG_COMPOSE;
+                               sc->sc_composed_char = 0;
+                               return (ERRKEY);
+                       }
+                       break;
+               }
+       }
+
+       /* keycode to key action */
+       action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
+                                 &sc->sc_state, &sc->sc_accents);
+       if (action == NOKEY)
+               goto next_code;
+       else
+               return (action);
 }
 
 /* Currently wait is always false. */
@@ -353,7 +559,9 @@ hvkbd_clear_state(keyboard_t *kbd)
 {
        hv_kbd_sc *sc = kbd->kb_data;
        sc->sc_state &= LOCK_MASK;      /* preserve locking key state */
-       sc->sc_flags &= ~HVKBD_FLAG_POLLING;
+       sc->sc_flags &= ~(HVKBD_FLAG_POLLING | HVKBD_FLAG_COMPOSE);
+       sc->sc_accents = 0;
+       sc->sc_composed_char = 0;
 }
 
 static int
@@ -453,6 +661,12 @@ hvkbd_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t 
arg)
 #endif
                KBD_LED_VAL(kbd) = *(int *)arg;
                break;
+       case PIO_KEYMAP:        /* set keyboard translation table */
+       case OPIO_KEYMAP:       /* set keyboard translation table (compat) */
+       case PIO_KEYMAPENT:     /* set keyboard translation table entry */
+       case PIO_DEADKEYMAP:    /* set accent key translation table */
+               sc->sc_accents = 0;
+               /* FALLTHROUGH */
        default:
                return (genkbd_commonioctl(kbd, cmd, arg));
        }
@@ -578,7 +792,7 @@ hv_kbd_drv_attach(device_t dev)
        hvkbd_clear_state(kbd);
        KBD_PROBE_DONE(kbd);
        KBD_INIT_DONE(kbd);
-       sc->sc_mode = K_RAW;
+       sc->sc_mode = K_XLATE;
        (*sw->enable)(kbd);
 
 #ifdef EVDEV_SUPPORT
diff --git a/sys/dev/hyperv/input/hv_kbdc.h b/sys/dev/hyperv/input/hv_kbdc.h
index 562009df9a94..7effa6b8a49b 100644
--- a/sys/dev/hyperv/input/hv_kbdc.h
+++ b/sys/dev/hyperv/input/hv_kbdc.h
@@ -90,6 +90,9 @@ typedef struct hv_kbd_sc_t {
        keyboard_t                      sc_kbd;
        int                             sc_mode;
        int                             sc_state;
+       uint32_t                        sc_accents;     /* accent key index (> 
0) */
+       uint32_t                        sc_composed_char; /* composed char code 
*/
+       uint8_t                         sc_prefix;      /* AT scan code prefix 
*/
        int                             sc_polling;     /* polling recursion 
count */
        uint32_t                        sc_flags;
        int                             debug;
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to