Author: hselasky
Date: Thu Feb 13 16:03:12 2020
New Revision: 357861
URL: https://svnweb.freebsd.org/changeset/base/357861

Log:
  Improve USB gaming keyboard support.
  
  Add support for decoding pressed keys as a bitmap. The keys in the
  bitmap are described in the interface specific HID descriptor. Some
  keyboards even have multiple input interfaces, only using the bitmap
  method when the event array is full. That typically means when more
  than seven keys are pressed simultaneously.
  
  The internals of the USB keyboard driver have been slightly reworked
  to keep track of all keys in a single bitmap having 256 bits. This
  bitmap is then divided into blocks of 64-bits as an optimisation.
  
  Simplify automatic key repeat logic, because only the last key pressed
  can be repeated.
  
  PR:   224592
  PR:   233884
  Tested by:    Alex V. Petrov <alexvpet...@gmail.com>
  MFC after:    1 week
  Sponsored by: Mellanox Technologies

Modified:
  head/sys/dev/usb/input/ukbd.c

Modified: head/sys/dev/usb/input/ukbd.c
==============================================================================
--- head/sys/dev/usb/input/ukbd.c       Thu Feb 13 15:42:14 2020        
(r357860)
+++ head/sys/dev/usb/input/ukbd.c       Thu Feb 13 16:03:12 2020        
(r357861)
@@ -109,27 +109,21 @@ SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_R
 
 #define        UKBD_EMULATE_ATSCANCODE        1
 #define        UKBD_DRIVER_NAME          "ukbd"
-#define        UKBD_NMOD                     8 /* units */
-#define        UKBD_NKEYCODE                 6 /* units */
-#define        UKBD_IN_BUF_SIZE  (2*(UKBD_NMOD + (2*UKBD_NKEYCODE)))   /* 
bytes */
-#define        UKBD_IN_BUF_FULL  ((UKBD_IN_BUF_SIZE / 2) - 1)  /* bytes */
+#define        UKBD_NKEYCODE                 256 /* units */
+#define        UKBD_IN_BUF_SIZE  (4 * UKBD_NKEYCODE) /* scancodes */
+#define        UKBD_IN_BUF_FULL  ((UKBD_IN_BUF_SIZE / 2) - 1)  /* scancodes */
 #define        UKBD_NFKEY        (sizeof(fkey_tab)/sizeof(fkey_tab[0]))        
/* units */
 #define        UKBD_BUFFER_SIZE              64        /* bytes */
+#define        UKBD_KEY_PRESSED(map, key) ({ \
+       CTASSERT((key) >= 0 && (key) < UKBD_NKEYCODE); \
+       ((map)[(key) / 64] & (1ULL << ((key) % 64))); \
+})
 
