[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Bug-fixing and keystroke
From: |
Serbinenko Vladimir |
Subject: |
Bug-fixing and keystroke |
Date: |
Sat, 30 Jul 2005 15:20:21 +0200 |
User-agent: |
Mozilla Thunderbird 1.0.2-1.3.2 (X11/20050324) |
I wrote some bugfixing patch + new feature.
Bug-fixing was mainly about FAT bug (unalloc magic on not-fat fs).
The new feature is sending keystroke to OS (imitating keypress +
changing keyboard flags).
it works like:
keystroke [flags] [keys]
[flags] are like
--capslock=0 --rshift=1 ... (documentation in patch in keystroke.c at
the end)
0 - means set flag to 0, 1 to 1 and 2 means keep value.
Some flags are the modes (like caps, num, scroll). Others are keys (like
ctrl and shift)
If you set 0/1 to mode it will result like turning off/on the mode
If you set key to 1 it will imitate keypressing until you really press it
[keys] are key1 key2 ... like
h e l l o or
down down enter.
keylist is taken from GRUB Legacy + some new keys.
Known bugs (can smb help fix them):
LEDs in qemu are not set
help doesn't contain all useful informations.
Serbinenko Vladimir
2005-07-30 Vladimir Serbinenko <address@hidden>
Some bugfixes
* commands/ls.c (grub_ls_list_disks): fixed segmentation fault
when fs == 0 or fs->label == 0
(grub_ls_list_files): Added label showing
* kern/disk.c (grub_print_partinfo): fixed segmentation fault when
fs->label == 0
* fs/fat.c (grub_fat_dir): fixed segmentetaion fault by freeing
Keystroke module(pc) and preboots
* commands/boot.c: Added support for preboot functions
* conf/i386.rmk: new module keystroke
* include/grub/normal.h: new headers and types for preboots
* keystroke/keystroke.c: new file
diff -urN grub2um/commands/boot.c grub2m/commands/boot.c
--- grub2um/commands/boot.c 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/commands/boot.c 2005-07-25 16:58:11.000000000 +0200
@@ -23,13 +23,23 @@
#include <grub/arg.h>
#include <grub/misc.h>
#include <grub/loader.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+
+static grub_prebootfn_t *grub_preboots = 0;
+static int grub_preboot_cnt = 0;
static grub_err_t
grub_cmd_boot (struct grub_arg_list *state __attribute__ ((unused)),
int argc, char **args __attribute__ ((unused)))
{
+ int i;
+
if (argc)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many arguments");
+
+ for (i = 0; i < grub_preboot_cnt; i++)
+ grub_preboots[i] ();
grub_loader_boot ();
@@ -38,6 +48,46 @@
+grub_err_t
+grub_preboot_add (grub_prebootfn_t fn)
+{
+ grub_prebootfn_t *tmp;
+ tmp = (grub_prebootfn_t *) grub_realloc (grub_preboots, (grub_preboot_cnt +
1) * sizeof(grub_prebootfn_t));
+ if (!tmp)
+ return grub_errno;
+ grub_preboots = tmp;
+ grub_preboots[grub_preboot_cnt] = fn;
+ grub_preboot_cnt++;
+
+ return 0;
+}
+
+
+
+grub_err_t
+grub_preboot_remove (grub_prebootfn_t fn)
+{
+ int i;
+ for (i = 0; i < grub_preboot_cnt; i++)
+ if (grub_preboots[i] == fn)
+ break;
+
+ if (i == grub_preboot_cnt)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "fn not found");
+ }
+
+ for (; i < grub_preboot_cnt - 1; i++)
+ grub_preboots[i] = grub_preboots[i + 1];
+
+ grub_preboots = (grub_prebootfn_t *) grub_realloc (grub_preboots,
(--grub_preboot_cnt) * sizeof(grub_prebootfn_t));
+
+ return 0;
+
+}
+
+
+
#ifdef GRUB_UTIL
void
grub_boot_init (void)
diff -urN grub2um/commands/ls.c grub2m/commands/ls.c
--- grub2um/commands/ls.c 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/commands/ls.c 2005-07-30 13:42:04.000000000 +0200
@@ -84,16 +84,18 @@
grub_printf (", Filesystem type %s",
fs ? fs->name : "Unknown");
-
- (fs->label) (dev, &label);
- if (grub_errno == GRUB_ERR_NONE)
+ if (fs && fs->label)
{
- if (label && grub_strlen (label))
- grub_printf (", Label: %s", label);
- grub_free (label);
+ (fs->label) (dev, &label);
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ if (label && grub_strlen (label))
+ grub_printf (", Label: %s", label);
+ grub_free (label);
+ }
+ else
+ grub_errno = GRUB_ERR_NONE;
}
- else
- grub_errno = GRUB_ERR_NONE;
}
grub_putchar ('\n');
@@ -108,6 +110,7 @@
}
grub_device_close (dev);
+
}
return 0;
@@ -223,6 +226,19 @@
grub_printf ("(%s): Filesystem is %s.\n",
device_name, fs ? fs->name : "unknown");
+ if (fs && fs->label)
+ {
+ char *label;
+ (fs->label) (dev, &label);
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ if (label && grub_strlen (label))
+ grub_printf (", Label: %s", label);
+ grub_free (label);
+ }
+ else
+ grub_errno = GRUB_ERR_NONE;
+ }
}
else if (fs)
{
@@ -267,6 +283,7 @@
}
fail:
+
if (dev)
grub_device_close (dev);
diff -urN grub2um/conf/i386-pc.mk grub2m/conf/i386-pc.mk
--- grub2um/conf/i386-pc.mk 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/conf/i386-pc.mk 2005-07-25 15:25:29.000000000 +0200
@@ -989,7 +989,7 @@
font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
- help.mod default.mod timeout.mod configfile.mod
+ help.mod default.mod timeout.mod configfile.mod keystroke.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -1781,6 +1781,51 @@
hello_mod_CFLAGS = $(COMMON_CFLAGS)
+# For keystroke.mod.
+keystroke_mod_SOURCES = keystroke/keystroke.c
+CLEANFILES += keystroke.mod mod-keystroke.o mod-keystroke.c pre-keystroke.o
keystroke_mod-keystroke_keystroke.o def-keystroke.lst und-keystroke.lst
+MOSTLYCLEANFILES += keystroke_mod-keystroke_keystroke.d
+DEFSYMFILES += def-keystroke.lst
+UNDSYMFILES += und-keystroke.lst
+
+keystroke.mod: pre-keystroke.o mod-keystroke.o
+ -rm -f $@
+ $(LD) -r -d -o $@ $^
+ $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R
.comment $@
+
+pre-keystroke.o: keystroke_mod-keystroke_keystroke.o
+ -rm -f $@
+ $(LD) -r -d -o $@ $^
+
+mod-keystroke.o: mod-keystroke.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(keystroke_mod_CFLAGS) -c -o $@ $<
+
+mod-keystroke.c: moddep.lst genmodsrc.sh
+ sh $(srcdir)/genmodsrc.sh 'keystroke' $< > $@ || (rm -f $@; exit 1)
+
+def-keystroke.lst: pre-keystroke.o
+ $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 keystroke/' >
$@
+
+und-keystroke.lst: pre-keystroke.o
+ echo 'keystroke' > $@
+ $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+keystroke_mod-keystroke_keystroke.o: keystroke/keystroke.c
+ $(CC) -Ikeystroke -I$(srcdir)/keystroke $(CPPFLAGS) $(CFLAGS)
$(keystroke_mod_CFLAGS) -c -o $@ $<
+
+keystroke_mod-keystroke_keystroke.d: keystroke/keystroke.c
+ set -e; $(CC) -Ikeystroke -I$(srcdir)/keystroke $(CPPFLAGS)
$(CFLAGS) $(keystroke_mod_CFLAGS) -M $< | sed 's,keystroke\.o[
:]*,keystroke_mod-keystroke_keystroke.o $@ : ,g' > $@; [ -s $@ ] ||
rm -f $@
+
+-include keystroke_mod-keystroke_keystroke.d
+
+CLEANFILES += cmd-keystroke.lst
+COMMANDFILES += cmd-keystroke.lst
+
+cmd-keystroke.lst: keystroke/keystroke.c gencmdlist.sh
+ set -e; $(CC) -Ikeystroke -I$(srcdir)/keystroke $(CPPFLAGS)
$(CFLAGS) $(keystroke_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh
keystroke > $@ || (rm -f $@; exit 1)
+
+keystroke_mod_CFLAGS = $(COMMON_CFLAGS)
+
# For boot.mod.
boot_mod_SOURCES = commands/boot.c
CLEANFILES += boot.mod mod-boot.o mod-boot.c pre-boot.o
boot_mod-commands_boot.o def-boot.lst und-boot.lst
diff -urN grub2um/conf/i386-pc.rmk grub2m/conf/i386-pc.rmk
--- grub2um/conf/i386-pc.rmk 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/conf/i386-pc.rmk 2005-07-25 15:25:29.000000000 +0200
@@ -102,7 +102,7 @@
font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
- help.mod default.mod timeout.mod configfile.mod
+ help.mod default.mod timeout.mod configfile.mod keystroke.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -163,6 +163,10 @@
hello_mod_SOURCES = hello/hello.c
hello_mod_CFLAGS = $(COMMON_CFLAGS)
+# For keystroke.mod.
+keystroke_mod_SOURCES = keystroke/keystroke.c
+keystroke_mod_CFLAGS = $(COMMON_CFLAGS)
+
# For boot.mod.
boot_mod_SOURCES = commands/boot.c
boot_mod_CFLAGS = $(COMMON_CFLAGS)
diff -urN grub2um/fs/fat.c grub2m/fs/fat.c
--- grub2um/fs/fat.c 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/fs/fat.c 2005-07-30 14:26:32.000000000 +0200
@@ -629,7 +629,7 @@
struct grub_fat_data *data = 0;
grub_disk_t disk = device->disk;
grub_size_t len;
- char *dirname;
+ char *dirname = 0;
char *p;
#ifndef GRUB_UTIL
@@ -660,8 +660,10 @@
fail:
- grub_free (dirname);
- grub_free (data);
+ if (dirname)
+ grub_free (dirname);
+ if (data)
+ grub_free (data);
#ifndef GRUB_UTIL
grub_dl_unref (my_mod);
diff -urN grub2um/include/grub/normal.h grub2m/include/grub/normal.h
--- grub2um/include/grub/normal.h 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/include/grub/normal.h 2005-07-25 15:25:29.000000000 +0200
@@ -44,6 +44,9 @@
/* Not loaded yet. Used for auto-loading. */
#define GRUB_COMMAND_FLAG_NOT_LOADED 0x20
+/* Preboot function declaration. */
+typedef void (*grub_prebootfn_t) (void);
+
/* The command description. */
struct grub_command
{
@@ -178,6 +181,8 @@
grub_menu_t grub_context_get_current_menu (void);
grub_menu_t grub_context_push_menu (grub_menu_t menu);
void grub_context_pop_menu (void);
+grub_err_t grub_preboot_add (grub_prebootfn_t fn);
+grub_err_t grub_preboot_remove (grub_prebootfn_t fn);
#ifdef GRUB_UTIL
void grub_normal_init (void);
diff -urN grub2um/kern/disk.c grub2m/kern/disk.c
--- grub2um/kern/disk.c 2005-07-25 15:23:26.000000000 +0200
+++ grub2m/kern/disk.c 2005-07-30 12:14:34.000000000 +0200
@@ -535,7 +535,7 @@
grub_printf ("\tPartition num:%s, Filesystem type %s",
partname, fs ? fs->name : "Unknown");
- if (fs)
+ if (fs && fs->label)
{
(fs->label) (part, &label);
if (grub_errno == GRUB_ERR_NONE)
diff -urN grub2um/keystroke/keystroke.c grub2m/keystroke/keystroke.c
--- grub2um/keystroke/keystroke.c 1970-01-01 01:00:00.000000000 +0100
+++ grub2m/keystroke/keystroke.c 2005-07-28 16:59:19.000000000 +0200
@@ -0,0 +1,406 @@
+/* keystroke.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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/arg.h>
+
+#define RAW_ADDR(a) ((void *)(a))
+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 */
+};
+
+char keystroke[32];
+int keylen=0;
+/* The sum of:
+ x << y x - action y - flag
+ x: 0x0 - turn off, 0x1 - turn on , 0x3 - keep
+ y:
+ 0x0 - numlock mode,
+ 0x1 - capslock mode,
+ 0x2 - scrolllock mode,
+ 0x3 - insert mode,
+ 0x4 - wait mode,
+ 0x5 - left shift key,
+ 0x6 - right shift key,
+ 0x7 - left alt key,
+ 0x8 - right alt key,
+ 0x9 - left ctrl key,
+ 0xa - right ctrl key,
+ 0xb - sysreq key,
+ 0xc - numlock key,
+ 0xd - capslock key,
+ 0xe - scrolllock key,
+ 0xf - insert key
+ */
+unsigned long kbflags=0;
+int noled = 1;
+
+/* 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,
+ inoffset - offset of flag in kbflags
+*/
+static void
+grub_keystroke_set_simple_flag (unsigned long *flags, int outoffset, int
inoffset)
+{
+ /* previous state of flag */
+ int prevstat = (*flags >> outoffset) & 1;
+ /* what to do with flag*/
+ int operation = (kbflags >> inoffset) & 3;
+ /* new state */
+ int newstat = (operation == 1) || (operation == 2 && prevstat);
+ /* Set new state */
+ *flags = (*flags & (~(1 << outoffset))) | (newstat << outoffset);
+}
+
+/* Set a double flag (ctrl/alt) in flags variable
+ flags - where to set,
+ outoffsetc - offset of common flag in FLAGS,
+ outoffsetl - offset of "left" flag in FLAGS,
+ inoffsetr - offset of "right" flag in kbflags,
+ inoffsetl - offset of "left" flag in kbflags,
+*/
+static void
+grub_keystroke_set_double_flag (unsigned long *flags, int outoffsetc, int
outoffsetl, int inoffsetr, int inoffsetl)
+{
+ /* previous state of flag */
+ int prevstatc = (*flags >> outoffsetc) & 1;
+ int prevstatl = (*flags >> outoffsetl) & 1;
+ int prevstatr = prevstatc && (!prevstatl);
+ /* what to do with flag*/
+ int operationr = (kbflags >> inoffsetr) & 3;
+ int operationl = (kbflags >> inoffsetl) & 3;
+ /* new state */
+ int newstatl = (operationl == 1) || (operationl == 2 && prevstatl);
+ int newstatr = (operationr == 1) || (operationr == 2 && prevstatr);
+ int newstatc = newstatr || newstatr;
+ /* Set new state */
+ *flags = (*flags & (~(1 << outoffsetl))) | (newstatl << outoffsetl);
+ *flags = (*flags & (~(1 << outoffsetc))) | (newstatc << outoffsetc);
+}
+
+
+/* Set keyboard buffer to our keystroke */
+static void
+grub_keystroke_preboot (void)
+{
+
+ int i;
+ /* For convenion: pointer to flags */
+ unsigned long *flags = (unsigned long *) RAW_ADDR (0x417);
+
+ /* Set the keystroke */
+ *((char *) RAW_ADDR (0x41a)) = 0x1e;
+ *((char *) RAW_ADDR (0x41c)) = keylen+0x1e;
+ for(i = 0; i < 0x20; i++)
+ ((char *) RAW_ADDR (0x41e))[i] = keystroke[i];
+
+ /* Set the flags. For more information reffer to technical specification*/
+ grub_keystroke_set_simple_flag (flags, 5, 0 * 2); // numlock mode
+ grub_keystroke_set_simple_flag (flags, 6, 1 * 2); // capslock mode
+ grub_keystroke_set_simple_flag (flags, 4, 2 * 2); // scrolllock mode
+ grub_keystroke_set_simple_flag (flags, 7, 3 * 2); // insert mode
+ grub_keystroke_set_simple_flag (flags, 11, 4 * 2); // wait mode
+ grub_keystroke_set_simple_flag (flags, 1, 5 * 2); // left shift
+ grub_keystroke_set_simple_flag (flags, 0, 6 * 2); // right shift
+ grub_keystroke_set_simple_flag (flags, 10, 0xb * 2); // sysreq
+ grub_keystroke_set_simple_flag (flags, 13, 0xc * 2); // numlock key
+ grub_keystroke_set_simple_flag (flags, 14, 0xd * 2); // capslock key
+ grub_keystroke_set_simple_flag (flags, 12, 0xe * 2); // scrolllock key
+ grub_keystroke_set_simple_flag (flags, 15, 0xf * 2); // insert key
+
+ /*Set ctrl and alt*/
+ grub_keystroke_set_double_flag (flags, 2, 8, 0xa * 2, 9 * 2); //Ctrl
+ grub_keystroke_set_double_flag (flags, 3, 9, 8 * 2, 7 * 2); //Alt
+
+ /* 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;
+ }
+ }
+ }
+}
+
+ /* 0x0 - numlock mode,
+ 0x1 - capslock mode,
+ 0x2 - scrolllock mode,
+ 0x3 - insert mode,
+ 0x4 - wait mode,
+ 0x5 - left shift key,
+ 0x6 - right shift key,
+ 0x7 - left alt key,
+ 0x8 - right alt key,
+ 0x9 - left ctrl key,
+ 0xa - right ctrl key,
+ 0xb - sysreq key,
+ 0xc - numlock key,
+ 0xd - capslock key,
+ 0xe - scrolllock key,
+ 0xf - insert key*/
+
+/*Parse keystroke */
+static grub_err_t
+grub_cmd_keystroke (struct grub_arg_list *state,
+ int argc,
+ char **args)
+{
+
+ /* To stop warning */
+ 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;
+ }
+
+ int i;
+
+ /* Set keystroke and keylen variables*/
+ keylen = 0;
+
+ for (i = 0; i < argc && keylen < 0x20; i++)
+ {
+ if (find_key_code (args[i]))
+ {
+ keystroke[keylen++] = find_ascii_code (args[i]);
+ keystroke[keylen++] = find_key_code (args[i]);
+ }
+ }
+
+ /* Set kbflags */
+ kbflags = 0;
+ for (i = 0; i <= 15; i++)
+ kbflags |= (state[i].set ? grub_strtoul (state[i].arg, 0, 0) : 2) << (2*i);
+
+ noled = state[16].set;
+
+ return 0;
+}
+
+static const struct grub_arg_option options[] =
+ {
+ {"numlock", 'n', GRUB_ARG_OPTION_OPTIONAL, "set numlock mode
(2=keep, 0=off, 1=on)", "2", ARG_TYPE_INT},
+ {"capslock", 'c', GRUB_ARG_OPTION_OPTIONAL, "set capslock mode
(2=keep, 0=off, 1=on)", "2", ARG_TYPE_INT},
+ {"scrolllock", 's', GRUB_ARG_OPTION_OPTIONAL, "set scrolllock mode
(2=keep, 0=off, 1=on)", "2", ARG_TYPE_INT},
+ {"insert", 'i', GRUB_ARG_OPTION_OPTIONAL, "set insert mode
(2=keep, 0=off, 1=on)", "2", ARG_TYPE_INT},
+ {"wait", 0 , GRUB_ARG_OPTION_OPTIONAL, "set wait mode (pause)
(2=keep, 0=off, 1=on)", "2", ARG_TYPE_INT},
+ {"lshift", 'l', GRUB_ARG_OPTION_OPTIONAL, "block left shift key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"rshift", 'r', GRUB_ARG_OPTION_OPTIONAL, "block right shift key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"lalt", 0 , GRUB_ARG_OPTION_OPTIONAL, "block left alt key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"ralt", 'a', GRUB_ARG_OPTION_OPTIONAL, "block right alt key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"lctrl", 0 , GRUB_ARG_OPTION_OPTIONAL, "block left ctrl key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"rctrl", 0 , GRUB_ARG_OPTION_OPTIONAL, "block right ctrl key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"sysreq", 0 , GRUB_ARG_OPTION_OPTIONAL, "block sys req key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"numkey", 0 , GRUB_ARG_OPTION_OPTIONAL, "block numlock key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"capskey", 0 , GRUB_ARG_OPTION_OPTIONAL, "block capslock key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"scrkey", 0 , GRUB_ARG_OPTION_OPTIONAL, "block scrolllock key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"inskey", 0 , GRUB_ARG_OPTION_OPTIONAL, "block insert key
(2=no, 0=unpress, 1=press)", "2", ARG_TYPE_INT},
+ {"noled", 0 , 0, "Don't try to set LEDs. Try if blocks.", 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+GRUB_MOD_INIT
+{
+ (void)mod; /* To stop warning. */
+ grub_register_command ("keystroke", grub_cmd_keystroke,
GRUB_COMMAND_FLAG_BOTH,
+ "keystroke [options] [KEY1 [KEY2 ...[KEY16]...]]",
+"Send a keystroke to OS. Set keyboard mode and block some keys as
pressed/unpressed. Keys are unblocked on next press.", options);
+ grub_preboot_add (grub_keystroke_preboot);
+}
+
+GRUB_MOD_FINI
+{
+ grub_unregister_command ("keystroke");
+ grub_preboot_remove (grub_keystroke_preboot);
+}