diff -urN grub.orig/grub-core/bus/usb/usb.c grub/grub-core/bus/usb/usb.c
--- grub.orig/grub-core/bus/usb/usb.c	2013-10-02 09:40:06.284312525 +0200
+++ grub/grub-core/bus/usb/usb.c	2013-10-02 09:42:32.584318027 +0200
@@ -262,6 +262,8 @@
 	case GRUB_USB_CLASS_HID:
 	  grub_dl_load ("usb_keyboard");
 	  grub_print_error ();
+	  grub_dl_load ("usb_mouse");
+	  grub_print_error ();
 	  break;
 	case 0xff:
 	  /* FIXME: don't load useless modules.  */
diff -urN grub.orig/grub-core/Makefile.core.def grub/grub-core/Makefile.core.def
--- grub.orig/grub-core/Makefile.core.def	2013-10-02 09:40:06.304309977 +0200
+++ grub/grub-core/Makefile.core.def	2013-10-02 09:42:03.900319068 +0200
@@ -1781,6 +1781,13 @@
 };
 
 module = {
+  name = usb_mouse;
+  common = term/mouse.c;
+  common = term/usb_mouse.c;
+  enable = usb;
+};
+
+module = {
   name = vga;
   common = video/i386/pc/vga.c;
   enable = i386_pc;
diff -urN grub.orig/grub-core/term/mouse.c grub/grub-core/term/mouse.c
--- grub.orig/grub-core/term/mouse.c	1970-01-01 01:00:00.000000000 +0100
+++ grub/grub-core/term/mouse.c	2013-10-02 09:41:29.324313408 +0200
@@ -0,0 +1,79 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008, 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mouse.h>
+#include <grub/list.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+
+static struct grub_mouse_hook *grub_mouse_hooks;
+
+grub_err_t
+grub_mouse_add_hook(grub_mouse_callback_t callback, void *priv)
+{
+  struct grub_mouse_hook *hook;
+
+  hook = grub_malloc(sizeof(*hook));
+  if (!hook)
+    {
+      grub_print_error();
+      return GRUB_ERR_OUT_OF_MEMORY;
+    }
+
+  hook->callback = callback;
+  hook->priv = priv;
+
+  grub_list_push (GRUB_AS_LIST_P (&grub_mouse_hooks), GRUB_AS_LIST (hook));
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_mouse_remove_hook(grub_mouse_callback_t callback, void *priv)
+{
+  struct grub_mouse_hook *hook;
+
+  FOR_LIST_ELEMENTS((hook), (grub_mouse_hooks))
+    {
+      if (hook->callback == callback && hook->priv == priv)
+        {
+          grub_list_remove (GRUB_AS_LIST (grub_mouse_hooks));
+          grub_free(hook);
+          return GRUB_ERR_NONE;
+        }
+    }
+
+  return GRUB_ERR_FILE_NOT_FOUND;
+}
+
+int
+grub_mouse_call_hook(struct grub_mouse_event *ev)
+{
+  struct grub_mouse_hook *hook;
+  int key;
+
+  FOR_LIST_ELEMENTS((hook), (grub_mouse_hooks))
+    {
+      key = hook->callback(ev, hook->priv);
+      if (key != GRUB_TERM_NO_KEY)
+        return key;
+    }
+
+  return GRUB_TERM_NO_KEY;
+}
diff -urN grub.orig/grub-core/term/usb_mouse.c grub/grub-core/term/usb_mouse.c
--- grub.orig/grub-core/term/usb_mouse.c	1970-01-01 01:00:00.000000000 +0100
+++ grub/grub-core/term/usb_mouse.c	2013-10-02 09:59:41.420330122 +0200
@@ -0,0 +1,526 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008, 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is a driver for USB mice and touchscreens.  Since there is no
+ * proper input event framework in GRUB we are using the keyboard
+ * infrastructure to perform polling of the USB bus.
+ *
+ * This file is based on usb_kebyoard.c */
+
+#include <grub/misc.h>
+#include <grub/term.h>
+#include <grub/usb.h>
+#include <grub/dl.h>
+#include <grub/mouse.h>
+#include <grub/video.h>
+GRUB_MOD_LICENSE ("GPLv3+");
+
+
+
+/* Valid values for bRequest.  See HID definition version 1.11 section 7.2. */
+#define USB_HID_GET_REPORT	0x01
+#define USB_HID_GET_IDLE	0x02
+#define USB_HID_GET_PROTOCOL	0x03
+#define USB_HID_SET_REPORT	0x09
+#define USB_HID_SET_IDLE	0x0A
+#define USB_HID_SET_PROTOCOL	0x0B
+
+#define USB_HID_BOOT_SUBCLASS	0x01
+#define USB_HID_KBD_PROTOCOL	0x01
+#define USB_HID_USB_MOUSE_PROTOCOL	0x02
+
+#define GRUB_USB_MOUSE_LEFT_CTRL   0x01
+#define GRUB_USB_MOUSE_LEFT_SHIFT  0x02
+#define GRUB_USB_MOUSE_LEFT_ALT    0x04
+#define GRUB_USB_MOUSE_RIGHT_CTRL  0x10
+#define GRUB_USB_MOUSE_RIGHT_SHIFT 0x20
+#define GRUB_USB_MOUSE_RIGHT_ALT   0x40
+
+/* Report field definitions */
+struct grub_usb_hid_field
+{
+  grub_uint8_t offset;		/* bit offset of field within report */
+  grub_uint8_t size;		/* size of field in bits */
+  grub_int16_t logical_min;	/* minimum value for field */
+  grub_int16_t logical_max;	/* maximum value for field */
+};
+
+/* Boot mice parameters */
+struct grub_usb_mouse_param
+{
+  grub_uint16_t vendorid;	/* USB Vendor ID */
+  grub_uint16_t prodid;		/* USB Product ID */
+  grub_uint8_t report_size;	/* Report Size */
+  grub_uint8_t flags;		/* Flags (see below) */
+  struct grub_usb_hid_field buttons; /* Buttons field in report */
+  struct grub_usb_hid_field x;  /* X field in report */
+  struct grub_usb_hid_field y;  /* Y field in report */
+};
+
+/* This device uses the USB boot device protocol */
+#define FLAG_BOOT_DEVICE	(1<<0)
+/* This device reports an absolute position, i.e. it is a touch
+   pad/screen, mice and joysticks report relative positions */
+#define FLAG_ABSOLUTE		(1<<1)
+
+/* Standard USB boot mouse report descriptor */
+static const struct grub_usb_mouse_param grub_usb_mouse_param_boot =
+  { -1, -1, 4, FLAG_BOOT_DEVICE,
+    { 0, 3, 0, 8 }, { 8, 8, -127, 127 }, { 16, 8, -127, 127 } };
+
+static int quirk_swap_xy;
+static int quirk_invert_x;
+static int quirk_invert_y;
+static int quirk_widescreen;
+
+/* Custom USB mouse parameters
+ *
+ * If the USB vendor and product ID matches an entry in this table we
+ * use the entry instead of the standard USB boot mouse parameters. */
+static const struct grub_usb_mouse_param grub_usb_mouse_param_custom[] =
+  {
+    /* Microchip TSHARC touch screen controller.  Identifies itself as
+     * a boot mouse but has an incompatible 5 byte descriptor and will
+     * crash if we try to read anything but 5 bytes at a time.
+     */
+    { 0x07dd, 0x0001, 5, FLAG_ABSOLUTE,
+      { 0, 3, 0, 8 }, { 8, 16, 0, 0xfff }, { 24, 16, 0, 0xfff } },
+
+    /* USB Tablet emulation in QEMU.  This is really useful for
+     * testing the tablet code.
+     *
+     * Note that the USB Mouse emulation in QEMU uses the same vendor
+     * and product ID but uses the standard USB boot mouse descriptor,
+     * so there is no easy way to distinguish between them unless we
+     * start looking at the configuration string descriptors or at the
+     * report descriptor (and the whole purpose of having these tables
+     * is to avoid parsing the report descriptor).  So if you want to
+     * use the QEMU mouse emulation you have to uncomment this entry. */
+    /* QEMU USB Tablet */
+    { 0x0627, 0x0001, 6, FLAG_ABSOLUTE,
+      { 0, 3, 0, 8 }, { 8, 16, 0, 0x7fff }, { 24, 16, 0, 0x7fff } },
+  };
+
+/* State for mouse device */
+struct grub_usb_mouse_data
+{
+  grub_usb_device_t usbdev;	/* Handle to USB device */
+  struct grub_usb_desc_endp *endp; /* Handle to USB endpoint */
+  grub_usb_transfer_t transfer;	   /* Handle to active USB transfer */
+  const struct grub_usb_mouse_param *param; /* Mouse param */
+  grub_uint8_t report[8];	   /* Report being read */
+  grub_uint8_t current_report[8];  /* Current good report */
+  int dead;			   /* Device is shutting down */
+};
+
+static grub_err_t grub_usb_mouse_term_init (struct grub_term_input *term);
+static grub_err_t grub_usb_mouse_term_fini (struct grub_term_input *term);
+static int grub_usb_mouse_getkey (struct grub_term_input *term);
+static int grub_usb_mouse_getkeystatus (struct grub_term_input *term);
+static int globalx, globaly;
+
+static struct grub_term_input grub_usb_mouse_term =
+  {
+    .init = grub_usb_mouse_term_init,
+    .fini = grub_usb_mouse_term_fini,
+    .getkey = grub_usb_mouse_getkey,
+    .getkeystatus = grub_usb_mouse_getkeystatus,
+    .next = 0
+  };
+
+static struct grub_term_input grub_mice[16];
+
+static void
+grub_usb_mouse_detach (grub_usb_device_t usbdev,
+                       int config __attribute__ ((unused)),
+                       int interface __attribute__ ((unused)))
+{
+  unsigned i;
+  for (i = 0; i < ARRAY_SIZE (grub_mice); i++)
+    {
+      struct grub_usb_mouse_data *data = grub_mice[i].data;
+
+      if (!data)
+	continue;
+
+      if (data->usbdev != usbdev)
+	continue;
+
+      if (data->transfer)
+	grub_usb_cancel_transfer (data->transfer);
+
+      grub_term_unregister_input (&grub_mice[i]);
+      grub_free ((char *) grub_mice[i].name);
+      grub_mice[i].name = NULL;
+      grub_free (grub_mice[i].data);
+      grub_mice[i].data = 0;
+    }
+}
+
+
+
+static int
+grub_usb_mouse_extract (grub_uint8_t *report,
+                        const struct grub_usb_hid_field *field)
+{
+  int value;
+  int i;
+  int offset;
+
+  value = 0;
+  i = 0;
+  while (i < field->size)
+    {
+      offset = field->offset + i;
+      value |= (report[offset >> 3] >> (offset & 7)) << i;
+      i += 8 - (offset & 7);
+    }
+  value &= (1<<field->size) - 1;
+  if ((field->logical_min < 0 || field->logical_max < 0) &&
+      value & (1<<(field->size-1)))
+    value |= -1 << field->size;
+  return value;
+}
+
+static grub_err_t
+grub_usb_mouse_term_init (struct grub_term_input *term)
+{
+  struct grub_usb_mouse_data *termdata = term->data;
+
+  grub_dprintf("usb_mouse", "%s: %s\n", __func__, term->name);
+
+  termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev,
+                                                      termdata->endp,
+                                                      termdata->param->report_size,
+                                                      (char *) termdata->report);
+  if (!termdata->transfer)
+    {
+      grub_dprintf ("usb_mouse", "%s: failed to start transfer\n", term->name);
+      grub_print_error ();
+      return 0;
+    }
+
+  return 0;
+}
+
+static grub_err_t
+grub_usb_mouse_term_fini (struct grub_term_input *term)
+{
+  struct grub_usb_mouse_data *termdata = term->data;
+
+  grub_dprintf("usb_mouse", "%s: %s\n", __func__, term->name);
+
+  if (termdata->transfer)
+    grub_usb_cancel_transfer (termdata->transfer);
+
+  return 0;
+}
+
+static int
+grub_usb_mouse_getkey (struct grub_term_input *term)
+{
+  grub_usb_err_t err;
+  struct grub_usb_mouse_data *termdata = term->data;
+  grub_size_t actual;
+  struct grub_video_mode_info mode_info;
+  int x, y;
+  unsigned buttons;
+  struct grub_mouse_event ev;
+
+  if (termdata->dead)
+    return GRUB_TERM_NO_KEY;
+
+  /* Poll interrupt pipe.  */
+  err = grub_usb_check_transfer (termdata->transfer, &actual);
+
+  if (err == GRUB_USB_ERR_WAIT)
+    return GRUB_TERM_NO_KEY;
+
+  grub_memcpy (termdata->current_report,
+               termdata->report,
+               termdata->param->report_size);
+
+  termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev,
+                                                      termdata->endp,
+                                                      termdata->param->report_size,
+                                                      (char *) termdata->report);
+  if (!termdata->transfer)
+    {
+      grub_dprintf ("usb_mouse", "%s failed. Stopped\n", term->name);
+      termdata->dead = 1;
+    }
+
+  if (err) {
+    grub_dprintf ("usb_mouse", "%s failed to start new transfer\n", term->name);
+    grub_print_error ();
+    return GRUB_TERM_NO_KEY;
+  }
+
+  x = grub_usb_mouse_extract(termdata->current_report,
+                             &termdata->param->x);
+  y = grub_usb_mouse_extract(termdata->current_report,
+                             &termdata->param->y);
+  buttons = grub_usb_mouse_extract(termdata->current_report,
+                                   &termdata->param->buttons);
+
+  grub_dprintf ("usb_mouse",
+		"err = %d, actual = %" PRIuGRUB_SIZE
+		" report: %02x %02x %02x %02x"
+		" %02x %02x %02x %02x\n",
+		err, actual,
+		termdata->current_report[0], termdata->current_report[1],
+		termdata->current_report[2], termdata->current_report[3],
+		termdata->current_report[4], termdata->current_report[5],
+		termdata->current_report[6], termdata->current_report[7]);
+
+  if (grub_video_get_info (&mode_info))
+    return GRUB_TERM_NO_KEY;
+
+  if (quirk_swap_xy)
+    {
+      int t = x;
+      x = y;
+      y = t;
+    }
+
+  if (quirk_invert_x)
+    x = termdata->param->x.logical_max - x;
+  if (quirk_invert_y)
+    y = termdata->param->x.logical_max - y;
+
+  /* We are on a graphical terminal so convert the mouse or
+   * touchscreen values into screen coordinates. */
+  if (termdata->param->flags & FLAG_ABSOLUTE)
+    {
+      if (quirk_widescreen)
+        {
+          x = (x - termdata->param->x.logical_max / 2) * 5 / 4
+            + termdata->param->x.logical_max / 2;
+          if (x < 0)
+            x = 0;
+          if (x > termdata->param->x.logical_max)
+            x = termdata->param->x.logical_max;
+        }
+
+      globalx = x * mode_info.width / termdata->param->x.logical_max;
+      globaly = y * mode_info.height / termdata->param->y.logical_max;
+    }
+  else
+    {
+      globalx += x;
+      globaly += y;
+    }
+
+  if (globalx < 0)
+    globalx = 0;
+  if (globalx >= (int)mode_info.width)
+    globalx = mode_info.width;
+  if (globaly < 0)
+    globaly = 0;
+  if (globaly >= (int)mode_info.height)
+    globaly = mode_info.height;
+
+  grub_dprintf("usb_mouse", "screen %d %d, values %d %d, xy %d %d\n",
+               mode_info.width, mode_info.height, x, y,
+               globalx, globaly);
+
+  memset(&ev, 0, sizeof(ev));
+  ev.x = globalx;
+  ev.y = globaly;
+  ev.buttons = buttons;
+
+  return grub_mouse_call_hook(&ev);
+}
+
+static int
+grub_usb_mouse_getkeystatus (struct grub_term_input *term)
+{
+  (void)term;
+  return 0;
+}
+
+static int
+grub_usb_mouse_attach (grub_usb_device_t usbdev, int configno, int interfno)
+{
+  unsigned curnum;
+  struct grub_usb_mouse_data *data;
+  struct grub_usb_desc_endp *endp = NULL;
+  unsigned n;
+  int j;
+  struct grub_usb_configuration *config = &usbdev->config[configno];
+  struct grub_usb_interface *interf = &config->interf[interfno];
+  const struct grub_usb_mouse_param *param;
+
+  grub_dprintf ("usb_mouse",
+                "%04x:%04x 0x%x 0x%x 0x%x conf[%d] if[%d] 0x%x 0x%x\n",
+		usbdev->descdev.vendorid, usbdev->descdev.prodid,
+		usbdev->descdev.class, usbdev->descdev.subclass,
+                usbdev->descdev.protocol,
+                configno,
+                interfno, interf->descif->subclass, interf->descif->protocol);
+
+  /* Add quirks here: Example
+  if ((usbdev->descdev.vendorid == 0xXXXX) &&
+      (usbdev->descdev.prodid == 0xYYYY)
+    {
+      grub_dprintf("usb_mouse", "usb_mouse quirks: invert_y widescreen\n");
+      quirk_invert_y = 1;
+      quirk_invert_x = 0;
+      quirk_widescreen = 1;
+      quirk_swap_xy = 0;
+    }
+  */
+  for (curnum = 0; curnum < ARRAY_SIZE (grub_mice); curnum++)
+    if (!grub_mice[curnum].data)
+      break;
+
+  if (curnum == ARRAY_SIZE (grub_mice))
+    {
+      grub_dprintf ("usb_mouse", "too many mice already\n");
+      return 0;
+    }
+
+  if (usbdev->descdev.class != 0 ||
+      usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
+    {
+      grub_dprintf ("usb_mouse", "unknown hid device\n");
+      return 0;
+    }
+
+  param = NULL;
+  for (n = 0; n < ARRAY_SIZE(grub_usb_mouse_param_custom); n++) {
+    if (grub_usb_mouse_param_custom[n].vendorid == usbdev->descdev.vendorid &&
+        grub_usb_mouse_param_custom[n].prodid == usbdev->descdev.prodid) {
+      grub_dprintf ("usb_mouse", "hardcoded usb mouse found\n");
+      param = &grub_usb_mouse_param_custom[n];
+      break;
+    }
+  }
+
+  if (!param &&
+      (interf->descif->subclass == USB_HID_BOOT_SUBCLASS &&
+       interf->descif->protocol == USB_HID_USB_MOUSE_PROTOCOL))
+    {
+      grub_dprintf ("usb_mouse", "usb boot mouse found\n");
+      param = &grub_usb_mouse_param_boot;
+    }
+
+  if (!param)
+    {
+      grub_dprintf ("usb_mouse", "unknown hid device\n");
+      return 0;
+    }
+
+  for (j = 0; j < interf->descif->endpointcnt; j++)
+    {
+      endp = &interf->descendp[j];
+
+      if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
+	  == GRUB_USB_EP_INTERRUPT)
+	break;
+    }
+  if (j == interf->descif->endpointcnt)
+    {
+      grub_dprintf ("usb_mouse", "could not find interrupt endpoint\n");
+      return 0;
+    }
+
+  data = grub_malloc (sizeof (*data));
+  if (!data)
+    {
+      grub_print_error ();
+      return 0;
+    }
+
+  grub_dprintf ("usb_mouse", "%04x:%04x conf %d intf %d size %d flags 0x%x\n",
+		usbdev->descdev.vendorid, usbdev->descdev.prodid,
+                configno, interfno,
+                param->report_size,
+                param->flags);
+
+  data->usbdev = usbdev;
+  data->endp = endp;
+  data->param = param;
+
+  /* Configure device */
+  grub_usb_set_configuration (usbdev, configno + 1);
+
+  /* Place the device in the correct mode, boot or report.  */
+  grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
+  			USB_HID_SET_PROTOCOL,
+                        param->flags & FLAG_BOOT_DEVICE ? 0 : 1,
+                        interfno, 0, 0);
+
+  /* Reports every time an event occurs and not more often than that.  */
+  grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
+  			USB_HID_SET_IDLE, 0<<8, interfno, 0, 0);
+
+  grub_memcpy (&grub_mice[curnum], &grub_usb_mouse_term,
+	       sizeof (grub_mice[curnum]));
+  grub_mice[curnum].data = data;
+  usbdev->config[configno].interf[interfno].detach_hook
+    = grub_usb_mouse_detach;
+  grub_mice[curnum].name = grub_xasprintf ("usb_mouse%d", curnum);
+  if (!grub_mice[curnum].name)
+    {
+      grub_dprintf ("usb_mouse", "failed to make name for %d\n", curnum);
+      grub_print_error ();
+      return 0;
+    }
+
+  data->transfer = NULL;
+  data->dead = 0;
+
+  grub_term_register_input_active ("usb_mouse", &grub_mice[curnum]);
+
+  return 1;
+}
+
+static struct grub_usb_attach_desc attach_hook =
+  {
+    .class = GRUB_USB_CLASS_HID,
+    .hook = grub_usb_mouse_attach
+  };
+
+GRUB_MOD_INIT(usb_mouse)
+{
+  grub_dprintf ("usb_mouse", "%s\n", __func__);
+  grub_usb_register_attach_hook_class (&attach_hook);
+}
+
+GRUB_MOD_FINI(usb_mouse)
+{
+  unsigned i;
+
+  for (i = 0; i < ARRAY_SIZE (grub_mice); i++) {
+    if (grub_mice[i].data)
+      {
+	struct grub_usb_mouse_data *data = grub_mice[i].data;
+        
+	if (!data)
+	  continue;
+        
+	grub_term_unregister_input (&grub_mice[i]);
+	grub_free ((char *) grub_mice[i].name);
+	grub_mice[i].name = NULL;
+	grub_free (grub_mice[i].data);
+	grub_mice[i].data = 0;
+      }
+  }
+  grub_usb_unregister_attach_hook_class (&attach_hook);
+}
diff -urN grub.orig/include/grub/mouse.h grub/include/grub/mouse.h
--- grub.orig/include/grub/mouse.h	1970-01-01 01:00:00.000000000 +0100
+++ grub/include/grub/mouse.h	2013-10-02 09:40:30.292316383 +0200
@@ -0,0 +1,63 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007,2008,2009,2010  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* A simple framework for connecting mouse device drivers to consumers
+ * that want to use the mouse position for something.
+ *
+ * A mouse driver calls grub_mouse_call_hook(x, y, buttons) whenever
+ * it has a new postion/button statae to report.
+ *
+ * A consumer registers a mouse hook with grub_mouse_add_hook which
+ * will be called whenever grub_mouse_call_hook is called.
+ */
+
+#ifndef GRUB_MOUSE_HEADER
+#define GRUB_MOUSE_HEADER 1
+
+#include <grub/err.h>
+
+struct grub_mouse_event
+{
+  unsigned x;
+  unsigned y;
+  unsigned buttons;
+};
+
+/* A mouse callback hook function
+ *
+ * Since this is all called from the terminal getkey function, the
+ * hook function returns a GRUB_TERM key value.  If the hook returns
+ * GRUB_TERM_NO_KEY, the next hook will be called.  If the hook
+ * returns something else, no more hooks will be called and the return
+ * value will become the return value from getkey.  This can for
+ * example be used for an on screen keyboard.  */
+typedef int (*grub_mouse_callback_t)(struct grub_mouse_event *ev, void *priv);
+
+struct grub_mouse_hook {
+  struct grub_mouse_hook *next;
+  struct grub_mouse_hook *prev;
+  grub_mouse_callback_t callback;
+  void *priv;
+};
+
+int grub_mouse_call_hook(struct grub_mouse_event *ev);
+
+grub_err_t grub_mouse_add_hook(grub_mouse_callback_t callback, void *priv);
+grub_err_t grub_mouse_remove_hook(grub_mouse_callback_t callback, void *priv);
+
+#endif /* ! GRUB_MOUSE_HEADER */
