OpenSolaris

Printable Version Enter a New Search
Bug ID 6317107
Synopsis # key cannot be used in polled mode with a german layout ps/2 keyboard
State 10-Fix Delivered (Fix available in build)
Category:Subcategory kernel:virtualkm
Keywords opensolaris | oss-request | oss-sponsor
Sponsor Riny Qian
Submitter jk
Responsible Engineer Riny Qian
Reported Against
Duplicate Of
Introduced In
Commit to Fix snv_30
Fixed In snv_30
Release Fixed solaris_nevada(snv_30) , solaris_10u4(s10u4_09) (Bug ID:2141302)
Related Bugs
Submit Date 29-August-2005
Last Update Date 6-November-2008
Description
Category
   kernel
Sub-Category
   virtualkm
Description
   As soon as the "kbtrans" kernel module is loaded and the german keyboard
layout is installed, the "#" / "'" / "`" (backtick, AltGr-#) key does not
work any more inside kmdb.
Without the '#' key, it's not possible to set delayed breakpoints
(::bp module_name`function_name) because there's no way to type the "`"
character (AltGr-#) in kmdb.
Outside of kmdb (on the text console), the "#" / "'" / "`" key works as
expected.
The interrupt driven code path in kbtrans already contains a workaround for
this problem [*], so that the problem does not occur outside of kmdb.  The
same workaround is needed for the polled code path (see the suggested fix).
------------------------------------------------------------------------
What happens inside the Solaris kernel when the '#' key is pressed on a
german layout PS/2 keyboard?
When '#' is typed, the kb8042 module reads scancode 0x2b
usr/src/uts/common/io/kb8042/at_keyprocess.c translates the 0x2b scancode to 
a keycode 29 in function KeyboardConvertScan() using the keytab_base[] array.
Because the kb8042 is used in "simulated_kbd_type == USB" mode, the keycode 29
is translated to an USB keycode of 49 using the keytab_pc2usb[] array in
usr/src/uts/common/io/kb8042/kb8042.c
Now the kbtrans module translates the usb keycode 49 in function
kbtrans_translate() which calls kbtrans_find_entry().  kbtrans_find_entry()
uses the kbtrans`keytab_usb_lc array and finds an entry 0x302 (HOLE)
==> the '#' key is ignored.
Note that the contents of the keytab_usb_lc[] array is changed from the
version compiled into the kbtrans module.  The compiled version contains
the entry '\\' at element 49.  During boot a german layout version is
installed using the function kbtrans`kbtrans_skey() and this changes the
keytab_usb_lc[49] entry to HOLE.  The process that triggers this is
"/usr/bin/loadkeys", started from /lib/svc/method/keymap.
/usr/share/lib/keytables/type_6/layout_09:
key  50  base # shift '\'' caps # ctrl # altg '`'
key  49  all hole
According to the USB "HID Usage Tables (Version 1.11)" specification (Section 
10, Keyboard/Keypad Page (0x07), on page 54), there is:
Usage ID 49: Keyboard \ and |
Usage ID 50: Keyboard Non-US # and ~
A german layout *USB* keyboard does in fact send the keycode 50 when the "#"
key is pressed.
When using a PS/2 keyboard and kmdb is not active, something inside the Solaris
kernel translates 49 -> 50 [*]; when kbtrans debug messages are enabled, the
following is listed:
kbtrans: kbtrans_processkey: newstate=0 key=49
kbtrans: kbtrans_queuepress: key=49
kbtrans: kbtrans_processkey: newstate=0 key=50
... and kbtrans_findentry is called with keycode 50.  Note how a firmevent
with key=49 is queued, but the next call to kbtrans_processkey translates
key=50
Root cause: a german layout USB keyboard has no key 49 but a key 50.
A US layout USB keyboard appears to use key 49.
When kb8042 emulates a USB keyboard, it generates USB key 49.
For a german layout USB keyboard emulation this appears incorrect, it should
generate key 50.
------------------------------------------------------------------------
Probably the same problem exists for all keyboard layouts that have
key 49 defined as "hole" in the usb keyboard layout tables:
% grep 'key *49.*hole' /usr/share/lib/keytables/type_6/*
/usr/share/lib/keytables/type_6/denmark:key  49  all hole
/usr/share/lib/keytables/type_6/finnish:key  49  all hole
/usr/share/lib/keytables/type_6/france:key  49  all hole
/usr/share/lib/keytables/type_6/germany:key  49  all hole
/usr/share/lib/keytables/type_6/italy:key  49  all hole
/usr/share/lib/keytables/type_6/japan:key  49  all hole
/usr/share/lib/keytables/type_6/layout_06:key  49  all hole
/usr/share/lib/keytables/type_6/layout_07:key  49  all hole
/usr/share/lib/keytables/type_6/layout_08:key  49  all hole
/usr/share/lib/keytables/type_6/layout_09:key  49  all hole
/usr/share/lib/keytables/type_6/layout_0e:key  49  all hole
/usr/share/lib/keytables/type_6/layout_0f:key  49  all hole
/usr/share/lib/keytables/type_6/layout_12:key  49  all hole
/usr/share/lib/keytables/type_6/layout_13:key  49  all hole
/usr/share/lib/keytables/type_6/layout_16:key  49  all hole
/usr/share/lib/keytables/type_6/layout_19:key  49  all hole
/usr/share/lib/keytables/type_6/layout_1a:key  49  all hole
/usr/share/lib/keytables/type_6/layout_1b:key  49  all hole
/usr/share/lib/keytables/type_6/layout_1c:key  49  all hole
/usr/share/lib/keytables/type_6/layout_20:key  49  all hole
/usr/share/lib/keytables/type_6/netherlands:key  49  all hole
/usr/share/lib/keytables/type_6/norway:key  49  all hole
/usr/share/lib/keytables/type_6/portugal:key  49  all hole
/usr/share/lib/keytables/type_6/spain:key  49  all hole
/usr/share/lib/keytables/type_6/sweden:key  49  all hole
/usr/share/lib/keytables/type_6/swiss_french:key  49  all hole
/usr/share/lib/keytables/type_6/swiss_german:key  49  all hole
/usr/share/lib/keytables/type_6/uk:key  49  all hole
---
[*] YES: usr/src/uts/common/io/conskbd.c, conskbdlrput():
  1054          case M_DATA:
  1055                  if (conskbd.conskbd_bypassed == B_FALSE) {
  1056
  1057                          fe = (Firm_event *)mp->b_rptr;
  1058
  1059                          /*
  1060                           * This is a workaround.
  1061                           *
  1062                           * According to HID specification, there are the
  1063                           * following keycode mapping between PS2 and USB,
  1064                           *
  1065                           *      PS2 AT-101 keycode(29)  --->    USB(49)
  1066                           *      PS2 AT-102 keycode(42)  --->    USB(50)
  1067                           *
  1068                           * However, the two keys, AT-101(29) and AT-102(42),
  1069                           * have the same scancode,0x2B, in PS2 scancode SET1
  1070                           * which we are using. The Kb8042 driver always
  1071                           * recognizes the two keys as PS2(29) so that we could
  1072                           * not know which is being pressed or released when we
  1073                           * receive scancode 0x2B. Fortunately, the two keys can
  1074                           * not co-exist in a specific layout. In other words,
  1075                           * in the table of keycode-to-symbol mapping, either
  1076                           * entry 49 or 50 is a hole. So, if we're processing a
  1077                           * keycode 49, we look at the entry for 49.  If it's
  1078                           * HOLE, remap the key to 50; If we're processing a 50,
  1079                           * look at the entry for 50.  If it's HOLE, we remap
  1080                           * the key to 49.
  1081                           */
  1082                          if (fe->id == 49 || fe->id == 50) {
  1083                                  if (conskbd_keyindex->k_normal[50] == HOLE)
  1084                                          fe->id = 49;
  1085                                  else
  1086                                          fe->id = 50;
  1087                          }
  1088
Frequency
   Always
Regression
   Solaris 10
Steps to Reproduce
   On an x86 system with a german layout ps/2 keyboard and "eeprom kbd-type=German"
boot into single user mode and enter kmdb using "F1-A" or "mdb -K".
Try to set a delayed breakpoint
::bp module`function
Try to get any keyboard input from the # key
Expected Result
   The user can type the ` character using the sequence AltGr-#
Actual Result
   The # key is completely ignored inside kmdb.
You cannot type # or "AltGr-#" (for the ` character).
Error Message(s)
   
Test Case
   
Workaround
   Workaround #1:
==============
Use a USB keyboard.  With a german layout USB keyboard the
"#" key works both inside kmdb and on the text console.
Workaround #2:
==============
Change keytab_pc2usb[29] from 49 to 50:
echo 'keytab_pc2usb+4*0t29?W 0t50' | adb -wk
Workaround #3:
==============
Changing /usr/share/lib/keytables/type_6/layout_09 like this fixes the kmdb
problem:
key  49  base # shift '\'' caps # ctrl # altg '`'
key  50  all hole
Suggested fix:
==============
The conskbd module already contains a workaround for this problem for
interrupt driven code.
The polled mode codepath needs the same fix:
*** usr/src/uts/common/io/conskbd.c~    Thu Aug 18 18:51:54 2005
--- usr/src/uts/common/io/conskbd.c     Sun Aug 28 11:19:52 2005
***************
*** 550,556 ****
        conskbd_consqueue = q;
        /*
!        * initialzie kbtrans module for conskbd
         */
        err = kbtrans_streams_init(q, sflag, crp, (struct kbtrans_hardware *)
            &conskbd, &conskbd_callbacks, &conskbd.conskbd_kbtrans, 0, 0);
--- 550,556 ----
        conskbd_consqueue = q;
        /*
!        * initialize kbtrans module for conskbd
         */
        err = kbtrans_streams_init(q, sflag, crp, (struct kbtrans_hardware *)
            &conskbd, &conskbd_callbacks, &conskbd.conskbd_kbtrans, 0, 0);
***************
*** 2003,2013 ****
                    (cb->cons_polledio_keycheck != NULL)) {
                        ret = cb->cons_polledio_keycheck(
                            cb->cons_polledio_argument, keycode, state);
-               }
!               /* Get a char from lower queue(hardware) ? */
!               if (ret == B_TRUE) {
!                       break;
                }
        }
--- 2003,2037 ----
                    (cb->cons_polledio_keycheck != NULL)) {
                        ret = cb->cons_polledio_keycheck(
                            cb->cons_polledio_argument, keycode, state);
!                       /* Get a char from lower queue(hardware) ? */
!                       if (ret == B_TRUE) {
!
!                               /*
!                                * This is the PS2 scancode 0x2B -> USB(49) /
!                                * USB(50) keycode mapping workaround, for
!                                * polled mode.
!                                *
!                                * There are two possible USB keycode mappings
!                                * for PS2 scancode 0x2B and this workaround
!                                * makes sure that we use the USB keycode that
!                                * does not end up being mapped to a HOLE key
!                                * using the current keyboard translation
!                                * tables.
!                                *
!                                * See conskbdlrput() for a detailed
!                                * explanation of the problem.
!                                */
!                               if (*keycode == 49 || *keycode == 50) {
!                                       if (conskbd_keyindex->k_normal[50] ==
!                                           HOLE)
!                                               *keycode = 49;
!                                       else
!                                               *keycode = 50;
!                               }
!
!                               break;
!                       }
                }
        }