+#define        MOD_EJECT       0x01
+#define        MOD_FN          0x02
+
 struct ukbd_data {
-       uint16_t        modifiers;
-#define        MOD_CONTROL_L   0x01
-#define        MOD_CONTROL_R   0x10
-#define        MOD_SHIFT_L     0x02
-#define        MOD_SHIFT_R     0x20
-#define        MOD_ALT_L       0x04
-#define        MOD_ALT_R       0x40
-#define        MOD_WIN_L       0x08
-#define        MOD_WIN_R       0x80
-/* internal */
-#define        MOD_EJECT       0x0100
-#define        MOD_FN          0x0200
-       uint8_t keycode[UKBD_NKEYCODE];
+       uint64_t bitmap[howmany(UKBD_NKEYCODE, 64)];
 };
 
 enum {
@@ -144,17 +138,10 @@ struct ukbd_softc {
        keymap_t sc_keymap;
        accentmap_t sc_accmap;
        fkeytab_t sc_fkeymap[UKBD_NFKEY];
+       uint64_t sc_loc_key_valid[howmany(UKBD_NKEYCODE, 64)];
        struct hid_location sc_loc_apple_eject;
        struct hid_location sc_loc_apple_fn;
-       struct hid_location sc_loc_ctrl_l;
-       struct hid_location sc_loc_ctrl_r;
-       struct hid_location sc_loc_shift_l;
-       struct hid_location sc_loc_shift_r;
-       struct hid_location sc_loc_alt_l;
-       struct hid_location sc_loc_alt_r;
-       struct hid_location sc_loc_win_l;
-       struct hid_location sc_loc_win_r;
-       struct hid_location sc_loc_events;
+       struct hid_location sc_loc_key[UKBD_NKEYCODE];
        struct hid_location sc_loc_numlock;
        struct hid_location sc_loc_capslock;
        struct hid_location sc_loc_scrolllock;
@@ -172,8 +159,7 @@ struct ukbd_softc {
 
        sbintime_t sc_co_basetime;
        int     sc_delay;
-       uint32_t sc_ntime[UKBD_NKEYCODE];
-       uint32_t sc_otime[UKBD_NKEYCODE];
+       uint32_t sc_repeat_time;
        uint32_t sc_input[UKBD_IN_BUF_SIZE];    /* input buffer */
        uint32_t sc_time_ms;
        uint32_t sc_composed_char;      /* composed char code, if non-zero */
@@ -191,15 +177,6 @@ struct ukbd_softc {
 #define        UKBD_FLAG_APPLE_EJECT   0x00000040
 #define        UKBD_FLAG_APPLE_FN      0x00000080
 #define        UKBD_FLAG_APPLE_SWAP    0x00000100
-#define        UKBD_FLAG_CTRL_L        0x00000400
-#define        UKBD_FLAG_CTRL_R        0x00000800
-#define        UKBD_FLAG_SHIFT_L       0x00001000
-#define        UKBD_FLAG_SHIFT_R       0x00002000
-#define        UKBD_FLAG_ALT_L         0x00004000
-#define        UKBD_FLAG_ALT_R         0x00008000
-#define        UKBD_FLAG_WIN_L         0x00010000
-#define        UKBD_FLAG_WIN_R         0x00020000
-#define        UKBD_FLAG_EVENTS        0x00040000
 #define        UKBD_FLAG_NUMLOCK       0x00080000
 #define        UKBD_FLAG_CAPSLOCK      0x00100000
 #define        UKBD_FLAG_SCROLLLOCK    0x00200000
@@ -214,31 +191,23 @@ struct ukbd_softc {
        uint16_t sc_inputs;
        uint16_t sc_inputhead;
        uint16_t sc_inputtail;
-       uint16_t sc_modifiers;
 
        uint8_t sc_leds;                /* store for async led requests */
        uint8_t sc_iface_index;
        uint8_t sc_iface_no;
        uint8_t sc_id_apple_eject;
        uint8_t sc_id_apple_fn;
-       uint8_t sc_id_ctrl_l;
-       uint8_t sc_id_ctrl_r;
-       uint8_t sc_id_shift_l;
-       uint8_t sc_id_shift_r;
-       uint8_t sc_id_alt_l;
-       uint8_t sc_id_alt_r;
-       uint8_t sc_id_win_l;
-       uint8_t sc_id_win_r;
-       uint8_t sc_id_event;
+       uint8_t sc_id_loc_key[UKBD_NKEYCODE];
        uint8_t sc_id_numlock;
        uint8_t sc_id_capslock;
        uint8_t sc_id_scrolllock;
-       uint8_t sc_id_events;
        uint8_t sc_kbd_id;
+       uint8_t sc_repeat_key;
 
        uint8_t sc_buffer[UKBD_BUFFER_SIZE];
 };
 
+#define        KEY_NONE          0x00
 #define        KEY_ERROR         0x01
 
 #define        KEY_PRESS         0
@@ -259,21 +228,6 @@ struct ukbd_softc {
 #define        UKBD_UNLOCK()   USB_MTX_UNLOCK(&Giant)
 #define        UKBD_LOCK_ASSERT()      USB_MTX_ASSERT(&Giant, MA_OWNED)
 
-struct ukbd_mods {
-       uint32_t mask, key;
-};
-
-static const struct ukbd_mods ukbd_mods[UKBD_NMOD] = {
-       {MOD_CONTROL_L, 0xe0},
-       {MOD_CONTROL_R, 0xe4},
-       {MOD_SHIFT_L, 0xe1},
-       {MOD_SHIFT_R, 0xe5},
-       {MOD_ALT_L, 0xe2},
-       {MOD_ALT_R, 0xe6},
-       {MOD_WIN_L, 0xe3},
-       {MOD_WIN_R, 0xe7},
-};
-
 #define        NN 0                            /* no translation */
 /*
  * Translate USB keycodes to AT keyboard scancodes.
@@ -347,8 +301,8 @@ static void ukbd_timeout(void *);
 static void    ukbd_set_leds(struct ukbd_softc *, uint8_t);
 static int     ukbd_set_typematic(keyboard_t *, int);
 #ifdef UKBD_EMULATE_ATSCANCODE
-static uint32_t        ukbd_atkeycode(int, int);
-static int     ukbd_key2scan(struct ukbd_softc *, int, int, int);
+static uint32_t        ukbd_atkeycode(int, const uint64_t *);
+static int     ukbd_key2scan(struct ukbd_softc *, int, const uint64_t *, int);
 #endif
 static uint32_t        ukbd_read_char(keyboard_t *, int);
 static void    ukbd_clear_state(keyboard_t *);
@@ -371,16 +325,26 @@ static const struct evdev_methods ukbd_evdev_methods =
 };
 #endif
 
-static uint8_t
+static bool
 ukbd_any_key_pressed(struct ukbd_softc *sc)
 {
-       uint8_t i;
-       uint8_t j;
+       bool ret = false;
+       unsigned i;
 
-       for (j = i = 0; i < UKBD_NKEYCODE; i++)
-               j |= sc->sc_odata.keycode[i];
+       for (i = 0; i != howmany(UKBD_NKEYCODE, 64); i++)
+               ret |= (sc->sc_odata.bitmap[i] != 0);
+       return (ret);
+}
 
-       return (j ? 1 : 0);
+static bool
+ukbd_any_key_valid(struct ukbd_softc *sc)
+{
+       bool ret = false;
+       unsigned i;
+
+       for (i = 0; i != howmany(UKBD_NKEYCODE, 64); i++)
+               ret |= (sc->sc_loc_key_valid[i] != 0);
+       return (ret);
 }
 
 static void
@@ -522,99 +486,63 @@ ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
 static void
 ukbd_interrupt(struct ukbd_softc *sc)
 {
-       uint32_t n_mod;
-       uint32_t o_mod;
-       uint32_t now = sc->sc_time_ms;
-       int32_t dtime;
-       uint8_t key;
-       uint8_t i;
-       uint8_t j;
+       const uint32_t now = sc->sc_time_ms;
+       unsigned key;
+       bool old_keys;
 
        UKBD_LOCK_ASSERT();
 
-       if (sc->sc_ndata.keycode[0] == KEY_ERROR)
-               return;
+       old_keys = ukbd_any_key_pressed(sc);
 
-       n_mod = sc->sc_ndata.modifiers;
-       o_mod = sc->sc_odata.modifiers;
-       if (n_mod != o_mod) {
-               for (i = 0; i < UKBD_NMOD; i++) {
-                       if ((n_mod & ukbd_mods[i].mask) !=
-                           (o_mod & ukbd_mods[i].mask)) {
-                               ukbd_put_key(sc, ukbd_mods[i].key |
-                                   ((n_mod & ukbd_mods[i].mask) ?
-                                   KEY_PRESS : KEY_RELEASE));
-                       }
-               }
-       }
-       /* Check for released keys. */
-       for (i = 0; i < UKBD_NKEYCODE; i++) {
-               key = sc->sc_odata.keycode[i];
-               if (key == 0) {
-                       continue;
-               }
-               for (j = 0; j < UKBD_NKEYCODE; j++) {
-                       if (sc->sc_ndata.keycode[j] == 0) {
-                               continue;
-                       }
-                       if (key == sc->sc_ndata.keycode[j]) {
-                               goto rfound;
-                       }
-               }
-               ukbd_put_key(sc, key | KEY_RELEASE);
-rfound:        ;
-       }
+       /* Check for key changes */
+       for (key = 0; key != UKBD_NKEYCODE; key++) {
+               const uint64_t mask = 1ULL << (key % 64);
+               const uint64_t delta =
+                   sc->sc_odata.bitmap[key / 64] ^
+                   sc->sc_ndata.bitmap[key / 64];
 
-       /* Check for pressed keys. */
-       for (i = 0; i < UKBD_NKEYCODE; i++) {
-               key = sc->sc_ndata.keycode[i];
-               if (key == 0) {
-                       continue;
-               }
-               sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay1;
-               for (j = 0; j < UKBD_NKEYCODE; j++) {
-                       if (sc->sc_odata.keycode[j] == 0) {
-                               continue;
-                       }
-                       if (key == sc->sc_odata.keycode[j]) {
+               if (mask == 1 && delta == 0) {
+                       key += 63;
+                       continue;       /* skip empty areas */
+               } else if (delta & mask) {
+                       if (sc->sc_odata.bitmap[key / 64] & mask) {
+                               ukbd_put_key(sc, key | KEY_RELEASE);
 
-                               /* key is still pressed */
+                               /* clear repeating key, if any */
+                               if (sc->sc_repeat_key == key)
+                                       sc->sc_repeat_key = 0;
+                       } else {
+                               ukbd_put_key(sc, key | KEY_PRESS);
 
-                               sc->sc_ntime[i] = sc->sc_otime[j];
-                               dtime = (sc->sc_otime[j] - now);
-
-                               if (dtime > 0) {
-                                       /* time has not elapsed */
-                                       goto pfound;
-                               }
-                               sc->sc_ntime[i] = now + sc->sc_kbd.kb_delay2;
-                               break;
+                               /* set repeat time for last key */
+                               sc->sc_repeat_time = now + sc->sc_kbd.kb_delay1;
+                               sc->sc_repeat_key = key;
                        }
                }
-               if (j == UKBD_NKEYCODE) {
-                       /* New key - set initial delay and [re]start timer */
-                       sc->sc_co_basetime = sbinuptime();
-                       sc->sc_delay = sc->sc_kbd.kb_delay1;
-                       ukbd_start_timer(sc);
-               }
-               ukbd_put_key(sc, key | KEY_PRESS);
-
-               /*
-                 * If any other key is presently down, force its repeat to be
-                 * well in the future (100s).  This makes the last key to be
-                 * pressed do the autorepeat.
-                 */
-               for (j = 0; j != UKBD_NKEYCODE; j++) {
-                       if (j != i)
-                               sc->sc_ntime[j] = now + (100 * 1000);
-               }
-pfound:        ;
        }
 
+       /* synchronize old data with new data */
        sc->sc_odata = sc->sc_ndata;
+       
+       /* check if last key is still pressed */
+       if (sc->sc_repeat_key != 0) {
+               const int32_t dtime = (sc->sc_repeat_time - now);
 
-       memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime));
+               /* check if time has elapsed */
+               if (dtime <= 0) {
+                       ukbd_put_key(sc, sc->sc_repeat_key | KEY_PRESS);
+                       sc->sc_repeat_time = now + sc->sc_kbd.kb_delay2;
+               }
+       }
 
+       /* check for first new key and set initial delay and [re]start timer */
+       if (old_keys == false && ukbd_any_key_pressed(sc) == true) {
+               sc->sc_co_basetime = sbinuptime();
+               sc->sc_delay = sc->sc_kbd.kb_delay1;
+               ukbd_start_timer(sc);
+       }
+
+       /* wakeup keyboard system */
        ukbd_event_keyinput(sc);
 }
 
@@ -664,8 +592,9 @@ ukbd_timeout(void *arg)
        }
 }
 
-static uint8_t
-ukbd_apple_fn(uint8_t keycode) {
+static uint32_t
+ukbd_apple_fn(uint32_t keycode)
+{
        switch (keycode) {
        case 0x28: return 0x49; /* RETURN -> INSERT */
        case 0x2a: return 0x4c; /* BACKSPACE -> DEL */
@@ -677,8 +606,9 @@ ukbd_apple_fn(uint8_t keycode) {
        }
 }
 
-static uint8_t
-ukbd_apple_swap(uint8_t keycode) {
+static uint32_t
+ukbd_apple_swap(uint32_t keycode)
+{
        switch (keycode) {
        case 0x35: return 0x64;
        case 0x64: return 0x35;
@@ -691,9 +621,10 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t 
 {
        struct ukbd_softc *sc = usbd_xfer_softc(xfer);
        struct usb_page_cache *pc;
-       uint8_t i;
-       uint8_t offset;
+       uint32_t i;
        uint8_t id;
+       uint8_t modifiers;
+       int offset;
        int len;
 
        UKBD_LOCK_ASSERT();
@@ -733,117 +664,72 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t 
                /* clear temporary storage */
                memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
 
+               /* clear modifiers */
+               modifiers = 0;
+
                /* scan through HID data */
                if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) &&
                    (id == sc->sc_id_apple_eject)) {
                        if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_apple_eject))
-                               sc->sc_modifiers |= MOD_EJECT;
-                       else
-                               sc->sc_modifiers &= ~MOD_EJECT;
+                               modifiers |= MOD_EJECT;
                }
                if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) &&
                    (id == sc->sc_id_apple_fn)) {
                        if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_apple_fn))
-                               sc->sc_modifiers |= MOD_FN;
-                       else
-                               sc->sc_modifiers &= ~MOD_FN;
+                               modifiers |= MOD_FN;
                }
-               if ((sc->sc_flags & UKBD_FLAG_CTRL_L) &&
-                   (id == sc->sc_id_ctrl_l)) {
-                       if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_ctrl_l))
-                         sc->  sc_modifiers |= MOD_CONTROL_L;
-                       else
-                         sc->  sc_modifiers &= ~MOD_CONTROL_L;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_CTRL_R) &&
-                   (id == sc->sc_id_ctrl_r)) {
-                       if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_ctrl_r))
-                               sc->sc_modifiers |= MOD_CONTROL_R;
-                       else
-                               sc->sc_modifiers &= ~MOD_CONTROL_R;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) &&
-                   (id == sc->sc_id_shift_l)) {
-                       if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_shift_l))
-                               sc->sc_modifiers |= MOD_SHIFT_L;
-                       else
-                               sc->sc_modifiers &= ~MOD_SHIFT_L;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) &&
-                   (id == sc->sc_id_shift_r)) {
-                       if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_shift_r))
-                               sc->sc_modifiers |= MOD_SHIFT_R;
-                       else
-                               sc->sc_modifiers &= ~MOD_SHIFT_R;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_ALT_L) &&
-                   (id == sc->sc_id_alt_l)) {
-                       if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l))
-                               sc->sc_modifiers |= MOD_ALT_L;
-                       else
-                               sc->sc_modifiers &= ~MOD_ALT_L;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_ALT_R) &&
-                   (id == sc->sc_id_alt_r)) {
-                       if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r))
-                               sc->sc_modifiers |= MOD_ALT_R;
-                       else
-                               sc->sc_modifiers &= ~MOD_ALT_R;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_WIN_L) &&
-                   (id == sc->sc_id_win_l)) {
-                       if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l))
-                               sc->sc_modifiers |= MOD_WIN_L;
-                       else
-                               sc->sc_modifiers &= ~MOD_WIN_L;
-               }
-               if ((sc->sc_flags & UKBD_FLAG_WIN_R) &&
-                   (id == sc->sc_id_win_r)) {
-                       if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r))
-                               sc->sc_modifiers |= MOD_WIN_R;
-                       else
-                               sc->sc_modifiers &= ~MOD_WIN_R;
-               }
 
