summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/interface/pcbios/bios_console.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/interface/pcbios/bios_console.c')
-rw-r--r--src/arch/x86/interface/pcbios/bios_console.c71
1 files changed, 52 insertions, 19 deletions
diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c
index 80ebf330e..0220c8564 100644
--- a/src/arch/x86/interface/pcbios/bios_console.c
+++ b/src/arch/x86/interface/pcbios/bios_console.c
@@ -60,6 +60,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ATTR_DEFAULT ATTR_FCOL_WHITE
+/** Maximum keycode subject to remapping
+ *
+ * This allows us to avoid remapping the numeric keypad, which is
+ * necessary for keyboard layouts such as "fr" that swap the shifted
+ * and unshifted digit keys.
+ */
+#define SCANCODE_RSHIFT 0x36
+
+/** Scancode for the "non-US \ and |" key
+ *
+ * This is the key that appears between Left Shift and Z on non-US
+ * keyboards.
+ */
+#define SCANCODE_NON_US 0x56
+
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
#undef CONSOLE_PCBIOS
@@ -340,28 +355,15 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
}
/**
- * Map a key
- *
- * @v character Character read from console
- * @ret character Mapped character
- */
-static int bios_keymap ( unsigned int character ) {
- struct key_mapping *mapping;
-
- for_each_table_entry ( mapping, KEYMAP ) {
- if ( mapping->from == character )
- return mapping->to;
- }
- return character;
-}
-
-/**
* Get character from BIOS console
*
* @ret character Character read from console
*/
static int bios_getchar ( void ) {
uint16_t keypress;
+ uint8_t kb0;
+ uint8_t kb2;
+ unsigned int scancode;
unsigned int character;
const char *ansi_seq;
@@ -383,11 +385,42 @@ static int bios_getchar ( void ) {
: "=a" ( keypress )
: "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
bios_inject_lock--;
+ scancode = ( keypress >> 8 );
character = ( keypress & 0xff );
+ get_real ( kb0, BDA_SEG, BDA_KB0 );
+ get_real ( kb2, BDA_SEG, BDA_KB2 );
+
+ /* If it's a normal character, map (if applicable) and return it */
+ if ( character && ( character < 0x80 ) ) {
+
+ /* Handle special scancodes */
+ if ( scancode == SCANCODE_NON_US ) {
+ /* Treat as "\|" with high bit set */
+ character |= KEYMAP_PSEUDO;
+ } else if ( scancode >= SCANCODE_RSHIFT ) {
+ /* Non-remappable scancode (e.g. numeric keypad) */
+ return character;
+ }
+
+ /* Apply modifiers */
+ if ( kb0 & BDA_KB0_CTRL )
+ character |= KEYMAP_CTRL;
+ if ( kb0 & BDA_KB0_CAPSLOCK )
+ character |= KEYMAP_CAPSLOCK_REDO;
+ if ( kb2 & BDA_KB2_RALT )
+ character |= KEYMAP_ALTGR;
+
+ /* Treat LShift+RShift as AltGr since many BIOSes will
+ * not return ASCII characters when AltGr is pressed.
+ */
+ if ( ( kb0 & ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) ==
+ ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) {
+ character |= KEYMAP_ALTGR;
+ }
- /* If it's a normal character, just map and return it */
- if ( character && ( character < 0x80 ) )
- return bios_keymap ( character );
+ /* Map and return */
+ return key_remap ( character );
+ }
/* Otherwise, check for a special key that we know about */
if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {