[kbd] [PATCH v2] setleds: add option to reset state to the BIOS default
Alexey Gladkov
gladkov.alexey at gmail.com
Fri Aug 3 00:36:31 MSK 2012
On 27.07.2012 11:09, Petr Tesarik wrote:
> Hello folks,
>
> 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>
It looks like what you propose has already been discussed several years ago:
http://article.gmane.org/gmane.linux.kernel/493362
I also found that some code is already in the kernel:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=b2d0b7a061bfddd27155c7dcd53f365d9dc0c7c3
As far as I could learn, it is possible to query the LEDs on the USB keyboard,
but for PS/2 this is not possible.
> ---
> src/setleds.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 files changed, 58 insertions(+), 3 deletions(-)
>
> diff --git a/src/setleds.c b/src/setleds.c
> index 3577aee..3defdea 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 ",
> +"Specify \"bios\" to reset state to the BIOS default.\n"
> #else
> - ""
> + "", ""
> #endif
> );
> exit(1);
> @@ -152,6 +169,37 @@ 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 =
> + (bios_state & BIOS_LED_SCR ? LED_SCR : 0) |
> + (bios_state & BIOS_LED_NUM ? LED_NUM : 0) |
> + (bios_state & BIOS_LED_CAP ? LED_CAP : 0);
> + 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 +289,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++;
>
--
Rgrds, legion
More information about the kbd
mailing list