-               sc->sc_ndata.modifiers = sc->sc_modifiers;
+               for (i = 0; i != UKBD_NKEYCODE; i++) {
+                       const uint64_t valid = sc->sc_loc_key_valid[i / 64];
+                       const uint64_t mask = 1ULL << (i % 64);
 
-               if ((sc->sc_flags & UKBD_FLAG_EVENTS) &&
-                   (id == sc->sc_id_events)) {
-                       i = sc->sc_loc_events.count;
-                       if (i > UKBD_NKEYCODE)
-                               i = UKBD_NKEYCODE;
-                       if (i > len)
-                               i = len;
-                       while (i--) {
-                               sc->sc_ndata.keycode[i] =
-                                   hid_get_data(sc->sc_buffer + i, len - i,
-                                   &sc->sc_loc_events);
-                       }
-               }
+                       if (mask == 1 && valid == 0) {
+                               i += 63;
+                               continue;       /* skip empty areas */
+                       } else if (~valid & mask) {
+                               continue;       /* location is not valid */
+                       } else if (id != sc->sc_id_loc_key[i]) {
+                               continue;       /* invalid HID ID */
+                       } else if (i == 0) {
+                               offset = sc->sc_loc_key[0].count;
+                               if (offset < 0 || offset > len)
+                                       offset = len;
+                               while (offset--) {
+                                       uint32_t key =
+                                           hid_get_data(sc->sc_buffer + 
offset, len - offset,
+                                           &sc->sc_loc_key[i]);
+                                       if (modifiers & MOD_FN)
+                                               key = ukbd_apple_fn(key);
+                                       if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP)
+                                               key = ukbd_apple_swap(key);
+                                       if (key == KEY_NONE || key == KEY_ERROR 
|| key >= UKBD_NKEYCODE)
+                                               continue;
+                                       /* set key in bitmap */
+                                       sc->sc_ndata.bitmap[key / 64] |= 1ULL 
<< (key % 64);
+                               }
+                       } else if (hid_get_data(sc->sc_buffer, len, 
&sc->sc_loc_key[i])) {
+                               uint32_t key = i;
 
-#ifdef USB_DEBUG
-               DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers);
-               for (i = 0; i < UKBD_NKEYCODE; i++) {
-                       if (sc->sc_ndata.keycode[i]) {
-                               DPRINTF("[%d] = 0x%02x\n",
-                                   (int)i, (int)sc->sc_ndata.keycode[i]);
+                               if (modifiers & MOD_FN)
+                                       key = ukbd_apple_fn(key);
+                               if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP)
+                                       key = ukbd_apple_swap(key);
+                               if (key == KEY_NONE || key == KEY_ERROR || key 
>= UKBD_NKEYCODE)
+                                       continue;
+                               /* set key in bitmap */
+                               sc->sc_ndata.bitmap[key / 64] |= 1ULL << (key % 
64);
                        }
                }