Submitter wants to work on bug
   Yes
Additional configuration information
   PS/2 keyboard, german keyboard layout
The same problem can also be reproduced on S10-GA with patch 118860-01 installed.
Work Around
Workaround #1:
==============
Use a USB keyboard.  With a german layout USB keyboard the
"#" key works both inside kmdb and on the text console.
Workaround #2:
==============
Change keytab_pc2usb[29] from 49 to 50:
echo 'keytab_pc2usb+4*0t29?W 0t50' | adb -wk
Workaround #3:
==============
Changing /usr/share/lib/keytables/type_6/layout_09 like this fixes the kmdb
problem:
key  49  base # shift '\'' caps # ctrl # altg '`'
key  50  all hole
Suggested fix:
==============
The conskbd module already contains a workaround for this problem for
interrupt driven code.
The polled mode codepath needs the same fix:
*** usr/src/uts/common/io/conskbd.c~    Thu Aug 18 18:51:54 2005
--- usr/src/uts/common/io/conskbd.c     Sun Aug 28 11:19:52 2005
***************
*** 550,556 ****
        conskbd_consqueue = q;
        /*
!        * initialzie kbtrans module for conskbd
         */
        err = kbtrans_streams_init(q, sflag, crp, (struct kbtrans_hardware *)
            &conskbd, &conskbd_callbacks, &conskbd.conskbd_kbtrans, 0, 0);
