[kbd] [PATCH] setleds: add option to reset state to the BIOS default
Petr Tesarik
ptesarik at suse.cz
Thu Jul 26 23:49:05 MSK 2012
Hello Alexey and everybody,
please consider the following patch for kbd.
As you probably know, the Linux kernel resets the LED states to all off on
boot. However, many users would like to keep the BIOS NumLock setting, and
others get confused after they press one of the lock keys in the boot loader
and it gets reset again when Linux initializes the terminal.
Because of that, many distros have used various ways to "improve" user
experience: setting NumLock on by default, making OS-specific configuration
options, or reading the BIOS area. The last option seems best to me, because
it usually also preserves whatever you did in the boot loader. Unfortunately,
there's no simple utility to read the state, so distros sometimes do insane
things to get it (e.g. run hwinfo and grep only for the LED states and then
run setleds with the appropriate arguments). Obviously, this approach isn't
exactly fast...
Since setleds must be always used in the end, the most efficient solution is
to add an option that resets the LED states to what they were before the Linux
kernel booted.
Signed-off-by: Petr Tesarik <ptesarik at suse.cz>
---
src/setleds.c | 64
+++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 3 deletions(-)
diff --git a/src/setleds.c b/src/setleds.c
index 3577aee..00e3151 100644
--- a/src/setleds.c
+++ b/src/setleds.c
@@ -11,18 +11,29 @@
#include <fcntl.h>
#include <linux/kd.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include "nls.h"
#include "version.h"
+#if defined(__i386__) || defined(__x86_64__)
+# define HAVE_BIOS 1
+# define BIOS_KBD_ADDR 0x497
+# define BIOS_LED_SCR 0x01
+# define BIOS_LED_NUM 0x02
+# define BIOS_LED_CAP 0x04
+#endif
+
static void attr_noreturn
usage(void)
{
fprintf(stderr, _(
"Usage:\n"
-" setleds [-v] [-L] [-D] [-F] [[+|-][ num | caps | scroll %s]]\n"
+" setleds [-v] [-L] [-D] [-F] [[+|-][ num | caps | scroll %s]%s]\n"
"Thus,\n"
" setleds +caps -num\n"
"will set CapsLock, clear NumLock and leave ScrollLock unchanged.\n"
+"%s"
"The settings before and after the change (if any) are reported\n"
"when the -v option is given or when no change is requested.\n"
"Normally, setleds influences the vt flag settings\n"
@@ -32,9 +43,15 @@ usage(void)
"that a subsequent reset will not change the flags.\n"
),
#ifdef __sparc__
- "| compose "
+ "| compose ",
+#else
+ "",
+#endif
+#ifdef HAVE_BIOS
+ " | bios ",
+"You can also specify \"bios\" to reset state to the BIOS default.\n"
#else
- ""
+ "", ""
#endif
);
exit(1);
@@ -152,6 +169,40 @@ sunsetleds(arg_state char *cur_leds) {
#endif
}
+#ifdef HAVE_BIOS
+static void
+biosgetleds(char *cur_leds) {
+ int memfd;
+ long pagesz, mapoff;
+ char *map, bios_state;
+
+ memfd = open("/dev/mem", O_RDONLY);
+ if (memfd < 0) {
+ perror("/dev/mem");
+ fprintf(stderr, _("Error opening /dev/mem.\n"));
+ exit(1);
+ }
+ pagesz = sysconf(_SC_PAGESIZE);
+ mapoff = BIOS_KBD_ADDR & ~(pagesz-1);
+ map = mmap(NULL, pagesz, PROT_READ, MAP_SHARED, memfd, mapoff);
+ if (map == MAP_FAILED) {
+ perror("/dev/mem");
+ fprintf(stderr, _("Error mapping /dev/mem.\n"));
+ exit(1);
+ }
+ bios_state = map[BIOS_KBD_ADDR - mapoff];
+ *cur_leds = 0;
+ if (bios_state & BIOS_LED_SCR)
+ *cur_leds |= LED_SCR;
+ if (bios_state & BIOS_LED_NUM)
+ *cur_leds |= LED_NUM;
+ if (bios_state & BIOS_LED_CAP)
+ *cur_leds |= LED_CAP;
+ munmap(map, pagesz);
+ close(memfd);
+}
+#endif /* HAVE_BIOS */
+
int
main(int argc, char **argv) {
int optL = 0, optD = 0, optF = 0, verbose = 0;
@@ -241,6 +292,13 @@ main(int argc, char **argv) {
while(--argc) {
ap = *++argv;
+#ifdef HAVE_BIOS
+ if (!strcmp(ap, "bios")) {
+ biosgetleds(&nval);
+ ndef = LED_NUM | LED_CAP | LED_SCR;
+ goto nxtarg;
+ }
+#endif
sign = 1; /* by default: set */
if(*ap == '+')
ap++;
More information about the kbd
mailing list