-#endif
-               if (sc->sc_modifiers & MOD_FN) {
-                       for (i = 0; i < UKBD_NKEYCODE; i++) {
-                               sc->sc_ndata.keycode[i] = 
-                                   ukbd_apple_fn(sc->sc_ndata.keycode[i]);
-                       }
-               }
+#ifdef USB_DEBUG
+               DPRINTF("modifiers = 0x%04x\n", modifiers);
+               for (i = 0; i != UKBD_NKEYCODE; i++) {
+                       const uint64_t valid = sc->sc_ndata.bitmap[i / 64];
+                       const uint64_t mask = 1ULL << (i % 64);
 
-               if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) {
-                       for (i = 0; i < UKBD_NKEYCODE; i++) {
-                               sc->sc_ndata.keycode[i] = 
-                                   ukbd_apple_swap(sc->sc_ndata.keycode[i]);
-                       }
+                       if (valid & mask)
+                               DPRINTF("Key 0x%02x pressed\n", i);
                }
-
+#endif
                ukbd_interrupt(sc);
 
        case USB_ST_SETUP:
@@ -1072,10 +958,14 @@ static void
 ukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len)
 {
        uint32_t flags;
+       uint32_t key;
 
        /* reset detected bits */
        sc->sc_flags &= ~UKBD_FLAG_HID_MASK;
 
+       /* reset detected keys */
+       memset(sc->sc_loc_key_valid, 0, sizeof(sc->sc_loc_key_valid));
+
        /* check if there is an ID byte */
        sc->sc_kbd_size = hid_report_size(ptr, len,
            hid_input, &sc->sc_kbd_id);
@@ -1098,84 +988,34 @@ ukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *p
                        sc->sc_flags |= UKBD_FLAG_APPLE_FN;
                DPRINTFN(1, "Found Apple FN-key\n");
        }
