[PATCH] Use BIOS Keyboard variable to set Numlock

From: Bodo Eggert
Date: Wed Jul 11 2007 - 18:13:47 EST


As discussed in the thread "Linus' laptop and Num lock status", the
numlock setting may cause some laptop keyboards to turn on the numeric key
part, so cannot be safely enabled on those systems. Unfortunately we can't
tell if the current system is one of these laptops nor can we read the
numlock status from the keyboard, so we can't enable Numlock based on one of
these facts and therefore it was disabled by default on most architectures.

This is very unfortunate, since the MF-II keyboards feature a way better
set of cursor keys, freeing the numeric keypad for numeric input. Having
to enable this each time you boot is a nuisance, especially if the
keyboard does not feature LED to remind you.

This patch uses the IBM-PC (1981) BIOS data area to determine the initial
state of theNumlock key. This data area holds a bitmap for the current
keyboard status, including the numlock bit. All PC-compatible systems that
can operate DOS or i386 expansion cards need to support this. This data
area is not destroyed by booting linux from lilo.

Instead of the byte at 0x497 as suggested in that thread, I'm using the
byte at 0x417, which reflects the intended LED state. In order to change
the keyboard LED, DOS programs would change this byte and call INT 5
(which is the keyboard software interrupt).

It is yet unknown if booting from non-classic BIOS will provide this data
area, therefore I've set it to depend on EXPERIMENTAL. The worst thing
that should happen is a wrongly set keyboard LED.

This patch adds 48 bytes of init-text on x86_32.


Signed-Off-By: Bodo Eggert <7eggert@xxxxxx>


diff -X dontdiff -pruN linux-2.6.22/drivers/char/keyboard.c linux-2.6.22.changed/drivers/char/keyboard.c
--- linux-2.6.22/drivers/char/keyboard.c 2007-07-11 23:26:01.000000000 +0200
+++ linux-2.6.22.changed/drivers/char/keyboard.c 2007-07-11 23:27:39.000000000 +0200
@@ -24,6 +24,7 @@
* 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/

+#include <asm/io.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -56,7 +57,10 @@ extern void ctrl_alt_del(void);
* to be used for numbers.
*/

-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#ifdef CONFIG_KBD_DEFLEDS_PCBIOS
+/* KBD_DEFLEDS is a variable */
+#undef KBD_DEFLEDS
+#elif defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
#define KBD_DEFLEDS (1 << VC_NUMLOCK)
#else
#define KBD_DEFLEDS 0
@@ -1352,8 +1356,17 @@ int __init kbd_init(void)
{
int i;
int error;
+#ifdef CONFIG_KBD_DEFLEDS_PCBIOS
+ int KBD_DEFLEDS = 0;
+ /* address 0x40:0x17 */
+ char * bios_kbd_status=xlate_dev_mem_ptr(0x417);
+
+ /* Numlock status bit set? */
+ if (*bios_kbd_status & 0x20)
+ KBD_DEFLEDS = 1 << VC_NUMLOCK;
+#endif

- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS;
kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
kbd_table[i].ledmode = LED_SHOW_FLAGS;
diff -X dontdiff -pruN linux-2.6.22/drivers/input/keyboard/Kconfig linux-2.6.22.changed/drivers/input/keyboard/Kconfig
--- linux-2.6.22/drivers/input/keyboard/Kconfig 2007-07-11 23:26:01.000000000 +0200
+++ linux-2.6.22.changed/drivers/input/keyboard/Kconfig 2007-07-11 23:27:39.000000000 +0200
@@ -12,6 +12,17 @@ menuconfig INPUT_KEYBOARD

if INPUT_KEYBOARD

+config KBD_DEFLEDS_PCBIOS
+ bool "Enable Num-Lock based on BIOS settings"
+ depends on X86_PC && EXPERIMENTAL
+ help
+ Turns on Numlock depending on the BIOS settings.
+ This works by reading the BIOS data area as defined for IBM PCs (1981).
+
+ If you have an alternative firmware like OpenFirmware or LinuxBIOS,
+ this flag might not be set correctly, which results in a random state
+ of the Numlock key.
+
config KEYBOARD_ATKBD
tristate "AT keyboard" if EMBEDDED || !X86_PC
default ydiff -X dontdiff -pruN linux-2.6.22/drivers/char/keyboard.c linux-2.6.22.changed/drivers/char/keyboard.c
--- linux-2.6.22/drivers/char/keyboard.c 2007-07-11 23:26:01.000000000 +0200
+++ linux-2.6.22.changed/drivers/char/keyboard.c 2007-07-11 23:27:39.000000000 +0200
@@ -24,6 +24,7 @@
* 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/

+#include <asm/io.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -56,7 +57,10 @@ extern void ctrl_alt_del(void);
* to be used for numbers.
*/

-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#ifdef CONFIG_KBD_DEFLEDS_PCBIOS
+/* KBD_DEFLEDS is a variable */
+#undef KBD_DEFLEDS
+#elif defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
#define KBD_DEFLEDS (1 << VC_NUMLOCK)
#else
#define KBD_DEFLEDS 0
@@ -1352,8 +1356,17 @@ int __init kbd_init(void)
{
int i;
int error;
+#ifdef CONFIG_KBD_DEFLEDS_PCBIOS
+ int KBD_DEFLEDS = 0;
+ /* address 0x40:0x17 */
+ char * bios_kbd_status=xlate_dev_mem_ptr(0x417);
+
+ /* Numlock status bit set? */
+ if (*bios_kbd_status & 0x20)
+ KBD_DEFLEDS = 1 << VC_NUMLOCK;
+#endif

- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS;
kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
kbd_table[i].ledmode = LED_SHOW_FLAGS;
diff -X dontdiff -pruN linux-2.6.22/drivers/input/keyboard/Kconfig linux-2.6.22.changed/drivers/input/keyboard/Kconfig
--- linux-2.6.22/drivers/input/keyboard/Kconfig 2007-07-11 23:26:01.000000000 +0200
+++ linux-2.6.22.changed/drivers/input/keyboard/Kconfig 2007-07-11 23:27:39.000000000 +0200
@@ -12,6 +12,17 @@ menuconfig INPUT_KEYBOARD

if INPUT_KEYBOARD

+config KBD_DEFLEDS_PCBIOS
+ bool "Enable Num-Lock based on BIOS settings"
+ depends on X86_PC && EXPERIMENTAL
+ help
+ Turns on Numlock depending on the BIOS settings.
+ This works by reading the BIOS data area as defined for IBM PCs (1981).
+
+ If you have an alternative firmware like OpenFirmware or LinuxBios,
+ this flag might not be set correctly, which results in a random state
+ of the Numlock key.
+
config KEYBOARD_ATKBD
tristate "AT keyboard" if EMBEDDED || !X86_PC
default y