--- 550,556 ----
        conskbd_consqueue = q;
        /*
!        * initialize kbtrans module for conskbd
         */
        err = kbtrans_streams_init(q, sflag, crp, (struct kbtrans_hardware *)
            &conskbd, &conskbd_callbacks, &conskbd.conskbd_kbtrans, 0, 0);
***************
*** 2003,2013 ****
                    (cb->cons_polledio_keycheck != NULL)) {
                        ret = cb->cons_polledio_keycheck(
                            cb->cons_polledio_argument, keycode, state);
-               }
!               /* Get a char from lower queue(hardware) ? */
!               if (ret == B_TRUE) {
!                       break;
                }
        }
--- 2003,2037 ----
                    (cb->cons_polledio_keycheck != NULL)) {
                        ret = cb->cons_polledio_keycheck(
                            cb->cons_polledio_argument, keycode, state);
!                       /* Get a char from lower queue(hardware) ? */
!                       if (ret == B_TRUE) {
!
!                               /*
!                                * This is the PS2 scancode 0x2B -> USB(49) /
!                                * USB(50) keycode mapping workaround, for
!                                * polled mode.
!                                *
!                                * There are two possible USB keycode mappings
!                                * for PS2 scancode 0x2B and this workaround
!                                * makes sure that we use the USB keycode that
!                                * does not end up being mapped to a HOLE key
!                                * using the current keyboard translation
!                                * tables.
!                                *
!                                * See conskbdlrput() for a detailed
!                                * explanation of the problem.
!                                */
!                               if (*keycode == 49 || *keycode == 50) {
!                                       if (conskbd_keyindex->k_normal[50] ==
!                                           HOLE)
!                                               *keycode = 49;
!                                       else
!                                               *keycode = 50;
!                               }
!
!                               break;
!                       }
                }
        }
Comments
N/A