-       /* figure out some keys */
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE0),
-           hid_input, 0, &sc->sc_loc_ctrl_l, &flags,
-           &sc->sc_id_ctrl_l)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_CTRL_L;
-               DPRINTFN(1, "Found left control\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE4),
-           hid_input, 0, &sc->sc_loc_ctrl_r, &flags,
-           &sc->sc_id_ctrl_r)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_CTRL_R;
-               DPRINTFN(1, "Found right control\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE1),
-           hid_input, 0, &sc->sc_loc_shift_l, &flags,
-           &sc->sc_id_shift_l)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_SHIFT_L;
-               DPRINTFN(1, "Found left shift\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE5),
-           hid_input, 0, &sc->sc_loc_shift_r, &flags,
-           &sc->sc_id_shift_r)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_SHIFT_R;
-               DPRINTFN(1, "Found right shift\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE2),
-           hid_input, 0, &sc->sc_loc_alt_l, &flags,
-           &sc->sc_id_alt_l)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_ALT_L;
-               DPRINTFN(1, "Found left alt\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE6),
-           hid_input, 0, &sc->sc_loc_alt_r, &flags,
-           &sc->sc_id_alt_r)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_ALT_R;
-               DPRINTFN(1, "Found right alt\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE3),
-           hid_input, 0, &sc->sc_loc_win_l, &flags,
-           &sc->sc_id_win_l)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_WIN_L;
-               DPRINTFN(1, "Found left GUI\n");
-       }
-       if (hid_locate(ptr, len,
-           HID_USAGE2(HUP_KEYBOARD, 0xE7),
-           hid_input, 0, &sc->sc_loc_win_r, &flags,
-           &sc->sc_id_win_r)) {
-               if (flags & HIO_VARIABLE)
-                       sc->sc_flags |= UKBD_FLAG_WIN_R;
-               DPRINTFN(1, "Found right GUI\n");
-       }
+
        /* figure out event buffer */
        if (hid_locate(ptr, len,
            HID_USAGE2(HUP_KEYBOARD, 0x00),
-           hid_input, 0, &sc->sc_loc_events, &flags,
-           &sc->sc_id_events)) {
+           hid_input, 0, &sc->sc_loc_key[0], &flags,
+           &sc->sc_id_loc_key[0])) {
                if (flags & HIO_VARIABLE) {
                        DPRINTFN(1, "Ignoring keyboard event control\n");
                } else {
-                       sc->sc_flags |= UKBD_FLAG_EVENTS;
+                       sc->sc_loc_key_valid[0] |= 1;
                        DPRINTFN(1, "Found keyboard event array\n");
                }
        }
 
