Index: conf/i386-pc.rmk =================================================================== --- conf/i386-pc.rmk (revision 1845) +++ conf/i386-pc.rmk (working copy) @@ -117,7 +117,7 @@ commands/configfile.c commands/echo.c commands/help.c \ commands/terminal.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ - lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ + lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ commands/i386/cpuid.c \ disk/host.c disk/loopback.c \ fs/fshelp.c \ @@ -161,7 +161,7 @@ # Modules. pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ - _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ + _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod sendkey.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \ @@ -214,6 +214,11 @@ halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For sendkey.mod. +sendkey_mod_SOURCES = commands/i386/pc/sendkey.c +sendkey_mod_CFLAGS = $(COMMON_CFLAGS) +sendkey_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For serial.mod. serial_mod_SOURCES = term/i386/pc/serial.c serial_mod_CFLAGS = $(COMMON_CFLAGS) Index: conf/i386-pc.mk =================================================================== --- conf/i386-pc.mk (revision 1845) +++ conf/i386-pc.mk (working copy) @@ -520,7 +520,7 @@ commands/configfile.c commands/echo.c commands/help.c \ commands/terminal.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ - lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ + lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ commands/i386/cpuid.c \ disk/host.c disk/loopback.c \ fs/fshelp.c \ @@ -926,7 +926,7 @@ # Modules. pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ - _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ + _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod sendkey.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \ @@ -1661,6 +1661,63 @@ halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For sendkey.mod. +sendkey_mod_SOURCES = commands/i386/pc/sendkey.c +CLEANFILES += sendkey.mod mod-sendkey.o mod-sendkey.c pre-sendkey.o sendkey_mod-commands_i386_pc_sendkey.o und-sendkey.lst +ifneq ($(sendkey_mod_EXPORTS),no) +CLEANFILES += def-sendkey.lst +DEFSYMFILES += def-sendkey.lst +endif +MOSTLYCLEANFILES += sendkey_mod-commands_i386_pc_sendkey.d +UNDSYMFILES += und-sendkey.lst + +sendkey.mod: pre-sendkey.o mod-sendkey.o $(TARGET_OBJ2ELF) + -rm -f $@ + $(TARGET_CC) $(sendkey_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-sendkey.o mod-sendkey.o + if test ! -z $(TARGET_OBJ2ELF); then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@ + +pre-sendkey.o: $(sendkey_mod_DEPENDENCIES) sendkey_mod-commands_i386_pc_sendkey.o + -rm -f $@ + $(TARGET_CC) $(sendkey_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ sendkey_mod-commands_i386_pc_sendkey.o + +mod-sendkey.o: mod-sendkey.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(sendkey_mod_CFLAGS) -c -o $@ $< + +mod-sendkey.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'sendkey' $< > $@ || (rm -f $@; exit 1) + +ifneq ($(sendkey_mod_EXPORTS),no) +def-sendkey.lst: pre-sendkey.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 sendkey/' > $@ +endif + +und-sendkey.lst: pre-sendkey.o + echo 'sendkey' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +sendkey_mod-commands_i386_pc_sendkey.o: commands/i386/pc/sendkey.c $(commands/i386/pc/sendkey.c_DEPENDENCIES) + $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(sendkey_mod_CFLAGS) -MD -c -o $@ $< +-include sendkey_mod-commands_i386_pc_sendkey.d + +CLEANFILES += cmd-sendkey_mod-commands_i386_pc_sendkey.lst fs-sendkey_mod-commands_i386_pc_sendkey.lst partmap-sendkey_mod-commands_i386_pc_sendkey.lst +COMMANDFILES += cmd-sendkey_mod-commands_i386_pc_sendkey.lst +FSFILES += fs-sendkey_mod-commands_i386_pc_sendkey.lst +PARTMAPFILES += partmap-sendkey_mod-commands_i386_pc_sendkey.lst + +cmd-sendkey_mod-commands_i386_pc_sendkey.lst: commands/i386/pc/sendkey.c $(commands/i386/pc/sendkey.c_DEPENDENCIES) gencmdlist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(sendkey_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh sendkey > $@ || (rm -f $@; exit 1) + +fs-sendkey_mod-commands_i386_pc_sendkey.lst: commands/i386/pc/sendkey.c $(commands/i386/pc/sendkey.c_DEPENDENCIES) genfslist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(sendkey_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh sendkey > $@ || (rm -f $@; exit 1) + +partmap-sendkey_mod-commands_i386_pc_sendkey.lst: commands/i386/pc/sendkey.c $(commands/i386/pc/sendkey.c_DEPENDENCIES) genpartmaplist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(sendkey_mod_CFLAGS) -E $< | sh $(srcdir)/genpartmaplist.sh sendkey > $@ || (rm -f $@; exit 1) + + +sendkey_mod_CFLAGS = $(COMMON_CFLAGS) +sendkey_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For serial.mod. serial_mod_SOURCES = term/i386/pc/serial.c CLEANFILES += serial.mod mod-serial.o mod-serial.c pre-serial.o serial_mod-term_i386_pc_serial.o und-serial.lst Index: kern/loader.c =================================================================== --- kern/loader.c (revision 1845) +++ kern/loader.c (working copy) @@ -22,12 +22,41 @@ #include #include + static grub_err_t (*grub_loader_boot_func) (void); static grub_err_t (*grub_loader_unload_func) (void); static int grub_loader_noreturn; static int grub_loader_loaded; +static struct grub_preboot_t *grub_loader_preboots=0; + +struct grub_preboot_t * +grub_loader_add_preboot (grub_err_t (*preboot_func) (int)) +{ + struct grub_preboot_t **cur=&grub_loader_preboots; + if (!preboot_func) + return 0; + while (*cur) + cur=&((*cur)->next); + *cur=(struct grub_preboot_t *)grub_malloc (sizeof (struct grub_preboot_t)); + (*cur)->prev_pointer=cur; + (*cur)->next=0; + (*cur)->preboot_func=preboot_func; + return *cur; +} + +void +grub_loader_remove_preboot (struct grub_preboot_t *p) +{ + if (!p) + return; + *(p->prev_pointer)=p->next; + if (p->next) + (p->next)->prev_pointer=p->prev_pointer; + grub_free (p); +} + int grub_loader_is_loaded (void) { @@ -64,11 +93,19 @@ grub_err_t grub_loader_boot (void) { + struct grub_preboot_t *iter=grub_loader_preboots; if (! grub_loader_loaded) return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel"); if (grub_loader_noreturn) grub_machine_fini (); + + while (iter) + { + if (iter->preboot_func) + iter->preboot_func (grub_loader_noreturn); + iter=iter->next; + } return (grub_loader_boot_func) (); } Index: include/grub/loader.h =================================================================== --- include/grub/loader.h (revision 1845) +++ include/grub/loader.h (working copy) @@ -25,6 +25,14 @@ #include #include +struct grub_preboot_t +{ + grub_err_t (*preboot_func) (int); + struct grub_preboot_t *next; + struct grub_preboot_t **prev_pointer; +}; + + /* Check if a loader is loaded. */ int EXPORT_FUNC(grub_loader_is_loaded) (void); @@ -37,6 +45,12 @@ /* Unset current loader, if any. */ void EXPORT_FUNC(grub_loader_unset) (void); +/*Add a preboot function*/ +struct grub_preboot_t *EXPORT_FUNC(grub_loader_add_preboot) (grub_err_t (*preboot_func) (int noreturn)); + +/*Remove given preboot function*/ +void EXPORT_FUNC(grub_loader_remove_preboot) (struct grub_preboot_t *p); + /* Call the boot hook in current loader. This may or may not return, depending on the setting by grub_loader_set. */ grub_err_t EXPORT_FUNC(grub_loader_boot) (void); Index: commands/i386/pc/sendkey.c =================================================================== --- commands/i386/pc/sendkey.c (revision 0) +++ commands/i386/pc/sendkey.c (revision 0) @@ -0,0 +1,392 @@ +/* sendkey.c - test module for dynamic loading */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * Copyright (C) 2005 Vladimir Serbinenko serbinenko.vova@bk.ru + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#define RAW_ADDR(a) ((void *)(a)) + +static struct grub_preboot_t *grub_sendkey_preboot_handle=0; +struct +keysym +{ + char *unshifted_name; /* the name in unshifted state */ + char *shifted_name; /* the name in shifted state */ + unsigned char unshifted_ascii; /* the ascii code in unshifted state */ + unsigned char shifted_ascii; /* the ascii code in shifted state */ + unsigned char keycode; /* keyboard scancode */ +}; + +/* The table for key symbols. If the "shifted" member of an entry is + NULL, the entry does not have shifted state. Copied from GRUB Legacy setkey fuction */ +static struct keysym keysym_table[] = +{ + {"escape", 0, 0x1b, 0, 0x01}, + {"1", "exclam", '1', '!', 0x02}, + {"2", "at", '2', '@', 0x03}, + {"3", "numbersign", '3', '#', 0x04}, + {"4", "dollar", '4', '$', 0x05}, + {"5", "percent", '5', '%', 0x06}, + {"6", "caret", '6', '^', 0x07}, + {"7", "ampersand", '7', '&', 0x08}, + {"8", "asterisk", '8', '*', 0x09}, + {"9", "parenleft", '9', '(', 0x0a}, + {"0", "parenright", '0', ')', 0x0b}, + {"minus", "underscore", '-', '_', 0x0c}, + {"equal", "plus", '=', '+', 0x0d}, + {"backspace", 0, '\b', 0, 0x0e}, + {"tab", 0, '\t', 0, 0x0f}, + {"q", "Q", 'q', 'Q', 0x10}, + {"w", "W", 'w', 'W', 0x11}, + {"e", "E", 'e', 'E', 0x12}, + {"r", "R", 'r', 'R', 0x13}, + {"t", "T", 't', 'T', 0x14}, + {"y", "Y", 'y', 'Y', 0x15}, + {"u", "U", 'u', 'U', 0x16}, + {"i", "I", 'i', 'I', 0x17}, + {"o", "O", 'o', 'O', 0x18}, + {"p", "P", 'p', 'P', 0x19}, + {"bracketleft", "braceleft", '[', '{', 0x1a}, + {"bracketright", "braceright", ']', '}', 0x1b}, + {"enter", 0, '\r', 0, 0x1c}, + {"control", 0, 0, 0, 0x1d}, + {"a", "A", 'a', 'A', 0x1e}, + {"s", "S", 's', 'S', 0x1f}, + {"d", "D", 'd', 'D', 0x20}, + {"f", "F", 'f', 'F', 0x21}, + {"g", "G", 'g', 'G', 0x22}, + {"h", "H", 'h', 'H', 0x23}, + {"j", "J", 'j', 'J', 0x24}, + {"k", "K", 'k', 'K', 0x25}, + {"l", "L", 'l', 'L', 0x26}, + {"semicolon", "colon", ';', ':', 0x27}, + {"quote", "doublequote", '\'', '"', 0x28}, + {"backquote", "tilde", '`', '~', 0x29}, + {"shift", 0, 0, 0, 0x2a}, + {"backslash", "bar", '\\', '|', 0x2b}, + {"z", "Z", 'z', 'Z', 0x2c}, + {"x", "X", 'x', 'X', 0x2d}, + {"c", "C", 'c', 'C', 0x2e}, + {"v", "V", 'v', 'V', 0x2f}, + {"b", "B", 'b', 'B', 0x30}, + {"n", "N", 'n', 'N', 0x31}, + {"m", "M", 'm', 'M', 0x32}, + {"comma", "less", ',', '<', 0x33}, + {"period", "greater", '.', '>', 0x34}, + {"slash", "question", '/', '?', 0x35}, + {"rshift", 0, 0, 0, 0x36}, + {"numasterisk", 0, '*', 0, 0x37}, + {"alt", 0, 0, 0, 0x38}, + {"space", 0, ' ', 0, 0x39}, + {"capslock", 0, 0, 0, 0x3a}, + {"F1", 0, 0, 0, 0x3b}, + {"F2", 0, 0, 0, 0x3c}, + {"F3", 0, 0, 0, 0x3d}, + {"F4", 0, 0, 0, 0x3e}, + {"F5", 0, 0, 0, 0x3f}, + {"F6", 0, 0, 0, 0x40}, + {"F7", 0, 0, 0, 0x41}, + {"F8", 0, 0, 0, 0x42}, + {"F9", 0, 0, 0, 0x43}, + {"F10", 0, 0, 0, 0x44}, + {"num7", "numhome", '7', 0, 0x47}, + {"num8", "numup", '8', 0, 0x48}, + {"num9", "numpgup", '9', 0, 0x49}, + {"numminus", 0, '-', 0, 0x4a}, + {"num4", "numleft", '4', 0, 0x4b}, + {"num5", "num5numlock", '5', 0, 0x4c}, + {"num6", "numright", '6', 0, 0x4d}, + {"numplus", 0, '-', 0, 0x4e}, + {"num1", "numend", '1', 0, 0x4f}, + {"num2", "numdown", '2', 0, 0x50}, + {"num3", "numpgdown", '3', 0, 0x51}, + {"num0", "numinsert", '0', 0, 0x52}, + {"numperiod", "numdelete", 0, 0x7f, 0x53}, + {"F11", 0, 0, 0, 0x57}, + {"F12", 0, 0, 0, 0x58}, + {"numenter", 0, '\r', 0, 0xe0}, + {"numslash", 0, '/', 0, 0xe0}, + {"delete", 0, 0x7f, 0, 0xe0}, + {"insert", 0, 0xe0, 0, 0x52}, + {"home", 0, 0xe0, 0, 0x47}, + {"end", 0, 0xe0, 0, 0x4f}, + {"pgdown", 0, 0xe0, 0, 0x51}, + {"pgup", 0, 0xe0, 0, 0x49}, + {"down", 0, 0xe0, 0, 0x50}, + {"up", 0, 0xe0, 0, 0x48}, + {"left", 0, 0xe0, 0, 0x4b}, + {"right", 0, 0xe0, 0, 0x4d} +}; + +/* Send a character VALUE to port PORT */ +static void +outportb (char value, int port) { + asm volatile ("outb %%al,%%dx": :"a" (value),"d" (port)); + return; +} + +/* Read a byte from port PORT */ +static unsigned char +inb (unsigned int port) +{ + unsigned char ret; + asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port)); + return ret; + +} + +/* Set a simple flag in flags variable + FLAGS - where to set, + OUTOFFSET - offset of flag in FLAGS, + OP - action id +*/ +static void +grub_sendkey_set_simple_flag (unsigned long *flags, int outoffset, int op) +{ + /* previous state of flag */ + int prevstat = (*flags >> outoffset) & 1; + /* new state */ + int newstat = (op == 1) || (op == 2 && prevstat); + /* Set new state */ + *flags = (*flags & (~(1 << outoffset))) | (newstat << outoffset); +} + +/* Set a double flag (ctrl/alt) in flags variable + FLAGS - where to set, + OUTOFFSETR - offset of common flag in FLAGS, + OUTOFFSETL - offset of "left" flag in FLAGS, + OPR - operation for "right" flag, + OPL - operation for "left" flag +*/ +static void +grub_sendkey_set_double_flag (unsigned long *flags, int outoffsetc, int outoffsetl, int opr, int opl) +{ + /* previous state of flag */ + int prevstatc = (*flags >> outoffsetc) & 1; + int prevstatl = (*flags >> outoffsetl) & 1; + int prevstatr = prevstatc && (!prevstatl); + /* new state */ + int newstatl = (opl == 1) || (opl == 2 && prevstatl); + int newstatr = (opr == 1) || (opr == 2 && prevstatr); + int newstatc = newstatr || newstatr; + /* Set new state */ + *flags = (*flags & (~(1 << outoffsetl))) | (newstatl << outoffsetl); + *flags = (*flags & (~(1 << outoffsetc))) | (newstatc << outoffsetc); +} + +static int +grub_sendkey_parse_op (char *name) +{ + char *var; + + var = grub_env_get (name); + + if (!var) + return 2; + + if (!grub_strcmp (var, "off") || !grub_strcmp (var, "0") || !grub_strcmp (var, "unpress")) + return 0; + + if (!grub_strcmp (var, "on") || !grub_strcmp (var, "1") || !grub_strcmp (var, "press")) + return 1; + + return 2; +} + +/* Set keyboard buffer to our sendkey */ +static grub_err_t +grub_sendkey_preboot (int noreturn __attribute__ ((unused))) +{ + + /* Length of sendkey */ + int keylen = 0; + char sendkey[0x20]; + /* For convenion: pointer to flags */ + unsigned long *flags = (unsigned long *) RAW_ADDR (0x417); + char *next, ch=0, *sendkeyvar; + int noled = 0; + + auto int find_key_code (char *key); + auto int find_ascii_code (char *key); + + auto int find_key_code (char *key) + { + unsigned i; + + for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) + { + if (keysym_table[i].unshifted_name && grub_strcmp (key, keysym_table[i].unshifted_name) == 0) + return keysym_table[i].keycode; + else if (keysym_table[i].shifted_name && grub_strcmp (key, keysym_table[i].shifted_name) == 0) + return keysym_table[i].keycode; + } + + return 0; + } + + auto int find_ascii_code (char *key) + { + unsigned i; + + for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) + { + if (keysym_table[i].unshifted_name && grub_strcmp (key, keysym_table[i].unshifted_name) == 0) + return keysym_table[i].unshifted_ascii; + else if (keysym_table[i].shifted_name && grub_strcmp (key, keysym_table[i].shifted_name) == 0) + return keysym_table[i].shifted_ascii; + } + + return 0; + } + + sendkeyvar = grub_env_get ("sendkey"); + + if (sendkeyvar) + do + { + next = grub_strchr (sendkeyvar, ' '); + if (next) + { + ch = *next; + *next = 0; + } + if (find_key_code (sendkeyvar)) + { + sendkey[keylen++] = find_ascii_code (sendkeyvar); + sendkey[keylen++] = find_key_code (sendkeyvar); + } + if (next) + { + *next = ch; + sendkeyvar = next + 1; + } + } + while (next && keylen < 0x20); + + { + int i; + /* Set the sendkey */ + *((char *) RAW_ADDR (0x41a)) = 0x1e; + *((char *) RAW_ADDR (0x41c)) = keylen + 0x1e; + for(i = 0; i < 0x20; i++) + ((char *) RAW_ADDR (0x41e))[i] = sendkey[i]; + } + + /* Set the flags. For more information reffer to technical specification*/ + grub_sendkey_set_simple_flag (flags, 5, grub_sendkey_parse_op("kb_num")); // numlock mode + grub_sendkey_set_simple_flag (flags, 6, grub_sendkey_parse_op("kb_caps")); // capslock mode + grub_sendkey_set_simple_flag (flags, 4, grub_sendkey_parse_op("kb_scroll")); // scrolllock mode + grub_sendkey_set_simple_flag (flags, 7, grub_sendkey_parse_op("kb_insert")); // insert mode + grub_sendkey_set_simple_flag (flags, 11, grub_sendkey_parse_op("kb_wait")); // wait mode + grub_sendkey_set_simple_flag (flags, 1, grub_sendkey_parse_op("kb_lshift")); // left shift + grub_sendkey_set_simple_flag (flags, 0, grub_sendkey_parse_op("kb_rshift")); // right shift + grub_sendkey_set_simple_flag (flags, 10, grub_sendkey_parse_op("kb_sysreq")); // sysreq + grub_sendkey_set_simple_flag (flags, 13, grub_sendkey_parse_op("kb_numkey")); // numlock key + grub_sendkey_set_simple_flag (flags, 14, grub_sendkey_parse_op("kb_capskey")); // capslock key + grub_sendkey_set_simple_flag (flags, 12, grub_sendkey_parse_op("kb_scrollkey")); // scrolllock key + grub_sendkey_set_simple_flag (flags, 15, grub_sendkey_parse_op("kb_insertkey")); // insert key + + /*Set ctrl and alt*/ + grub_sendkey_set_double_flag (flags, 2, 8, grub_sendkey_parse_op("kb_rctrl"), grub_sendkey_parse_op("kb_lctrl")); //Ctrl + grub_sendkey_set_double_flag (flags, 3, 9, grub_sendkey_parse_op("kb_ralt"), grub_sendkey_parse_op("kb_lalt")); //Alt + + + /* Set noled */ + { + char *var; + + /* set 1 if set explicitely */ + if ((var = grub_env_get ("kb_noled")) && grub_strcmp (var, "0")) + noled = 1; + + /* implicit: when LEDs haven't changed */ + if (!var && grub_sendkey_parse_op("kb_num") == 2 && grub_sendkey_parse_op("kb_caps") == 2 + && grub_sendkey_parse_op("kb_scroll") == 2) + noled = 1; + } + + /* Write new LED state */ + if (!noled) + { + int value = 0; + int failed; + /* Try 5 times */ + for (failed = 0; failed < 5; failed++) + { + value = 0; + /* Send command change LEDs */ + outportb (0xed, 0x60); + + /* Wait */ + while ((value != 0xfa) && (value != 0xfe)) + value = inb (0x60); + + if (value == 0xfa) + { + /* Set new LEDs*/ + outportb ((flags[0] >> 4) & 7, 0x60); + break; + } + } + } + return 0; +} + +GRUB_MOD_INIT(sendkey) +{ + (void)mod; /* To stop warning. */ + unsigned i; + /* List of variables to set to "keep" */ + static char list[16][12] = + { + "kb_num", "kb_caps", "kb_scroll", "kb_insert", "kb_wait", "kb_lshift", "kb_rshift", "kb_sysreq", + "kb_numkey", "kb_capskey", "kb_scrollkey", "kb_insertkey", "kb_lalt", "kb_ralt", "kb_lctrl", "kb_rctrl" + }; + + grub_env_set ("sendkey", ""); + grub_env_set ("kb_noled", "0"); + + for (i = 0; i < sizeof (list) / sizeof (list[0]); i++) + grub_env_set (list[i], "keep"); + + grub_sendkey_preboot_handle=grub_loader_add_preboot (grub_sendkey_preboot); +} + +GRUB_MOD_FINI(sendkey) +{ + + unsigned i; + /* List of variables to unset */ + static char list[19][12] = + { + "kb_num", "kb_caps", "kb_scroll", "kb_insert", "kb_wait", "kb_lshift", "kb_rshift", "kb_sysreq", + "kb_numkey", "kb_capskey", "kb_scrollkey", "kb_insertkey", "kb_lalt", "kb_ralt", "kb_lctrl", "kb_rctrl", + "sendkey", "kb_noled" + }; + + for (i = 0; i < sizeof (list) / sizeof (list[0]); i++) + grub_env_unset (list[i]); + + grub_loader_remove_preboot (grub_sendkey_preboot_handle); +}