grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Sendkey patch


From: phcoder
Subject: Sendkey patch
Date: Tue, 02 Sep 2008 16:23:14 +0200
User-agent: Thunderbird 2.0.0.16 (X11/20080724)

Hello. I wrote a patch to add sendkey functionality to grub2. After
loading sendkey module some new environments variables appear with which
one may control the sequence of keys that would be sent to OS or next
bootloader. This functionality is useful in different cases. One example
 is entering "safe mode" in some OS when without this feature you
desperately try many times to press "magic key" in exactly good moment.
Another usage example is chainloading another bootloader. Then you can
send someting like "down down enter" to it and avoid another delay. The
implementation as environment variables has its downside as I don't know
where to put help about it. Perhaps possibility of adding help notice to
environment variables would be a good idea. Then we could do like
>help root
root is a variable containing root device.
For implementing this functionality I needed my function to be executed
right before booting. To do it I added a simple interface for adding
"preboot" functions:
struct grub_preboot_t *grub_loader_add_preboot (grub_err_t
(*preboot_func) (int));
As parameter this function recieves a callback (integer parameter to
callback is noreturn variable). This function returns a handle with
which the preboot function may be removed using
void grub_loader_remove_preboot (struct grub_preboot_t *p);
Implementation uses linked lists and tries to implement it in as few
commands as possible since this code is a part of core image. This
interface can later be reused for adding different hooks to bios ("map",
"memdisk",...). Now the questions are:
Whether such interface is OK for grub2?
Whether we need also interface for adding "postboot" commands? (in case
boot_function returns)
Variables made available after loading sendkey module:
sendkey - a space-separated list of keys to be sent
kb_num, kb_caps, kb_scroll, kb_insert, kb_wait - [keep|on|off] - set
numlock, capslock, scrollock, insert or wait state
kb_noled - [0|1] When set to 1 the LED state is not changed to match
num-/caps-/scrolllock state
"kb_lshift", "kb_rshift", "kb_sysreq", "kb_numkey", "kb_capskey",
"kb_scrollkey", "kb_insertkey", "kb_lalt", "kb_ralt", "kb_lctrl",
"kb_rctrl" - [keep|on|off] When set to on emulate pressing and holding
of corresponding key. To undo just press the corresponding key on your
keyboard

Regards
Vladimir Serbinenko
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 <grub/err.h>
 #include <grub/kernel.h>
 
+
 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 <grub/err.h>
 #include <grub/types.h>
 
+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 address@hidden
+ *
+ *  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 <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+
+#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);
+}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]