+       /* figure out the keys */
+       for (key = 1; key != UKBD_NKEYCODE; key++) {
+               if (hid_locate(ptr, len,
+                   HID_USAGE2(HUP_KEYBOARD, key),
+                   hid_input, 0, &sc->sc_loc_key[key], &flags,
+                   &sc->sc_id_loc_key[key])) {
+                       if (flags & HIO_VARIABLE) {
+                               sc->sc_loc_key_valid[key / 64] |=
+                                   1ULL << (key % 64);
+                               DPRINTFN(1, "Found key 0x%02x\n", key);
+                       }
+               }
+       }
+
        /* figure out leds on keyboard */
        sc->sc_led_size = hid_report_size(ptr, len,
            hid_output, NULL);
@@ -1301,7 +1141,7 @@ ukbd_attach(device_t dev)
 
        /* check if we should use the boot protocol */
        if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) ||
-           (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) {
+           (err != 0) || ukbd_any_key_valid(sc) == false) {
 
                DPRINTF("Forcing boot protocol\n");
 
@@ -1660,11 +1500,11 @@ ukbd_read(keyboard_t *kbd, int wait)
        ++(kbd->kb_count);
 
 #ifdef UKBD_EMULATE_ATSCANCODE
-       keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.modifiers);
+       keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.bitmap);
        if (keycode == NN) {
                return -1;
        }
-       return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers,
+       return (ukbd_key2scan(sc, keycode, sc->sc_ndata.bitmap,
            (usbcode & KEY_RELEASE)));
 #else                                  /* !UKBD_EMULATE_ATSCANCODE */
        return (usbcode);
@@ -1731,13 +1571,13 @@ next_code:
 
 #ifdef UKBD_EMULATE_ATSCANCODE
        /* USB key index -> key code -> AT scan code */
-       keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.modifiers);
+       keycode = ukbd_atkeycode(usbcode, sc->sc_ndata.bitmap);
        if (keycode == NN) {
                return (NOKEY);
        }
        /* return an AT scan code for the K_RAW mode */
        if (sc->sc_mode == K_RAW) {
-               return (ukbd_key2scan(sc, keycode, sc->sc_ndata.modifiers,
+               return (ukbd_key2scan(sc, keycode, sc->sc_ndata.bitmap,
                    (usbcode & KEY_RELEASE)));
        }
 #else                                  /* !UKBD_EMULATE_ATSCANCODE */
@@ -2061,8 +1901,8 @@ ukbd_clear_state(keyboard_t *kbd)
 #endif
        memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
        memset(&sc->sc_odata, 0, sizeof(sc->sc_odata));
-       memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime));
-       memset(&sc->sc_otime, 0, sizeof(sc->sc_otime));
+       sc->sc_repeat_time = 0;
+       sc->sc_repeat_key = 0;
 }
 
 /* save the internal state, not used */
@@ -2149,11 +1989,12 @@ ukbd_set_typematic(keyboard_t *kbd, int code)
 
 #ifdef UKBD_EMULATE_ATSCANCODE
 static uint32_t
-ukbd_atkeycode(int usbcode, int shift)
+ukbd_atkeycode(int usbcode, const uint64_t *bitmap)
 {
        uint32_t keycode;
 
        keycode = ukbd_trtab[KEY_INDEX(usbcode)];
+
        /*
         * Translate Alt-PrintScreen to SysRq.
         *
@@ -2168,13 +2009,14 @@ ukbd_atkeycode(int usbcode, int shift)
         * is routine.
         */
        if ((keycode == 0x5c || keycode == 0x7e) &&
-           shift & (MOD_ALT_L | MOD_ALT_R))
+           (UKBD_KEY_PRESSED(bitmap, 0xe2 /* ALT-L */) ||
+            UKBD_KEY_PRESSED(bitmap, 0xe6 /* ALT-R */)))
                return (0x54);
        return (keycode);
 }
 
 static int
-ukbd_key2scan(struct ukbd_softc *sc, int code, int shift, int up)
+ukbd_key2scan(struct ukbd_softc *sc, int code, const uint64_t *bitmap, int up)
 {
        static const int scan[] = {
                /* 89 */
@@ -2234,12 +2076,17 @@ ukbd_key2scan(struct ukbd_softc *sc, int code, int shi
                code = scan[code - 89];
        }
        /* PrintScreen */
-       if (code == 0x137 && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R |
-           MOD_SHIFT_L | MOD_SHIFT_R)))) {
+       if (code == 0x137 && (!(
+           UKBD_KEY_PRESSED(bitmap, 0xe0 /* CTRL-L */) ||
+           UKBD_KEY_PRESSED(bitmap, 0xe4 /* CTRL-R */) ||
+           UKBD_KEY_PRESSED(bitmap, 0xe1 /* SHIFT-L */) ||
+           UKBD_KEY_PRESSED(bitmap, 0xe5 /* SHIFT-R */)))) {
                code |= SCAN_PREFIX_SHIFT;
        }
        /* Pause/Break */
-       if ((code == 0x146) && (!(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))) {
+       if ((code == 0x146) && (!(
+           UKBD_KEY_PRESSED(bitmap, 0xe0 /* CTRL-L */) ||
+           UKBD_KEY_PRESSED(bitmap, 0xe4 /* CTRL-R */)))) {
                code = (0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL);
        }
        code |= (up ? SCAN_RELEASE : SCAN_PRESS);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to