[1982] 2009-02-08 Marco Gerards <[email protected]>

Robert Millan <[email protected]>
Newsgroups gmane.comp.boot-loaders.grub.cvs
Message-ID <[email protected]>
Revision: 1982
          http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=1982
Author:   robertmh
Date:     2009-02-08 17:58:32 +0000 (Sun, 08 Feb 2009)

Log Message:
-----------
2009-02-08  Marco Gerards  <[email protected]>

        * Makefile.in (enable_grub_emu_usb): New variable.
        * conf/i386-pc.rmk (grub_emu_SOURCES): Add `disk/scsi.c'.
        (grub_emu_SOURCES) [grub_emu_SOURCES]: Add `disk/usbms.c',
        `util/usb.c', `bus/usb/usb.c' and `commands/usbtest.c'.
        (grub_emu_LDFLAGS): Add `$(LIBUSB)'.
        (pkglib_MODULES): Add `usb.mod', `uhci.mod', `ohci.mod',
        `usbtest.mod' and `usbms.mod'.
        (usb_mod_SOURCES, usb_mod_CFLAGS, usb_mod_LDFLAGS)
        (usbtest_mod_SOURCES, usbtest_mod_CFLAGS, usbtest_mod_LDFLAGS)
        (uhci_mod_SOURCES, uhci_mod_CFLAGS, uhci_mod_LDFLAGS,
        (ohci_mod_SOURCES, ohci_mod_CFLAGS, ohci_mod_LDFLAGS)
        (usbms_mod_SOURCES, usbms_mod_CFLAGS, usbms_mod_LDFLAGS): New
        variables.

        * disk/usbms.c: New file.

        * include/grub/usb.h: Likewise.

        * include/grub/usbtrans.h: Likewise.

        * include/grub/usbdesc.h: Likewise.

        * bus/usb/usbtrans.c: Likewise.

        * bus/usb/ohci.c: Likewise.

        * bus/usb/uhci.c: Likewise.

        * bus/usb/usbhub.c: Likewise.

        * bus/usb/usb.c: Likewise.

        * commands/usbtest.c: Likewise.

        * util/usb.c: Likewise.

        * include/grub/err.h (grub_err_t): Add `GRUB_ERR_IO'.

        * configure.ac: Test for libusb presence.

        * util/grub-emu.c (main) [HAVE_LIBUSB_H]: Call `grub_libusb_init'.

Modified Paths:
--------------
    trunk/grub2/ChangeLog
    trunk/grub2/DISTLIST
    trunk/grub2/Makefile.in
    trunk/grub2/conf/i386-pc.mk
    trunk/grub2/conf/i386-pc.rmk
    trunk/grub2/config.h.in
    trunk/grub2/configure
    trunk/grub2/configure.ac
    trunk/grub2/include/grub/err.h
    trunk/grub2/util/grub-emu.c

Added Paths:
-----------
    trunk/grub2/bus/usb/
    trunk/grub2/bus/usb/ohci.c
    trunk/grub2/bus/usb/uhci.c
    trunk/grub2/bus/usb/usb.c
    trunk/grub2/bus/usb/usbhub.c
    trunk/grub2/bus/usb/usbtrans.c
    trunk/grub2/commands/usbtest.c
    trunk/grub2/disk/usbms.c
    trunk/grub2/include/grub/usb.h
    trunk/grub2/include/grub/usbdesc.h
    trunk/grub2/include/grub/usbtrans.h
    trunk/grub2/util/usb.c

Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/ChangeLog	2009-02-08 17:58:32 UTC (rev 1982)
@@ -1,3 +1,47 @@
+2009-02-08  Marco Gerards  <[email protected]>
+
+	* Makefile.in (enable_grub_emu_usb): New variable.
+	* conf/i386-pc.rmk (grub_emu_SOURCES): Add `disk/scsi.c'.
+	(grub_emu_SOURCES) [grub_emu_SOURCES]: Add `disk/usbms.c',
+	`util/usb.c', `bus/usb/usb.c' and `commands/usbtest.c'.
+	(grub_emu_LDFLAGS): Add `$(LIBUSB)'.
+	(pkglib_MODULES): Add `usb.mod', `uhci.mod', `ohci.mod',
+	`usbtest.mod' and `usbms.mod'.
+	(usb_mod_SOURCES, usb_mod_CFLAGS, usb_mod_LDFLAGS)
+	(usbtest_mod_SOURCES, usbtest_mod_CFLAGS, usbtest_mod_LDFLAGS)
+	(uhci_mod_SOURCES, uhci_mod_CFLAGS, uhci_mod_LDFLAGS,
+	(ohci_mod_SOURCES, ohci_mod_CFLAGS, ohci_mod_LDFLAGS)
+	(usbms_mod_SOURCES, usbms_mod_CFLAGS, usbms_mod_LDFLAGS): New
+	variables.
+
+	* disk/usbms.c: New file.
+
+	* include/grub/usb.h: Likewise.
+
+	* include/grub/usbtrans.h: Likewise.
+
+	* include/grub/usbdesc.h: Likewise.
+
+	* bus/usb/usbtrans.c: Likewise.
+
+	* bus/usb/ohci.c: Likewise.
+
+	* bus/usb/uhci.c: Likewise.
+
+	* bus/usb/usbhub.c: Likewise.
+
+	* bus/usb/usb.c: Likewise.
+
+	* commands/usbtest.c: Likewise.
+
+	* util/usb.c: Likewise.
+	
+	* include/grub/err.h (grub_err_t): Add `GRUB_ERR_IO'.
+
+	* configure.ac: Test for libusb presence.
+	
+	* util/grub-emu.c (main) [HAVE_LIBUSB_H]: Call `grub_libusb_init'.
+
 2009-02-08  Vesa Jääskeläinen  <[email protected]>
 
 	* kern/mm.c: Add more comments.

Modified: trunk/grub2/DISTLIST
===================================================================
--- trunk/grub2/DISTLIST	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/DISTLIST	2009-02-08 17:58:32 UTC (rev 1982)
@@ -35,6 +35,11 @@
 boot/i386/pc/lnxboot.S
 boot/i386/pc/pxeboot.S
 bus/pci.c
+bus/usb/ohci.c
+bus/usb/uhci.c
+bus/usb/usb.c
+bus/usb/usbhub.c
+bus/usb/usbtrans.c
 commands/blocklist.c
 commands/boot.c
 commands/cat.c
@@ -56,6 +61,7 @@
 commands/sleep.c
 commands/terminal.c
 commands/test.c
+commands/usbtest.c
 commands/videotest.c
 commands/i386/cpuid.c
 commands/i386/pc/halt.c
@@ -95,6 +101,7 @@
 disk/raid5_recover.c
 disk/raid6_recover.c
 disk/scsi.c
+disk/usbms.c
 disk/efi/efidisk.c
 disk/i386/pc/biosdisk.c
 disk/ieee1275/nand.c
@@ -179,6 +186,9 @@
 include/grub/time.h
 include/grub/tparm.h
 include/grub/types.h
+include/grub/usb.h
+include/grub/usbdesc.h
+include/grub/usbtrans.h
 include/grub/video.h
 include/grub/efi/api.h
 include/grub/efi/chainloader.h
@@ -438,6 +448,7 @@
 util/raid.c
 util/resolve.c
 util/update-grub_lib.in
+util/usb.c
 util/elf/grub-mkimage.c
 util/grub.d/00_header.in
 util/grub.d/10_freebsd.in

Modified: trunk/grub2/Makefile.in
===================================================================
--- trunk/grub2/Makefile.in	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/Makefile.in	2009-02-08 17:58:32 UTC (rev 1982)
@@ -92,6 +92,7 @@
 
 # Options.
 enable_grub_emu = @enable_grub_emu@
+enable_grub_emu_usb = @enable_grub_emu_usb@
 enable_grub_fstest = @enable_grub_fstest@
 enable_grub_pe2elf = @enable_grub_pe2elf@
 enable_lzo = @enable_lzo@

Added: trunk/grub2/bus/usb/ohci.c
===================================================================
--- trunk/grub2/bus/usb/ohci.c	                        (rev 0)
+++ trunk/grub2/bus/usb/ohci.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,608 @@
+/* ohci.c - OHCI Support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/usb.h>
+#include <grub/usbtrans.h>
+#include <grub/misc.h>
+#include <grub/pci.h>
+#include <grub/cpu/pci.h>
+#include <grub/i386/io.h>
+#include <grub/time.h>
+
+struct grub_ohci_hcca
+{
+  /* Pointers to Interrupt Endpoint Descriptors.  Not used by
+     GRUB.  */
+  grub_uint32_t inttable[32];
+
+  /* Current frame number.  */
+  grub_uint16_t framenumber;
+
+  grub_uint16_t pad;
+
+  /* List of completed TDs.  */
+  grub_uint32_t donehead;
+
+  grub_uint8_t reserved[116];
+} __attribute__((packed));
+
+/* OHCI Endpoint Descriptor.  */
+struct grub_ohci_ed
+{
+  grub_uint32_t target;
+  grub_uint32_t td_tail;
+  grub_uint32_t td_head;
+  grub_uint32_t next_ed;
+} __attribute__((packed));
+
+struct grub_ohci_td
+{
+  /* Information used to construct the TOKEN packet.  */
+  grub_uint32_t token;
+
+  grub_uint32_t buffer;
+  grub_uint32_t next_td;
+  grub_uint32_t buffer_end;
+} __attribute__((packed));
+
+typedef struct grub_ohci_td *grub_ohci_td_t;
+typedef struct grub_ohci_ed *grub_ohci_ed_t;
+
+struct grub_ohci
+{
+  volatile grub_uint32_t *iobase;
+  volatile struct grub_ohci_hcca *hcca;
+  struct grub_ohci *next;
+};
+
+static struct grub_ohci *ohci;
+
+typedef enum
+{
+  GRUB_OHCI_REG_REVISION = 0x00,
+  GRUB_OHCI_REG_CONTROL,
+  GRUB_OHCI_REG_CMDSTATUS,
+  GRUB_OHCI_REG_INTSTATUS,
+  GRUB_OHCI_REG_INTENA,
+  GRUB_OHCI_REG_INTDIS,
+  GRUB_OHCI_REG_HCCA,
+  GRUB_OHCI_REG_PERIODIC,
+  GRUB_OHCI_REG_CONTROLHEAD,
+  GRUB_OHCI_REG_CONTROLCURR,
+  GRUB_OHCI_REG_BULKHEAD,
+  GRUB_OHCI_REG_BULKCURR,
+  GRUB_OHCI_REG_DONEHEAD,
+  GRUB_OHCI_REG_FRAME_INTERVAL,
+  GRUB_OHCI_REG_RHUBA = 18,
+  GRUB_OHCI_REG_RHUBPORT = 21
+} grub_ohci_reg_t;
+
+static grub_uint32_t
+grub_ohci_readreg32 (struct grub_ohci *o, grub_ohci_reg_t reg)
+{
+  return grub_le_to_cpu32 (*(o->iobase + reg));
+}
+
+static void
+grub_ohci_writereg32 (struct grub_ohci *o,
+		      grub_ohci_reg_t reg, grub_uint32_t val)
+{
+  *(o->iobase + reg) = grub_cpu_to_le32 (val);
+}
+
+
+
+/* Iterate over all PCI devices.  Determine if a device is an OHCI
+   controller.  If this is the case, initialize it.  */
+static int grub_ohci_pci_iter (int bus, int device, int func,
+			       grub_pci_id_t pciid __attribute__((unused)))
+{
+  grub_uint32_t class;
+  grub_uint32_t subclass;
+  int interf;
+  grub_uint32_t base;
+  grub_pci_address_t addr;
+  struct grub_ohci *o;
+  grub_uint32_t revision;
+  grub_uint32_t frame_interval;
+
+  addr = grub_pci_make_address (bus, device, func, 2);
+  class = grub_pci_read (addr);
+  addr = grub_pci_make_address (bus, device, func, 2);
+  class = grub_pci_read (addr);
+
+  interf = class & 0xFF;
+  subclass = (class >> 16) & 0xFF;
+  class >>= 24;
+
+  /* If this is not an OHCI controller, just return.  */
+  if (class != 0x0c || subclass != 0x03)
+    return 0;
+
+  /* Determine IO base address.  */
+  addr = grub_pci_make_address (bus, device, func, 4);
+  base = grub_pci_read (addr);
+
+#if 0
+  /* Stop if there is no IO space base address defined.  */
+  if (! (base & 1))
+    return 0;
+#endif
+
+  /* Allocate memory for the controller and register it.  */
+  o = grub_malloc (sizeof (*o));
+  if (! o)
+    return 1;
+
+  /* Link in the OHCI.  */
+  o->next = ohci;
+  ohci = o;
+  o->iobase = (grub_uint32_t *) base;
+
+  /* Reserve memory for the HCCA.  */
+  o->hcca = (struct grub_ohci_hcca *) grub_memalign (256, 256);
+
+  /* Check if the OHCI revision is actually 1.0 as supported.  */
+  revision = grub_ohci_readreg32 (o, GRUB_OHCI_REG_REVISION);
+  grub_dprintf ("ohci", "OHCI revision=0x%02x\n", revision & 0xFF);
+  if ((revision & 0xFF) != 0x10)
+    goto fail;
+
+  /* Backup the frame interval register.  */
+  frame_interval = grub_ohci_readreg32 (o, GRUB_OHCI_REG_FRAME_INTERVAL);
+
+  /* Suspend the OHCI by issuing a reset.  */
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic.
+							  */
+  grub_millisleep (1);
+  grub_dprintf ("ohci", "OHCI reset\n");
+
+  /* Restore the frame interval register.  */
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_FRAME_INTERVAL, frame_interval);
+
+  /* Setup the HCCA.  */
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, (grub_uint32_t) o->hcca);
+  grub_dprintf ("ohci", "OHCI HCCA\n");
+ 
+  /* Enable the OHCI.  */
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL,
+			(2 << 6));
+  grub_dprintf ("ohci", "OHCI enable: 0x%02x\n",
+		(grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) >> 6) & 3);
+ 
+  return 0;
+
+ fail:
+  if (o)
+    grub_free ((void *) o->hcca);
+  grub_free (o);
+
+  return 1;
+}
+
+
+static void
+grub_ohci_inithw (void)
+{
+  grub_pci_iterate (grub_ohci_pci_iter);
+}
+
+
+
+static int
+grub_ohci_iterate (int (*hook) (grub_usb_controller_t dev))
+{
+  struct grub_ohci *o;
+  struct grub_usb_controller dev;
+
+  for (o = ohci; o; o = o->next)
+    {
+      dev.data = o;
+      if (hook (&dev))
+	return 1;
+    }
+
+  return 0;
+}
+
+static void
+grub_ohci_transaction (grub_ohci_td_t td, 
+		       grub_transfer_type_t type, unsigned int toggle,
+		       grub_size_t size, char *data)
+{
+  grub_uint32_t token;
+  grub_uint32_t buffer;
+  grub_uint32_t buffer_end;
+
+ grub_dprintf ("ohci", "OHCI transaction td=0x%02x type=%d, toggle=%d, size=%d\n",
+	       td, type, toggle, size);
+ 
+  switch (type)
+    {
+    case GRUB_USB_TRANSFER_TYPE_SETUP:
+      token = 0 << 19;
+      break;
+    case GRUB_USB_TRANSFER_TYPE_IN:
+      token = 2 << 19;
+      break;
+    case GRUB_USB_TRANSFER_TYPE_OUT:
+      token = 1 << 19;
+      break;
+    default:
+      token = 0;
+      break;
+    }
+
+  /* Generate no interrupts.  */
+  token |= 7 << 21;
+
+  /* Set the token.  */
+  token |= toggle << 24;
+  token |= 1 << 25;
+
+  buffer = (grub_uint32_t) data;
+  buffer_end = buffer + size - 1;
+
+  td->token = grub_cpu_to_le32 (token);
+  td->buffer = grub_cpu_to_le32 (buffer);
+  td->next_td = 0;
+  td->buffer_end = grub_cpu_to_le32 (buffer_end);
+}
+
+static grub_usb_err_t
+grub_ohci_transfer (grub_usb_controller_t dev,
+		    grub_usb_transfer_t transfer)
+{
+  struct grub_ohci *o = (struct grub_ohci *) dev->data;
+  grub_ohci_ed_t ed;
+  grub_ohci_td_t td_list;
+  grub_uint32_t target;
+  grub_uint32_t td_tail;
+  grub_uint32_t td_head;
+  grub_uint32_t status;
+  grub_uint32_t control;
+  grub_usb_err_t err;
+  int i;
+
+  /* Allocate an Endpoint Descriptor.  */
+  ed = grub_memalign (16, sizeof (*ed));
+  if (! ed)
+    return GRUB_USB_ERR_INTERNAL;
+
+  td_list = grub_memalign (16, sizeof (*td_list) * (transfer->transcnt + 1));
+  if (! td_list)
+    {
+      grub_free ((void *) ed);
+      return GRUB_USB_ERR_INTERNAL;
+    }
+
+  grub_dprintf ("ohci", "alloc=0x%08x\n", td_list);
+
+  /* Setup all Transfer Descriptors.  */
+  for (i = 0; i < transfer->transcnt; i++)
+    {
+      grub_usb_transaction_t tr = &transfer->transactions[i];
+
+      grub_ohci_transaction (&td_list[i], tr->pid, tr->toggle,
+			     tr->size, tr->data); 
+
+      td_list[i].next_td = grub_cpu_to_le32 (&td_list[i + 1]);
+    }
+
+  /* Setup the Endpoint Descriptor.  */
+
+  /* Set the device address.  */
+  target = transfer->devaddr;
+
+  /* Set the endpoint.  */
+  target |= transfer->endpoint << 7;
+
+  /* Set the device speed.  */
+  target |= (transfer->dev->speed == GRUB_USB_SPEED_LOW) << 13;
+
+  /* Set the maximum packet size.  */
+  target |= transfer->max << 16;
+
+  td_head = (grub_uint32_t) td_list;
+
+  td_tail = (grub_uint32_t) &td_list[transfer->transcnt];
+
+  ed->target = grub_cpu_to_le32 (target);
+  ed->td_head = grub_cpu_to_le32 (td_head);
+  ed->td_tail = grub_cpu_to_le32 (td_tail);
+  ed->next_ed = grub_cpu_to_le32 (0);
+
+  grub_dprintf ("ohci", "program OHCI\n");
+
+  /* Program the OHCI to actually transfer.  */
+  switch (transfer->type)
+    {
+    case GRUB_USB_TRANSACTION_TYPE_BULK:
+      {
+	grub_dprintf ("ohci", "add to bulk list\n");
+
+	status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
+	control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
+
+	/* Disable the Control and Bulk lists.  */
+	control &= ~(3 << 4);
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
+
+	/* Clear BulkListFilled.  */
+	status &= ~(1 << 2);
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
+
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, (grub_uint32_t) ed);
+
+	/* Enable the Bulk list.  */
+	control |= 1 << 5;
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
+
+	/* Set BulkListFilled.  */
+	status |= 1 << 2;
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
+
+	break;
+      }
+
+    case GRUB_USB_TRANSACTION_TYPE_CONTROL:
+      {
+	grub_dprintf ("ohci", "add to control list\n");
+	status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
+	control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
+
+	/* Disable the Control and Bulk lists.  */
+	control &= ~(3 << 4);
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
+
+	/* Clear ControlListFilled.  */
+	status &= ~(1 << 1);
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
+
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD,
+			      (grub_uint32_t) ed);
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD+1,
+			      (grub_uint32_t) ed);
+
+	/* Enable the Control list.  */
+	control |= 1 << 4;
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
+
+	/* Set ControlListFilled.  */
+	status |= 1 << 1;
+	grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
+	break;
+      }
+    }
+
+  grub_dprintf ("ohci", "wait for completion\n");
+  grub_dprintf ("ohci", "control=0x%02x status=0x%02x\n",
+		grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL),
+		grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS));
+
+  /* Wait until the transfer is completed or STALLs.  */
+  while ((ed->td_head & ~0xf) != (ed->td_tail & ~0xf))
+    {
+      grub_cpu_idle ();
+
+      grub_dprintf ("ohci", "head=0x%02x tail=0x%02x\n", ed->td_head, ed->td_tail);
+
+      /* Detected a STALL.  */
+      if (ed->td_head & 1)
+	break;
+    }
+
+  grub_dprintf ("ohci", "complete\n");
+
+/*   if (ed->td_head & 1) */
+/*     err = GRUB_USB_ERR_STALL; */
+/*   else if (ed->td */
+
+
+  if (ed->td_head & 1)
+    {
+      grub_uint8_t errcode;
+      grub_ohci_td_t tderr;
+
+      tderr = (grub_ohci_td_t) grub_ohci_readreg32 (o,
+						    GRUB_OHCI_REG_DONEHEAD);
+      errcode = tderr->token >> 28;
+
+      switch (errcode)
+	{
+	case 0:
+	  /* XXX: Should not happen!  */
+	  grub_error (GRUB_ERR_IO, "OHCI without reporting the reason");
+	  err = GRUB_USB_ERR_INTERNAL;
+	  break;
+
+	case 1:
+	  /* XXX: CRC error.  */
+	  err = GRUB_USB_ERR_TIMEOUT;
+	  break;
+
+	case 2:
+	  err = GRUB_USB_ERR_BITSTUFF;
+	  break;
+
+	case 3:
+	  /* XXX: Data Toggle error.  */
+	  err = GRUB_USB_ERR_DATA;
+	  break;
+
+	case 4:
+	  err = GRUB_USB_ERR_STALL;
+	  break;
+
+	case 5:
+	  /* XXX: Not responding.  */
+	  err = GRUB_USB_ERR_TIMEOUT;
+	  break;
+
+	case 6:
+	  /* XXX: PID Check bits failed.  */
+	  err = GRUB_USB_ERR_BABBLE;
+	  break;
+
+	case 7:
+	  /* XXX: PID unexpected failed.  */
+	  err = GRUB_USB_ERR_BABBLE;
+	  break;
+
+	case 8:
+	  /* XXX: Data overrun error.  */
+	  err = GRUB_USB_ERR_DATA;
+	  break;
+
+	case 9:
+	  /* XXX: Data underrun error.  */
+	  err = GRUB_USB_ERR_DATA;
+	  break;
+
+	case 10:
+	  /* XXX: Reserved.  */
+	  err = GRUB_USB_ERR_NAK;
+	  break;
+
+	case 11:
+	  /* XXX: Reserved.  */
+	  err = GRUB_USB_ERR_NAK;
+	  break;
+
+	case 12:
+	  /* XXX: Buffer overrun.  */
+	  err = GRUB_USB_ERR_DATA;
+	  break;
+
+	case 13:
+	  /* XXX: Buffer underrun.  */
+	  err = GRUB_USB_ERR_DATA;
+	  break;
+
+	default:
+	  err = GRUB_USB_ERR_NAK;
+	  break;
+	}
+    }
+  else
+    err = GRUB_USB_ERR_NONE;
+
+  /* Disable the Control and Bulk lists.  */
+  control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
+  control &= ~(3 << 4);
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
+
+  /* Clear BulkListFilled and ControlListFilled.  */
+  status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
+  status &= ~((1 << 2) | (1 << 3));
+  grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
+
+  /* XXX */
+  grub_free (td_list);
+  grub_free (ed);
+
+  return err;
+}
+
+static grub_err_t
+grub_ohci_portstatus (grub_usb_controller_t dev,
+		      unsigned int port, unsigned int enable)
+{
+   struct grub_ohci *o = (struct grub_ohci *) dev->data;
+   grub_uint32_t status;
+
+   /* Reset the port.  */
+   status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
+   status |= (1 << 4); /* XXX: Magic.  */
+   grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
+   grub_millisleep (100);
+
+   /* End the reset signaling.  */
+   status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
+   status |= (1 << 20); /* XXX: Magic.  */
+   grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
+   grub_millisleep (10);
+
+   /* Enable the port.  */
+   status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
+   status |= (enable << 1); /* XXX: Magic.  */
+   grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
+
+   status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
+   grub_dprintf ("ohci", "portstatus=0x%02x\n", status);
+
+   return GRUB_ERR_NONE;
+}
+
+static grub_usb_speed_t
+grub_ohci_detect_dev (grub_usb_controller_t dev, int port)
+{
+   struct grub_ohci *o = (struct grub_ohci *) dev->data;
+   grub_uint32_t status;
+
+   status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
+
+   grub_dprintf ("ohci", "detect_dev status=0x%02x\n", status);
+
+   if (! (status & 1))
+     return GRUB_USB_SPEED_NONE;
+   else if (status & (1 << 9))
+     return GRUB_USB_SPEED_LOW;
+   else
+     return GRUB_USB_SPEED_FULL;
+}
+
+static int
+grub_ohci_hubports (grub_usb_controller_t dev)
+{
+  struct grub_ohci *o = (struct grub_ohci *) dev->data;
+  grub_uint32_t portinfo;
+
+  portinfo = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA);
+
+  grub_dprintf ("ohci", "root hub ports=%d\n", portinfo & 0xFF);
+
+  /* The root hub has exactly two ports.  */
+  return portinfo & 0xFF;
+}
+
+
+
+static struct grub_usb_controller_dev usb_controller =
+{
+  .name = "ohci",
+  .iterate = grub_ohci_iterate,
+  .transfer = grub_ohci_transfer,
+  .hubports = grub_ohci_hubports,
+  .portstatus = grub_ohci_portstatus,
+  .detect_dev = grub_ohci_detect_dev
+};
+
+GRUB_MOD_INIT(ohci)
+{
+  grub_ohci_inithw ();
+  grub_usb_controller_dev_register (&usb_controller);
+}
+
+GRUB_MOD_FINI(ohci)
+{
+  grub_usb_controller_dev_unregister (&usb_controller);  
+}

Added: trunk/grub2/bus/usb/uhci.c
===================================================================
--- trunk/grub2/bus/usb/uhci.c	                        (rev 0)
+++ trunk/grub2/bus/usb/uhci.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,675 @@
+/* uhci.c - UHCI Support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/usb.h>
+#include <grub/usbtrans.h>
+#include <grub/pci.h>
+#include <grub/cpu/pci.h>
+#include <grub/i386/io.h>
+#include <grub/time.h>
+
+#define GRUB_UHCI_IOMASK	(0x7FF << 5)
+
+typedef enum
+  {
+    GRUB_UHCI_REG_USBCMD = 0x00,
+    GRUB_UHCI_REG_FLBASEADD = 0x08,
+    GRUB_UHCI_REG_PORTSC1 = 0x10,
+    GRUB_UHCI_REG_PORTSC2 = 0x12
+  } grub_uhci_reg_t;
+
+#define GRUB_UHCI_LINK_TERMINATE	1
+#define GRUB_UHCI_LINK_QUEUE_HEAD	2
+
+
+/* UHCI Queue Head.  */
+struct grub_uhci_qh
+{
+  /* Queue head link pointer which points to the next queue head.  */
+  grub_uint32_t linkptr;
+
+  /* Queue element link pointer which points to the first data object
+     within the queue.  */
+  grub_uint32_t elinkptr;
+
+  /* Queue heads are aligned on 16 bytes, pad so a queue head is 16
+     bytes so we can store many in a 4K page.  */
+  grub_uint8_t pad[8];
+} __attribute__ ((packed));
+
+/* UHCI Tranfer Descriptor.  */
+struct grub_uhci_td
+{
+  /* Pointer to the next TD in the list.  */
+  grub_uint32_t linkptr;
+
+  /* Control and status bits.  */
+  grub_uint32_t ctrl_status;
+
+  /* All information required to transfer the Token packet.  */
+  grub_uint32_t token;
+
+  /* A pointer to the data buffer, UHCI requires this pointer to be 32
+     bits.  */
+  grub_uint32_t buffer;
+
+  /* Another linkptr that is not overwritten by the Host Controller.
+     This is GRUB specific.  */
+  grub_uint32_t linkptr2;
+
+  /* 3 additional 32 bits words reserved for the Host Controller Driver.  */
+  grub_uint32_t data[3];
+} __attribute__ ((packed));
+
+typedef volatile struct grub_uhci_td *grub_uhci_td_t;
+typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
+
+struct grub_uhci
+{
+  int iobase;
+  grub_uint32_t *framelist;
+
+  /* 256 Queue Heads.  */
+  grub_uhci_qh_t qh;
+
+  /* 256 Transfer Descriptors.  */
+  grub_uhci_td_t td;
+
+  /* Free Transfer Descriptors.  */
+  grub_uhci_td_t tdfree;
+
+  struct grub_uhci *next;
+};
+
+static struct grub_uhci *uhci;
+
+static grub_uint16_t
+grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg)
+{
+  return grub_inw (u->iobase + reg);
+}
+
+#if 0
+static grub_uint32_t
+grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg)
+{
+  return grub_inl (u->iobase + reg);
+}
+#endif
+
+static void
+grub_uhci_writereg16 (struct grub_uhci *u,
+		      grub_uhci_reg_t reg, grub_uint16_t val)
+{
+  grub_outw (val, u->iobase + reg);
+}
+
+static void
+grub_uhci_writereg32 (struct grub_uhci *u,
+		    grub_uhci_reg_t reg, grub_uint32_t val)
+{
+  grub_outl (val, u->iobase + reg);
+}
+
+static grub_err_t
+grub_uhci_portstatus (grub_usb_controller_t dev,
+		      unsigned int port, unsigned int enable);
+
+
+/* Iterate over all PCI devices.  Determine if a device is an UHCI
+   controller.  If this is the case, initialize it.  */
+static int grub_uhci_pci_iter (int bus, int device, int func,
+			       grub_pci_id_t pciid __attribute__((unused)))
+{
+  grub_uint32_t class;
+  grub_uint32_t subclass;
+  grub_uint32_t base;
+  grub_uint32_t fp;
+  grub_pci_address_t addr;
+  struct grub_uhci *u;
+  int i;
+
+  addr = grub_pci_make_address (bus, device, func, 2);
+  class = grub_pci_read (addr);
+  addr = grub_pci_make_address (bus, device, func, 2);
+  class = grub_pci_read (addr);
+
+  subclass = (class >> 16) & 0xFF;
+  class >>= 24;
+
+  /* If this is not an UHCI controller, just return.  */
+  if (class != 0x0c || subclass != 0x03)
+    return 0;
+
+  /* Determine IO base address.  */
+  addr = grub_pci_make_address (bus, device, func, 8);
+  base = grub_pci_read (addr);
+  /* Stop if there is no IO space base address defined.  */
+  if (! (base & 1))
+    return 0;
+
+  /* Allocate memory for the controller and register it.  */
+  u = grub_malloc (sizeof (*u));
+  if (! u)
+    return 1;
+
+  u->next = uhci;
+  uhci = u;
+  u->iobase = base & GRUB_UHCI_IOMASK;
+  u->framelist = 0;
+  u->qh = 0;
+  u->td = 0;
+  grub_dprintf ("uhci", "class=0x%02x 0x%02x base=0x%x\n",
+		class, subclass, u->iobase);
+
+  /* Reserve a page for the frame list.  */
+  u->framelist = grub_memalign (4096, 4096);
+  if (! u->framelist)
+    goto fail;
+
+  /* The framelist pointer of UHCI is only 32 bits, make sure this
+     code works on on 64 bits architectures.  */
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+  if ((grub_uint64_t) u->framelist >> 32)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY,
+		  "allocated frame list memory not <4GB");
+      goto fail;
+    }
+#endif
+
+  /* The QH pointer of UHCI is only 32 bits, make sure this
+     code works on on 64 bits architectures.  */
+  u->qh = (grub_uhci_qh_t) grub_memalign (4096, 4096);
+  if (! u->qh)
+    goto fail;
+
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+  if ((grub_uint64_t) u->qh >> 32)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB");
+      goto fail;
+    }
+#endif
+
+  /* The TD pointer of UHCI is only 32 bits, make sure this
+     code works on on 64 bits architectures.  */
+  u->td = (grub_uhci_td_t) grub_memalign (4096, 4096*2);
+  if (! u->td)
+    goto fail;
+
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+  if ((grub_uint64_t) u->td >> 32)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB");
+      goto fail;
+    }
+#endif
+
+  /* Link all Transfer Descriptors in a list of available Transfer
+     Descriptors.  */
+  for (i = 0; i < 256; i++)
+    u->td[i].linkptr = (grub_uint32_t) &u->td[i + 1];
+  u->td[255 - 1].linkptr = 0;
+  u->tdfree = u->td;
+
+  /* Make sure UHCI is disabled!  */
+  grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
+
+  /* Setup the frame list pointers.  Since no isochronous transfers
+     are and will be supported, they all point to the (same!) queue
+     head.  */
+  fp = (grub_uint32_t) u->qh & (~15);
+  /* Mark this as a queue head.  */
+  fp |= 2;
+  for (i = 0; i < 1024; i++)
+    u->framelist[i] = fp;
+  /* Program the framelist address into the UHCI controller.  */
+  grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD,
+			(grub_uint32_t) u->framelist);
+
+  /* Make the Queue Heads point to eachother.  */
+  for (i = 0; i < 256; i++)
+    {
+      /* Point to the next QH.  */
+      u->qh[i].linkptr = (grub_uint32_t) (&u->qh[i + 1]) & (~15);
+
+      /* This is a QH.  */
+      u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
+
+      /* For the moment, do not point to a Transfer Descriptor.  These
+	 are set at transfer time, so just terminate it.  */
+      u->qh[i].elinkptr = 1;
+    }
+
+  /* The last Queue Head should terminate.  256 are too many QHs so
+     just use 50.  */
+  u->qh[50 - 1].linkptr = 1;
+
+  /* Enable UHCI again.  */
+  grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7));
+
+  /* UHCI is initialized and ready for transfers.  */
+  grub_dprintf ("uhci", "UHCI initialized\n");
+
+
+#if 0
+  {
+    int i;
+    for (i = 0; i < 10; i++)
+      {
+	grub_uint16_t frnum;
+
+	frnum = grub_uhci_readreg16 (u, 6);
+	grub_dprintf ("uhci", "Framenum=%d\n", frnum);
+	grub_millisleep (100);
+      }
+  }
+#endif
+
+  return 0;
+
+ fail:
+  if (u)
+    {
+      grub_free ((void *) u->qh);
+      grub_free (u->framelist);
+    }
+  grub_free (u);
+
+  return 1;
+}
+
+static void
+grub_uhci_inithw (void)
+{
+  grub_pci_iterate (grub_uhci_pci_iter);
+}
+
+static grub_uhci_td_t
+grub_alloc_td (struct grub_uhci *u)
+{
+  grub_uhci_td_t ret;
+
+  /* Check if there is a Transfer Descriptor available.  */
+  if (! u->tdfree)
+    return NULL;
+
+  ret = u->tdfree;
+  u->tdfree = (grub_uhci_td_t) u->tdfree->linkptr;
+
+  return ret;
+}
+
+static void
+grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
+{
+  td->linkptr = (grub_uint32_t) u->tdfree;
+  u->tdfree = td;
+}
+
+static void
+grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td)
+{
+  /* Free the TDs in this queue.  */
+  while (td)
+    {
+      grub_uhci_td_t tdprev;
+
+      /* Unlink the queue.  */
+      tdprev = td;
+      td = (grub_uhci_td_t) td->linkptr2;
+
+      /* Free the TD.  */
+      grub_free_td (u, tdprev);
+    }
+}
+
+static grub_uhci_qh_t
+grub_alloc_qh (struct grub_uhci *u,
+	       grub_transaction_type_t tr __attribute__((unused)))
+{
+  int i;
+  grub_uhci_qh_t qh;
+
+  /* Look for a Queue Head for this transfer.  Skip the first QH if
+     this is a Interrupt Transfer.  */
+#if 0
+  if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT)
+    i = 0;
+  else
+#endif
+    i = 1;
+
+  for (; i < 255; i++)
+    {
+      if (u->qh[i].elinkptr & 1)
+	break;
+    }
+  qh = &u->qh[i];
+  if (! (qh->elinkptr & 1))
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY,
+		  "no free queue heads available");
+      return NULL;
+    }
+
+  return qh;
+}
+
+static grub_uhci_td_t
+grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
+		       grub_transfer_type_t type, unsigned int addr,
+		       unsigned int toggle, grub_size_t size,
+		       char *data)
+{
+  grub_uhci_td_t td;
+  static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
+
+  /* XXX: Check if data is <4GB.  If it isn't, just copy stuff around.
+     This is only relevant for 64 bits architectures.  */
+
+  /* Grab a free Transfer Descriptor and initialize it.  */
+  td = grub_alloc_td (u);
+  if (! td)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY,
+		  "no transfer descriptors available for UHCI transfer");
+      return 0;
+    }
+
+  grub_dprintf ("uhci",
+		"transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%d data=%p td=%p\n",
+		endp, type, addr, toggle, size, data, td);
+
+  /* Don't point to any TD, just terminate.  */
+  td->linkptr = 1;
+
+  /* Active!  Only retry a transfer 3 times.  */
+  td->ctrl_status = (1 << 23) | (3 << 27);
+
+  /* If zero bytes are transmitted, size is 0x7FF.  Otherwise size is
+     size-1.  */
+  if (size == 0)
+    size = 0x7FF;
+  else
+    size = size - 1;
+
+  /* Setup whatever is required for the token packet.  */
+  td->token = ((size << 21) | (toggle << 19) | (endp << 15)
+	       | (addr << 8) | tf[type]);
+
+  td->buffer = (grub_uint32_t) data;
+
+  return td;
+}
+
+static grub_usb_err_t
+grub_uhci_transfer (grub_usb_controller_t dev,
+		    grub_usb_transfer_t transfer)
+{
+  struct grub_uhci *u = (struct grub_uhci *) dev->data;
+  grub_uhci_qh_t qh;
+  grub_uhci_td_t td;
+  grub_uhci_td_t td_first = NULL;
+  grub_uhci_td_t td_prev = NULL;
+  grub_usb_err_t err = GRUB_USB_ERR_NONE;
+  int i;
+
+  /* Allocate a queue head for the transfer queue.  */
+  qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
+  if (! qh)
+    return grub_errno;
+
+  for (i = 0; i < transfer->transcnt; i++)
+    {
+      grub_usb_transaction_t tr = &transfer->transactions[i];
+
+      td = grub_uhci_transaction (u, transfer->endpoint, tr->pid,
+				  transfer->devaddr, tr->toggle,
+				  tr->size, tr->data); 
+      if (! td)
+	{
+	  /* Terminate and free.  */
+	  td_prev->linkptr2 = 0;
+	  td_prev->linkptr = 1;
+
+	  if (td_first)
+	    grub_free_queue (u, td_first);
+
+	  return GRUB_USB_ERR_INTERNAL;
+	}
+
+      if (! td_first)
+	td_first = td;
+      else
+	{
+	  td_prev->linkptr2 = (grub_uint32_t) td;
+	  td_prev->linkptr = (grub_uint32_t) td;
+	  td_prev->linkptr |= 4;
+	}
+      td_prev = td;
+    }
+  td_prev->linkptr2 = 0;
+  td_prev->linkptr = 1;
+
+  grub_dprintf ("uhci", "setup transaction %d\n", transfer->type);
+
+  /* Link it into the queue and terminate.  Now the transaction can
+     take place.  */
+  qh->elinkptr = (grub_uint32_t) td_first;
+
+  grub_dprintf ("uhci", "initiate transaction\n");
+
+  /* Wait until either the transaction completed or an error
+     occured.  */
+  for (;;)
+    {
+      grub_uhci_td_t errtd;
+
+      errtd = (grub_uhci_td_t) (qh->elinkptr & ~0x0f);
+
+      grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n",
+		    errtd->ctrl_status, errtd->buffer & (~15), errtd);
+
+      /* Check if the transaction completed.  */
+      if (qh->elinkptr & 1)
+	break;
+
+      grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status);
+
+      /* Check if the TD is not longer active.  */
+      if (! (errtd->ctrl_status & (1 << 23)))
+	{
+	  grub_dprintf ("uhci", ">>t status=0x%02x\n", errtd->ctrl_status);
+
+	  /* Check if the endpoint is stalled.  */
+	  if (errtd->ctrl_status & (1 << 22))
+	    err = GRUB_USB_ERR_STALL;
+
+	  /* Check if an error related to the data buffer occured.  */
+	  if (errtd->ctrl_status & (1 << 21))
+	    err = GRUB_USB_ERR_DATA;
+
+	  /* Check if a babble error occured.  */
+	  if (errtd->ctrl_status & (1 << 20))
+	    err = GRUB_USB_ERR_BABBLE;
+ 
+	  /* Check if a NAK occured.  */
+	  if (errtd->ctrl_status & (1 << 19))
+	    err = GRUB_USB_ERR_NAK;
+
+	  /* Check if a timeout occured.  */
+	  if (errtd->ctrl_status & (1 << 18))
+	    err = GRUB_USB_ERR_TIMEOUT;
+
+	  /* Check if a bitstuff error occured.  */
+	  if (errtd->ctrl_status & (1 << 17))
+	    err = GRUB_USB_ERR_BITSTUFF;
+
+	  if (err)
+	    goto fail;
+
+	  /* Fall through, no errors occured, so the QH might be
+	     updated.  */
+	  grub_dprintf ("uhci", "transaction fallthrough\n");
+	}
+    }
+
+  grub_dprintf ("uhci", "transaction complete\n");
+
+ fail:
+
+  grub_dprintf ("uhci", "transaction failed\n");
+
+  /* Place the QH back in the free list and deallocate the associated
+     TDs.  */
+  qh->elinkptr = 1;
+  grub_free_queue (u, td_first);
+
+  return err;
+}
+
+static int
+grub_uhci_iterate (int (*hook) (grub_usb_controller_t dev))
+{
+  struct grub_uhci *u;
+  struct grub_usb_controller dev;
+
+  for (u = uhci; u; u = u->next)
+    {
+      dev.data = u;
+      if (hook (&dev))
+	return 1;
+    }
+
+  return 0;
+}
+
+static grub_err_t
+grub_uhci_portstatus (grub_usb_controller_t dev,
+		      unsigned int port, unsigned int enable)
+{
+  struct grub_uhci *u = (struct grub_uhci *) dev->data;
+  int reg;
+  unsigned int status;
+
+  grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
+
+  if (port == 0)
+    reg = GRUB_UHCI_REG_PORTSC1;
+  else if (port == 1)
+    reg = GRUB_UHCI_REG_PORTSC2;
+  else
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+		       "UHCI Root Hub port does not exist");
+
+  status = grub_uhci_readreg16 (u, reg);
+  grub_dprintf ("uhci", "detect=0x%02x\n", status);
+
+  /* Reset the port.  */
+  grub_uhci_writereg16 (u, reg, enable << 9);
+
+  /* Wait for the reset to complete.  XXX: How long exactly?  */
+  grub_millisleep (10);
+  status = grub_uhci_readreg16 (u, reg);
+  grub_uhci_writereg16 (u, reg, status & ~(1 << 9));
+  grub_dprintf ("uhci", "reset completed\n");
+
+  /* Enable the port.  */
+  grub_uhci_writereg16 (u, reg, enable << 2);
+  grub_millisleep (10);
+
+  grub_dprintf ("uhci", "waiting for the port to be enabled\n");
+
+  while (! (grub_uhci_readreg16 (u, reg) & (1 << 2)));
+
+  status = grub_uhci_readreg16 (u, reg);
+  grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
+
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_usb_speed_t
+grub_uhci_detect_dev (grub_usb_controller_t dev, int port)
+{
+  struct grub_uhci *u = (struct grub_uhci *) dev->data;
+  int reg;
+  unsigned int status;
+
+  if (port == 0)
+    reg = GRUB_UHCI_REG_PORTSC1;
+  else if (port == 1)
+    reg = GRUB_UHCI_REG_PORTSC2;
+  else
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+		       "UHCI Root Hub port does not exist");
+
+  status = grub_uhci_readreg16 (u, reg);
+
+  grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
+
+  if (! (status & 1))
+    return GRUB_USB_SPEED_NONE;
+  else if (status & (1 << 8))
+    return GRUB_USB_SPEED_LOW;
+  else
+    return GRUB_USB_SPEED_FULL;
+}
+
+static int
+grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused)))
+{
+  /* The root hub has exactly two ports.  */
+  return 2;
+}
+
+
+static struct grub_usb_controller_dev usb_controller =
+{
+  .name = "uhci",
+  .iterate = grub_uhci_iterate,
+  .transfer = grub_uhci_transfer,
+  .hubports = grub_uhci_hubports,
+  .portstatus = grub_uhci_portstatus,
+  .detect_dev = grub_uhci_detect_dev
+};
+
+GRUB_MOD_INIT(uhci)
+{
+  grub_uhci_inithw ();
+  grub_usb_controller_dev_register (&usb_controller);
+  grub_dprintf ("uhci", "registed\n");
+}
+
+GRUB_MOD_FINI(uhci)
+{
+  struct grub_uhci *u;
+
+  /* Disable all UHCI controllers.  */
+  for (u = uhci; u; u = u->next)
+    grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
+
+  /* Unregister the controller.  */
+  grub_usb_controller_dev_unregister (&usb_controller);
+}

Added: trunk/grub2/bus/usb/usb.c
===================================================================
--- trunk/grub2/bus/usb/usb.c	                        (rev 0)
+++ trunk/grub2/bus/usb/usb.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,263 @@
+/* usb.c - Generic USB interfaces.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/usb.h>
+#include <grub/misc.h>
+
+static grub_usb_controller_dev_t grub_usb_list;
+
+void
+grub_usb_controller_dev_register (grub_usb_controller_dev_t usb)
+{
+  auto int iterate_hook (grub_usb_controller_t dev);
+
+  /* Iterate over all controllers found by the driver.  */
+  int iterate_hook (grub_usb_controller_t dev)
+    {
+      dev->dev = usb;
+
+      /* Enable the ports of the USB Root Hub.  */
+      grub_usb_root_hub (dev);
+
+      return 0;
+    }
+
+  usb->next = grub_usb_list;
+  grub_usb_list = usb;
+
+  if (usb->iterate)
+    usb->iterate (iterate_hook);
+}
+
+void
+grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb)
+{
+  grub_usb_controller_dev_t *p, q;
+
+  for (p = &grub_usb_list, q = *p; q; p = &(q->next), q = q->next)
+    if (q == usb)
+      {
+	*p = q->next;
+	break;
+      }
+}
+
+#if 0
+int
+grub_usb_controller_iterate (int (*hook) (grub_usb_controller_t dev))
+{
+  grub_usb_controller_dev_t p;
+
+  auto int iterate_hook (grub_usb_controller_t dev);
+
+  int iterate_hook (grub_usb_controller_t dev)
+    {
+      dev->dev = p;
+      if (hook (dev))
+	return 1;
+      return 0;
+    }
+
+  /* Iterate over all controller drivers.  */
+  for (p = grub_usb_list; p; p = p->next)
+    {
+      /* Iterate over the busses of the controllers.  XXX: Actually, a
+	 hub driver should do this.  */
+      if (p->iterate (iterate_hook))
+	return 1;
+    }
+
+  return 0;
+}
+#endif
+
+
+grub_usb_err_t
+grub_usb_clear_halt (grub_usb_device_t dev, int endpoint)
+{
+  dev->toggle[endpoint] = 0;
+  return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+				     | GRUB_USB_REQTYPE_STANDARD
+				     | GRUB_USB_REQTYPE_TARGET_ENDP),
+			       GRUB_USB_REQ_CLEAR_FEATURE,
+			       GRUB_USB_FEATURE_ENDP_HALT,
+			       endpoint, 0, 0);
+}
+
+grub_usb_err_t
+grub_usb_set_configuration (grub_usb_device_t dev, int configuration)
+{
+  int i;
+
+  for (i = 0; i < 16; i++)
+    dev->toggle[i] = 0;
+
+  return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+				     | GRUB_USB_REQTYPE_STANDARD
+				     | GRUB_USB_REQTYPE_TARGET_DEV),
+			       GRUB_USB_REQ_SET_CONFIGURATION, configuration,
+			       0, 0, NULL);
+}
+
+grub_usb_err_t
+grub_usb_get_descriptor (grub_usb_device_t dev,
+			 grub_uint8_t type, grub_uint8_t index,
+			 grub_size_t size, char *data)
+{
+  return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+				     | GRUB_USB_REQTYPE_STANDARD
+				     | GRUB_USB_REQTYPE_TARGET_DEV),
+			       GRUB_USB_REQ_GET_DESCRIPTOR,
+			       (type << 8) | index,
+			       0, size, data);
+}
+
+struct grub_usb_desc_endp *
+grub_usb_get_endpdescriptor (grub_usb_device_t usbdev, int addr)
+{
+  int i;
+
+  for (i = 0; i < usbdev->config[0].descconf->numif; i++)
+    {
+      struct grub_usb_desc_if *interf;
+      int j;
+
+      interf = usbdev->config[0].interf[i].descif;
+
+      for (j = 0; j < interf->endpointcnt; j++)
+	{
+	  struct grub_usb_desc_endp *endp;
+	  endp = &usbdev->config[0].interf[i].descendp[j];
+
+	  if (endp->endp_addr == addr)
+	    return endp;
+	}
+    }
+
+  return NULL;
+}
+
+grub_usb_err_t
+grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
+		     char **string)
+{
+  struct grub_usb_desc_str descstr;
+  struct grub_usb_desc_str *descstrp;
+  grub_usb_err_t err;
+
+  /* Only get the length.  */
+  err = grub_usb_control_msg (dev, 1 << 7,
+			      0x06, (3 << 8) | index,
+			      langid, 1, (char *) &descstr);
+  if (err)
+    return err;
+
+  descstrp = grub_malloc (descstr.length);
+  if (! descstrp)
+    return GRUB_USB_ERR_INTERNAL;
+  err = grub_usb_control_msg (dev, 1 << 7,
+			      0x06, (3 << 8) | index,
+			      langid, descstr.length, (char *) descstrp);
+
+  *string = grub_malloc (descstr.length / 2);
+  if (! *string)
+    {
+      grub_free (descstrp);
+      return GRUB_USB_ERR_INTERNAL;
+    }
+
+  grub_utf16_to_utf8 ((grub_uint8_t *) *string, descstrp->str, descstrp->length / 2 - 1);
+  (*string)[descstr.length / 2 - 1] = '\0';
+  grub_free (descstrp);
+
+  return GRUB_USB_ERR_NONE;
+}
+
+grub_usb_err_t
+grub_usb_device_initialize (grub_usb_device_t dev)
+{
+  struct grub_usb_desc_device *descdev;
+  struct grub_usb_desc_config config;
+  grub_usb_err_t err;
+  int i;
+
+  err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE,
+				 0, sizeof (struct grub_usb_desc_device),
+				 (char *) &dev->descdev);
+  if (err)
+    return err;
+  descdev = &dev->descdev;
+
+  for (i = 0; i < 8; i++)
+    dev->config[i].descconf = NULL;
+
+  for (i = 0; i < descdev->configcnt; i++)
+    {
+      int pos;
+      int currif;
+      char *data;
+
+      /* First just read the first 4 bytes of the configuration
+	 descriptor, after that it is known how many bytes really have
+	 to be read.  */
+      err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i, 4,
+				     (char *) &config);
+
+      data = grub_malloc (config.totallen);
+      if (! data)
+	{
+	  err = GRUB_USB_ERR_INTERNAL;
+	  goto fail;
+	}
+
+      dev->config[i].descconf = (struct grub_usb_desc_config *) data;
+      err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i,
+				     config.totallen, data);
+      if (err)
+	goto fail;
+
+      /* Skip the configuration descriptor.  */
+      pos = sizeof (struct grub_usb_desc_config);
+      
+      /* Read all interfaces.  */
+      for (currif = 0; currif < dev->config[i].descconf->numif; currif++)
+	{
+	  dev->config[i].interf[currif].descif
+	    = (struct grub_usb_desc_if *) &data[pos];
+	  pos += sizeof (struct grub_usb_desc_if);
+
+	  /* Point to the first endpoint.  */
+	  dev->config[i].interf[currif].descendp
+	    = (struct grub_usb_desc_endp *) &data[pos];
+	  pos += (sizeof (struct grub_usb_desc_endp)
+		  * dev->config[i].interf[currif].descif->endpointcnt);
+	}
+    }
+
+  return GRUB_USB_ERR_NONE;
+
+ fail:
+
+  for (i = 0; i < 8; i++)
+    grub_free (dev->config[i].descconf);
+
+  return err;
+}

Added: trunk/grub2/bus/usb/usbhub.c
===================================================================
--- trunk/grub2/bus/usb/usbhub.c	                        (rev 0)
+++ trunk/grub2/bus/usb/usbhub.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,193 @@
+/* usb.c - USB Hub Support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/usb.h>
+#include <grub/misc.h>
+
+/* USB Supports 127 devices, with device 0 as special case.  */
+static struct grub_usb_device *grub_usb_devs[128];
+
+/* Add a device that currently has device number 0 and resides on
+   CONTROLLER, the Hub reported that the device speed is SPEED.  */
+static grub_usb_device_t
+grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed)
+{
+  grub_usb_device_t dev;
+  int i;
+
+  dev = grub_malloc (sizeof (struct grub_usb_device));
+  if (! dev)
+    return NULL;
+
+  dev->controller = *controller;
+  dev->addr = 0;
+  dev->initialized = 0;
+  dev->speed = speed;
+
+  grub_usb_device_initialize (dev);
+
+  /* Assign a new address to the device.  */
+  for (i = 1; i < 128; i++)
+    {
+      if (! grub_usb_devs[i])
+	break;
+    }
+  if (grub_usb_devs[i])
+    {
+      grub_error (GRUB_ERR_IO, "Can't assign address to USB device");
+      return NULL;
+    }
+
+  grub_usb_control_msg (dev,
+			(GRUB_USB_REQTYPE_OUT
+			 | GRUB_USB_REQTYPE_STANDARD
+			 | GRUB_USB_REQTYPE_TARGET_DEV),
+			GRUB_USB_REQ_SET_ADDRESS,
+			i, 0, 0, NULL);
+  dev->addr = i;
+  dev->initialized = 1;
+  grub_usb_devs[i] = dev;
+
+  return dev;
+}
+
+
+static grub_err_t
+grub_usb_add_hub (grub_usb_device_t dev)
+{
+  struct grub_usb_usb_hubdesc hubdesc;
+  grub_err_t err;
+  int i;
+
+  grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+			      | GRUB_USB_REQTYPE_CLASS
+			      | GRUB_USB_REQTYPE_TARGET_DEV),
+			GRUB_USB_REQ_GET_DESCRIPTOR,
+			(GRUB_USB_DESCRIPTOR_HUB << 8) | 0,
+			0, sizeof (hubdesc), (char *) &hubdesc);
+
+  /* Iterate over the Hub ports.  */
+  for (i = 1; i <= hubdesc.portcnt; i++)
+    {
+      grub_uint32_t status;
+
+      /* Get the port status.  */
+      err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+					| GRUB_USB_REQTYPE_CLASS
+					| GRUB_USB_REQTYPE_TARGET_OTHER),
+				  GRUB_USB_REQ_HUB_GET_PORT_STATUS,
+				  0, i, sizeof (status), (char *) &status);
+
+      /* Just ignore the device if the Hub does not report the
+	 status.  */
+      if (err)
+	continue;
+
+      /* If connected, reset and enable the port.  */
+      if (status & GRUB_USB_HUB_STATUS_CONNECTED)
+	{
+	  grub_usb_speed_t speed;
+
+	  /* Determine the device speed.  */
+	  if (status & GRUB_USB_HUB_STATUS_LOWSPEED)
+	    speed = GRUB_USB_SPEED_LOW;
+	  else
+	    {
+	      if (status & GRUB_USB_HUB_STATUS_HIGHSPEED)
+		speed = GRUB_USB_SPEED_HIGH;
+	      else
+		speed = GRUB_USB_SPEED_FULL;
+	    }
+
+	  /* A device is actually connected to this port, not enable
+	     the port.  XXX: Why 0x03?  According to some docs it
+	     should be 0x0.  Check the specification!  */
+	  err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+					    | GRUB_USB_REQTYPE_CLASS
+					    | GRUB_USB_REQTYPE_TARGET_OTHER),
+				      0x3, 0x4, i, 0, 0);
+
+	  /* If the Hub does not cooperate for this port, just skip
+	     the port.  */
+	  if (err)
+	    continue;
+
+	  /* Add the device and assign a device address to it.  */
+	  grub_usb_hub_add_dev (&dev->controller, speed);
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+grub_usb_err_t
+grub_usb_root_hub (grub_usb_controller_t controller)
+{
+  grub_err_t err;
+  int ports;
+  int i;
+
+  /* Query the number of ports the root Hub has.  */
+  ports = controller->dev->hubports (controller);
+
+  for (i = 0; i < ports; i++)
+    {
+      grub_usb_speed_t speed = controller->dev->detect_dev (controller, i);
+
+      if (speed != GRUB_USB_SPEED_NONE)
+	{
+	  grub_usb_device_t dev;
+
+	  /* Enable the port.  */
+	  err = controller->dev->portstatus (controller, i, 1);
+	  if (err)
+	    continue;
+
+	  /* Enable the port and create a device.  */
+	  dev = grub_usb_hub_add_dev (controller, speed);
+	  if (! dev)
+	    continue;
+
+	  /* If the device is a Hub, scan it for more devices.  */
+	  if (dev->descdev.class == 0x09)
+	    grub_usb_add_hub (dev);
+	}
+    }
+
+  return GRUB_USB_ERR_NONE;
+}
+
+int
+grub_usb_iterate (int (*hook) (grub_usb_device_t dev))
+{
+  int i;
+
+  for (i = 0; i < 128; i++)
+    {
+      if (grub_usb_devs[i])
+	{
+	  if (hook (grub_usb_devs[i]))
+	      return 1;
+	}
+    }
+
+  return 0;
+}

Added: trunk/grub2/bus/usb/usbtrans.c
===================================================================
--- trunk/grub2/bus/usb/usbtrans.c	                        (rev 0)
+++ trunk/grub2/bus/usb/usbtrans.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,212 @@
+/* usbtrans.c - USB Transfers and Transactions.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/usb.h>
+#include <grub/usbtrans.h>
+
+grub_usb_err_t
+grub_usb_control_msg (grub_usb_device_t dev,
+		      grub_uint8_t reqtype,
+		      grub_uint8_t request,
+		      grub_uint16_t value,
+		      grub_uint16_t index,
+		      grub_size_t size, char *data)
+{
+  int i;
+  grub_usb_transfer_t transfer;
+  int datablocks;
+  struct grub_usb_packet_setup setupdata;
+  grub_usb_err_t err;
+  int max;
+
+  grub_dprintf ("usb",
+		"control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%d\n",
+		reqtype, request,  value, index, size);
+
+  /* Create a transfer.  */
+  transfer = grub_malloc (sizeof (struct grub_usb_transfer));
+  if (! transfer)
+    return grub_errno;
+
+  /* Determine the maximum packet size.  */
+  if (dev->initialized)
+    max = dev->descdev.maxsize0;
+  else
+    max = 64;
+
+  datablocks = (size + max - 1) / max;
+  
+  /* XXX: Discriminate between different types of control
+     messages.  */
+  transfer->transcnt = datablocks + 2;
+  transfer->size = size; /* XXX ? */
+  transfer->endpoint = 0;
+  transfer->devaddr = dev->addr;
+  transfer->type = GRUB_USB_TRANSACTION_TYPE_CONTROL;
+  transfer->max = max;
+  transfer->dev = dev;
+
+  /* Allocate an array of transfer data structures.  */
+  transfer->transactions = grub_malloc (transfer->transcnt
+					* sizeof (struct grub_usb_transfer));
+  if (! transfer->transactions)
+    {
+      grub_free (transfer);
+      return grub_errno;
+    }
+
+  /* Build a Setup packet.  XXX: Endianess.  */
+  setupdata.reqtype = reqtype;
+  setupdata.request = request;
+  setupdata.value = value;
+  setupdata.index = index;
+  setupdata.length = size;
+  transfer->transactions[0].size = sizeof (setupdata);
+  transfer->transactions[0].pid = GRUB_USB_TRANSFER_TYPE_SETUP;
+  transfer->transactions[0].data = (char *) &setupdata;
+  transfer->transactions[0].toggle = 0;
+
+  /* Now the data...  XXX: Is this the right way to transfer control
+     transfers?  */
+  for (i = 0; i < datablocks; i++)
+    {
+      grub_usb_transaction_t tr = &transfer->transactions[i + 1];
+
+      tr->size = (size > max) ? max : size;
+      /* Use the right most bit as the data toggle.  Simple and
+	 effective.  */
+      tr->toggle = !(i & 1);
+      if (reqtype & 128)
+	tr->pid = GRUB_USB_TRANSFER_TYPE_IN;
+      else
+	tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
+      tr->data = &data[i * max];
+      size -= max;
+    }
+
+  /* End with an empty OUT transaction.  */
+  transfer->transactions[datablocks + 1].size = 0;
+  transfer->transactions[datablocks + 1].data = NULL;
+  if (reqtype & 128)
+    transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
+  else
+    transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_IN;
+  
+  transfer->transactions[datablocks + 1].toggle = 1;
+
+  err = dev->controller.dev->transfer (&dev->controller, transfer);
+
+  grub_free (transfer->transactions);
+  grub_free (transfer);
+
+  return err;
+}
+
+static grub_usb_err_t
+grub_usb_bulk_readwrite (grub_usb_device_t dev,
+			 int endpoint, grub_size_t size, char *data,
+			 grub_transfer_type_t type)
+{
+  int i;
+  grub_usb_transfer_t transfer;
+  int datablocks;
+  unsigned int max;
+  grub_usb_err_t err;
+  int toggle = dev->toggle[endpoint];
+
+  /* Use the maximum packet size given in the endpoint descriptor.  */
+  if (dev->initialized)
+    {
+      struct grub_usb_desc_endp *endpdesc;
+      endpdesc = grub_usb_get_endpdescriptor (dev, 0);
+
+      if (endpdesc)
+	max = endpdesc->maxpacket;
+      else
+	max = 64;
+    }
+  else
+    max = 64;
+
+  /* Create a transfer.  */
+  transfer = grub_malloc (sizeof (struct grub_usb_transfer));
+  if (! transfer)
+    return grub_errno;
+
+  datablocks = ((size + max - 1) / max);
+  transfer->transcnt = datablocks;
+  transfer->size = size - 1;
+  transfer->endpoint = endpoint;
+  transfer->devaddr = dev->addr;
+  transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK;
+  transfer->max = max;
+  transfer->dev = dev;
+
+  /* Allocate an array of transfer data structures.  */
+  transfer->transactions = grub_malloc (transfer->transcnt
+					* sizeof (struct grub_usb_transfer));
+  if (! transfer->transactions)
+    {
+      grub_free (transfer);
+      return grub_errno;
+    }
+
+  /* Set up all transfers.  */
+  for (i = 0; i < datablocks; i++)
+    {
+      grub_usb_transaction_t tr = &transfer->transactions[i];
+
+      tr->size = (size > max) ? max : size;
+      /* XXX: Use the right most bit as the data toggle.  Simple and
+	 effective.  */
+      tr->toggle = toggle;
+      toggle = toggle ? 0 : 1;
+      tr->pid = type;
+      tr->data = &data[i * max];
+      size -= tr->size;
+    }
+ 
+  err = dev->controller.dev->transfer (&dev->controller, transfer);
+  grub_dprintf ("usb", "toggle=%d\n", toggle);
+  dev->toggle[endpoint] = toggle;
+
+  grub_free (transfer->transactions);
+  grub_free (transfer);
+
+  return err;
+}
+
+grub_usb_err_t
+grub_usb_bulk_write (grub_usb_device_t dev,
+		     int endpoint, grub_size_t size, char *data)
+{
+  return grub_usb_bulk_readwrite (dev, endpoint, size, data,
+				  GRUB_USB_TRANSFER_TYPE_OUT);
+}
+
+grub_usb_err_t
+grub_usb_bulk_read (grub_usb_device_t dev,
+		    int endpoint, grub_size_t size, char *data)
+{
+  return grub_usb_bulk_readwrite (dev, endpoint, size, data,
+				  GRUB_USB_TRANSFER_TYPE_IN);
+}

Added: trunk/grub2/commands/usbtest.c
===================================================================
--- trunk/grub2/commands/usbtest.c	                        (rev 0)
+++ trunk/grub2/commands/usbtest.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,160 @@
+/* usbtest.c - test module for USB */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/usb.h>
+
+static const char *usb_classes[] =
+  {
+    "",
+    "Audio",
+    "Communication Interface",
+    "HID",
+    "",
+    "Physical",
+    "Image",
+    "Printer",
+    "Mass Storage",
+    "Hub",
+    "Data Interface",
+    "Smart Card",
+    "Content Security",
+    "Video"
+  };
+
+static const char *usb_endp_type[] =
+  {
+    "Control",
+    "Isochronous",
+    "Bulk",
+    "Interrupt"
+  };
+
+static const char *usb_devspeed[] = 
+  {
+    "",
+    "Low",
+    "Full",
+    "High"
+  };
+
+static void
+usb_print_str (const char *description, grub_usb_device_t dev, int idx)
+{
+  char *name;
+  /* XXX: LANGID  */
+
+  if (! idx)
+    return;
+
+  grub_usb_get_string (dev, idx, 0x0409, &name);
+  grub_printf ("%s: `%s'\n", description, name);
+  grub_free (name);
+}
+
+static int
+usb_iterate (grub_usb_device_t dev)
+{
+  struct grub_usb_desc_device *descdev;
+  int i;
+
+  descdev = &dev->descdev;
+
+  usb_print_str ("Product", dev, descdev->strprod);
+  usb_print_str ("Vendor", dev, descdev->strvendor);
+  usb_print_str ("Serial", dev, descdev->strserial);
+  
+  if (descdev->class > 0 && descdev->class <= 0x0E)
+    grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
+		 descdev->class, usb_classes[descdev->class],
+		 descdev->subclass, descdev->protocol);
+  grub_printf ("USB version %d.%d, VendorID: 0x%02x, ProductID: 0x%02x, #conf: %d\n",
+	       descdev->usbrel >> 8, (descdev->usbrel >> 4) & 0x0F,
+	       descdev->vendorid, descdev->prodid, descdev->configcnt);
+
+  grub_printf ("%s speed device\n", usb_devspeed[dev->speed]);
+
+  for (i = 0; i < descdev->configcnt; i++)
+    {
+      struct grub_usb_desc_config *config;
+
+      config = dev->config[i].descconf;
+      usb_print_str ("Configuration:", dev, config->strconfig);
+    }
+
+  for (i = 0; i < dev->config[0].descconf->numif; i++)
+    {
+      int j;
+      struct grub_usb_desc_if *interf;
+      interf = dev->config[0].interf[i].descif;
+
+      grub_printf ("Interface #%d: #Endpoints: %d   ",
+		   i, interf->endpointcnt);
+      if (interf->class > 0 && interf->class <= 0x0E)
+	grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
+		     interf->class, usb_classes[interf->class],
+		     interf->subclass, interf->protocol);
+
+      usb_print_str ("Interface", dev, interf->strif);
+
+      for (j = 0; j < interf->endpointcnt; j++)
+	{
+	  struct grub_usb_desc_endp *endp;
+	  endp = &dev->config[0].interf[i].descendp[j];
+
+	  grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n",
+		       endp->endp_addr & 15,
+		       (endp->endp_addr & 128) ? "IN" : "OUT",
+		       endp->maxpacket, usb_endp_type[endp->attrib & 3],
+		       endp->interval);
+	}
+    }
+
+  grub_printf("\n");
+
+  return 0;
+}
+
+static grub_err_t
+grub_cmd_usbtest (struct grub_arg_list *state __attribute__ ((unused)),
+		  int argc __attribute__ ((unused)),
+		  char **args __attribute__ ((unused)))
+{
+  grub_printf ("USB devices:\n\n");
+  grub_usb_iterate (usb_iterate);
+
+  return 0;
+}
+
+GRUB_MOD_INIT(usbtest)
+{
+  (void)mod;			/* To stop warning. */
+  grub_register_command ("usb", grub_cmd_usbtest, GRUB_COMMAND_FLAG_BOTH,
+			 "usb", "Test USB support", 0);
+}
+
+GRUB_MOD_FINI(usbtest)
+{
+  grub_unregister_command ("usb");
+}

Modified: trunk/grub2/conf/i386-pc.mk
===================================================================
--- trunk/grub2/conf/i386-pc.mk	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/conf/i386-pc.mk	2009-02-08 17:58:32 UTC (rev 1982)
@@ -525,7 +525,7 @@
 	commands/search.c commands/blocklist.c commands/hexdump.c	\
 	lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c		\
 	commands/i386/cpuid.c						\
-	disk/host.c disk/loopback.c					\
+	disk/host.c disk/loopback.c disk/scsi.c				\
 	fs/fshelp.c 	\
 	\
 	io/gzio.c							\
@@ -553,11 +553,11 @@
 	disk/raid.c disk/raid5_recover.c disk/raid6_recover.c		\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c		\
 	grub_emu_init.c
-CLEANFILES += grub-emu$(EXEEXT) grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-kern_m
 ain.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu
 -fs_ntfs.o grub_emu-fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o
-MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_configfile.d grub_emu-commands_echo.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_test.d grub_emu-commands_search.d grub_emu-commands_blocklist.d grub_emu-commands_hexdump.d grub_emu-lib_hexdump.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_reboot.d grub_emu-commands_i386_cpuid.d grub_emu-disk_host.d grub_emu-disk_loopback.d grub_emu-fs_fshelp.d grub_emu-io_gzio.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_elf.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-normal_execute.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-normal_lexer.d grub_emu-kern_loader.d grub_emu-kern_main.d grub_e
 mu-kern_misc.d grub_emu-kern_parser.d grub_emu-grub_script_tab.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_function.d grub_emu-normal_completion.d grub_emu-normal_main.d grub_emu-normal_color.d grub_emu-normal_menu.d grub_emu-normal_menu_entry.d grub_emu-normal_menu_viewer.d grub_emu-normal_misc.d grub_emu-normal_script.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-partmap_sun.d grub_emu-partmap_acorn.d grub_emu-partmap_gpt.d grub_emu-fs_affs.d grub_emu-fs_cpio.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_hfs.d grub_emu-fs_hfsplus.d grub_emu-fs_iso9660.d grub_emu-fs_udf.d grub_emu-fs_jfs.d grub_emu-fs_minix.d grub_emu-fs_ntfs.d g
 rub_emu-fs_ntfscomp.d grub_emu-fs_reiserfs.d grub_emu-fs_sfs.d grub_emu-fs_ufs.d grub_emu-fs_xfs.d grub_emu-fs_afs.d grub_emu-fs_tar.d grub_emu-util_console.d grub_emu-util_hostfs.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_hostdisk.d grub_emu-util_getroot.d grub_emu-util_i386_pc_misc.d grub_emu-disk_raid.d grub_emu-disk_raid5_recover.d grub_emu-disk_raid6_recover.d grub_emu-disk_mdraid_linux.d grub_emu-disk_dmraid_nvidia.d grub_emu-disk_lvm.d grub_emu-grub_emu_init.d
+CLEANFILES += grub-emu$(EXEEXT) grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-disk_scsi.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loa
 der.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub_em
 u-fs_minix.o grub_emu-fs_ntfs.o grub_emu-fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o
+MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_configfile.d grub_emu-commands_echo.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_test.d grub_emu-commands_search.d grub_emu-commands_blocklist.d grub_emu-commands_hexdump.d grub_emu-lib_hexdump.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_reboot.d grub_emu-commands_i386_cpuid.d grub_emu-disk_host.d grub_emu-disk_loopback.d grub_emu-disk_scsi.d grub_emu-fs_fshelp.d grub_emu-io_gzio.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_elf.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-normal_execute.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-normal_lexer.d grub_emu-kern_loader.d grub_e
 mu-kern_main.d grub_emu-kern_misc.d grub_emu-kern_parser.d grub_emu-grub_script_tab.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_function.d grub_emu-normal_completion.d grub_emu-normal_main.d grub_emu-normal_color.d grub_emu-normal_menu.d grub_emu-normal_menu_entry.d grub_emu-normal_menu_viewer.d grub_emu-normal_misc.d grub_emu-normal_script.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-partmap_sun.d grub_emu-partmap_acorn.d grub_emu-partmap_gpt.d grub_emu-fs_affs.d grub_emu-fs_cpio.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_hfs.d grub_emu-fs_hfsplus.d grub_emu-fs_iso9660.d grub_emu-fs_udf.d grub_emu-fs_jfs.d grub_emu-fs_minix.d
  grub_emu-fs_ntfs.d grub_emu-fs_ntfscomp.d grub_emu-fs_reiserfs.d grub_emu-fs_sfs.d grub_emu-fs_ufs.d grub_emu-fs_xfs.d grub_emu-fs_afs.d grub_emu-fs_tar.d grub_emu-util_console.d grub_emu-util_hostfs.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_hostdisk.d grub_emu-util_getroot.d grub_emu-util_i386_pc_misc.d grub_emu-disk_raid.d grub_emu-disk_raid5_recover.d grub_emu-disk_raid6_recover.d grub_emu-disk_mdraid_linux.d grub_emu-disk_dmraid_nvidia.d grub_emu-disk_lvm.d grub_emu-grub_emu_init.d
 
-grub-emu: $(grub_emu_DEPENDENCIES) grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-ker
 n_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_
 emu-fs_ntfs.o grub_emu-fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o
-	$(CC) -o $@ grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern
 _misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_ntfs.o grub_emu
 -fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o $(LDFLAGS) $(grub_emu_LDFLAGS)
+grub-emu: $(grub_emu_DEPENDENCIES) grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-disk_scsi.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_
 loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub
 _emu-fs_minix.o grub_emu-fs_ntfs.o grub_emu-fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o
+	$(CC) -o $@ grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_echo.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_blocklist.o grub_emu-commands_hexdump.o grub_emu-lib_hexdump.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_reboot.o grub_emu-commands_i386_cpuid.o grub_emu-disk_host.o grub_emu-disk_loopback.o grub_emu-disk_scsi.o grub_emu-fs_fshelp.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_elf.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-kern
 _main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_main.o grub_emu-normal_color.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_menu_viewer.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-partmap_acorn.o grub_emu-partmap_gpt.o grub_emu-fs_affs.o grub_emu-fs_cpio.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_hfs.o grub_emu-fs_hfsplus.o grub_emu-fs_iso9660.o grub_emu-fs_udf.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_e
 mu-fs_ntfs.o grub_emu-fs_ntfscomp.o grub_emu-fs_reiserfs.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-fs_afs.o grub_emu-fs_tar.o grub_emu-util_console.o grub_emu-util_hostfs.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_hostdisk.o grub_emu-util_getroot.o grub_emu-util_i386_pc_misc.o grub_emu-disk_raid.o grub_emu-disk_raid5_recover.o grub_emu-disk_raid6_recover.o grub_emu-disk_mdraid_linux.o grub_emu-disk_dmraid_nvidia.o grub_emu-disk_lvm.o grub_emu-grub_emu_init.o $(LDFLAGS) $(grub_emu_LDFLAGS)
 
 grub_emu-commands_boot.o: commands/boot.c $(commands/boot.c_DEPENDENCIES)
 	$(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
@@ -631,6 +631,10 @@
 	$(CC) -Idisk -I$(srcdir)/disk $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
 -include grub_emu-disk_loopback.d
 
+grub_emu-disk_scsi.o: disk/scsi.c $(disk/scsi.c_DEPENDENCIES)
+	$(CC) -Idisk -I$(srcdir)/disk $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
+-include grub_emu-disk_scsi.d
+
 grub_emu-fs_fshelp.o: fs/fshelp.c $(fs/fshelp.c_DEPENDENCIES)
 	$(CC) -Ifs -I$(srcdir)/fs $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
 -include grub_emu-fs_fshelp.d
@@ -912,8 +916,36 @@
 -include grub_emu-grub_emu_init.d
 
 
-grub_emu_LDFLAGS = $(LIBCURSES)
+grub_emu_LDFLAGS = $(LIBCURSES) 
 
+ifeq ($(enable_grub_emu_usb), yes)
+grub_emu_SOURCES += disk/usbms.c util/usb.c bus/usb/usb.c	\
+		commands/usbtest.c
+CLEANFILES += grub-emu$(EXEEXT) grub_emu-disk_usbms.o grub_emu-util_usb.o grub_emu-bus_usb_usb.o grub_emu-commands_usbtest.o
+MOSTLYCLEANFILES += grub_emu-disk_usbms.d grub_emu-util_usb.d grub_emu-bus_usb_usb.d grub_emu-commands_usbtest.d
+
+grub-emu: $(grub_emu_DEPENDENCIES) grub_emu-disk_usbms.o grub_emu-util_usb.o grub_emu-bus_usb_usb.o grub_emu-commands_usbtest.o
+	$(CC) -o $@ grub_emu-disk_usbms.o grub_emu-util_usb.o grub_emu-bus_usb_usb.o grub_emu-commands_usbtest.o $(LDFLAGS) $(grub_emu_LDFLAGS)
+
+grub_emu-disk_usbms.o: disk/usbms.c $(disk/usbms.c_DEPENDENCIES)
+	$(CC) -Idisk -I$(srcdir)/disk $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
+-include grub_emu-disk_usbms.d
+
+grub_emu-util_usb.o: util/usb.c $(util/usb.c_DEPENDENCIES)
+	$(CC) -Iutil -I$(srcdir)/util $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
+-include grub_emu-util_usb.d
+
+grub_emu-bus_usb_usb.o: bus/usb/usb.c $(bus/usb/usb.c_DEPENDENCIES)
+	$(CC) -Ibus/usb -I$(srcdir)/bus/usb $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
+-include grub_emu-bus_usb_usb.d
+
+grub_emu-commands_usbtest.o: commands/usbtest.c $(commands/usbtest.c_DEPENDENCIES)
+	$(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $<
+-include grub_emu-commands_usbtest.d
+
+grub_emu_LDFLAGS += $(LIBCURSES) $(LIBUSB)
+endif
+
 # Scripts.
 sbin_SCRIPTS = grub-install
 bin_SCRIPTS = grub-mkrescue
@@ -942,7 +974,8 @@
 	vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
 	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
-	datehook.mod lsmmap.mod
+	datehook.mod lsmmap.mod \
+	usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -2673,6 +2706,329 @@
 bsd_mod_CFLAGS = $(COMMON_CFLAGS)
 bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For usb.mod
+usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
+CLEANFILES += usb.mod mod-usb.o mod-usb.c pre-usb.o usb_mod-bus_usb_usb.o usb_mod-bus_usb_usbtrans.o usb_mod-bus_usb_usbhub.o und-usb.lst
+ifneq ($(usb_mod_EXPORTS),no)
+CLEANFILES += def-usb.lst
+DEFSYMFILES += def-usb.lst
+endif
+MOSTLYCLEANFILES += usb_mod-bus_usb_usb.d usb_mod-bus_usb_usbtrans.d usb_mod-bus_usb_usbhub.d
+UNDSYMFILES += und-usb.lst
+
+usb.mod: pre-usb.o mod-usb.o $(TARGET_OBJ2ELF)
+	-rm -f $@
+	$(TARGET_CC) $(usb_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-usb.o mod-usb.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-usb.o: $(usb_mod_DEPENDENCIES) usb_mod-bus_usb_usb.o usb_mod-bus_usb_usbtrans.o usb_mod-bus_usb_usbhub.o
+	-rm -f $@
+	$(TARGET_CC) $(usb_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ usb_mod-bus_usb_usb.o usb_mod-bus_usb_usbtrans.o usb_mod-bus_usb_usbhub.o
+
+mod-usb.o: mod-usb.c
+	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -c -o $@ $<
+
+mod-usb.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh 'usb' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(usb_mod_EXPORTS),no)
+def-usb.lst: pre-usb.o
+	$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 usb/' > $@
+endif
+
+und-usb.lst: pre-usb.o
+	echo 'usb' > $@
+	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+usb_mod-bus_usb_usb.o: bus/usb/usb.c $(bus/usb/usb.c_DEPENDENCIES)
+	$(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -MD -c -o $@ $<
+-include usb_mod-bus_usb_usb.d
+
+CLEANFILES += cmd-usb_mod-bus_usb_usb.lst fs-usb_mod-bus_usb_usb.lst partmap-usb_mod-bus_usb_usb.lst
+COMMANDFILES += cmd-usb_mod-bus_usb_usb.lst
+FSFILES += fs-usb_mod-bus_usb_usb.lst
+PARTMAPFILES += partmap-usb_mod-bus_usb_usb.lst
+
+cmd-usb_mod-bus_usb_usb.lst: bus/usb/usb.c $(bus/usb/usb.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh usb > $@ || (rm -f $@; exit 1)
+
+fs-usb_mod-bus_usb_usb.lst: bus/usb/usb.c $(bus/usb/usb.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh usb > $@ || (rm -f $@; exit 1)
+
+partmap-usb_mod-bus_usb_usb.lst: bus/usb/usb.c $(bus/usb/usb.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh usb > $@ || (rm -f $@; exit 1)
+
+
+usb_mod-bus_usb_usbtrans.o: bus/usb/usbtrans.c $(bus/usb/usbtrans.c_DEPENDENCIES)
+	$(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -MD -c -o $@ $<
+-include usb_mod-bus_usb_usbtrans.d
+
+CLEANFILES += cmd-usb_mod-bus_usb_usbtrans.lst fs-usb_mod-bus_usb_usbtrans.lst partmap-usb_mod-bus_usb_usbtrans.lst
+COMMANDFILES += cmd-usb_mod-bus_usb_usbtrans.lst
+FSFILES += fs-usb_mod-bus_usb_usbtrans.lst
+PARTMAPFILES += partmap-usb_mod-bus_usb_usbtrans.lst
+
+cmd-usb_mod-bus_usb_usbtrans.lst: bus/usb/usbtrans.c $(bus/usb/usbtrans.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh usb > $@ || (rm -f $@; exit 1)
+
+fs-usb_mod-bus_usb_usbtrans.lst: bus/usb/usbtrans.c $(bus/usb/usbtrans.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh usb > $@ || (rm -f $@; exit 1)
+
+partmap-usb_mod-bus_usb_usbtrans.lst: bus/usb/usbtrans.c $(bus/usb/usbtrans.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh usb > $@ || (rm -f $@; exit 1)
+
+
+usb_mod-bus_usb_usbhub.o: bus/usb/usbhub.c $(bus/usb/usbhub.c_DEPENDENCIES)
+	$(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -MD -c -o $@ $<
+-include usb_mod-bus_usb_usbhub.d
+
+CLEANFILES += cmd-usb_mod-bus_usb_usbhub.lst fs-usb_mod-bus_usb_usbhub.lst partmap-usb_mod-bus_usb_usbhub.lst
+COMMANDFILES += cmd-usb_mod-bus_usb_usbhub.lst
+FSFILES += fs-usb_mod-bus_usb_usbhub.lst
+PARTMAPFILES += partmap-usb_mod-bus_usb_usbhub.lst
+
+cmd-usb_mod-bus_usb_usbhub.lst: bus/usb/usbhub.c $(bus/usb/usbhub.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh usb > $@ || (rm -f $@; exit 1)
+
+fs-usb_mod-bus_usb_usbhub.lst: bus/usb/usbhub.c $(bus/usb/usbhub.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh usb > $@ || (rm -f $@; exit 1)
+
+partmap-usb_mod-bus_usb_usbhub.lst: bus/usb/usbhub.c $(bus/usb/usbhub.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh usb > $@ || (rm -f $@; exit 1)
+
+
+usb_mod_CFLAGS = $(COMMON_CFLAGS)
+usb_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For usbtest.mod
+usbtest_mod_SOURCES = commands/usbtest.c
+CLEANFILES += usbtest.mod mod-usbtest.o mod-usbtest.c pre-usbtest.o usbtest_mod-commands_usbtest.o und-usbtest.lst
+ifneq ($(usbtest_mod_EXPORTS),no)
+CLEANFILES += def-usbtest.lst
+DEFSYMFILES += def-usbtest.lst
+endif
+MOSTLYCLEANFILES += usbtest_mod-commands_usbtest.d
+UNDSYMFILES += und-usbtest.lst
+
+usbtest.mod: pre-usbtest.o mod-usbtest.o $(TARGET_OBJ2ELF)
+	-rm -f $@
+	$(TARGET_CC) $(usbtest_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-usbtest.o mod-usbtest.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-usbtest.o: $(usbtest_mod_DEPENDENCIES) usbtest_mod-commands_usbtest.o
+	-rm -f $@
+	$(TARGET_CC) $(usbtest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ usbtest_mod-commands_usbtest.o
+
+mod-usbtest.o: mod-usbtest.c
+	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbtest_mod_CFLAGS) -c -o $@ $<
+
+mod-usbtest.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh 'usbtest' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(usbtest_mod_EXPORTS),no)
+def-usbtest.lst: pre-usbtest.o
+	$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 usbtest/' > $@
+endif
+
+und-usbtest.lst: pre-usbtest.o
+	echo 'usbtest' > $@
+	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+usbtest_mod-commands_usbtest.o: commands/usbtest.c $(commands/usbtest.c_DEPENDENCIES)
+	$(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(usbtest_mod_CFLAGS) -MD -c -o $@ $<
+-include usbtest_mod-commands_usbtest.d
+
+CLEANFILES += cmd-usbtest_mod-commands_usbtest.lst fs-usbtest_mod-commands_usbtest.lst partmap-usbtest_mod-commands_usbtest.lst
+COMMANDFILES += cmd-usbtest_mod-commands_usbtest.lst
+FSFILES += fs-usbtest_mod-commands_usbtest.lst
+PARTMAPFILES += partmap-usbtest_mod-commands_usbtest.lst
+
+cmd-usbtest_mod-commands_usbtest.lst: commands/usbtest.c $(commands/usbtest.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbtest_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh usbtest > $@ || (rm -f $@; exit 1)
+
+fs-usbtest_mod-commands_usbtest.lst: commands/usbtest.c $(commands/usbtest.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbtest_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh usbtest > $@ || (rm -f $@; exit 1)
+
+partmap-usbtest_mod-commands_usbtest.lst: commands/usbtest.c $(commands/usbtest.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbtest_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh usbtest > $@ || (rm -f $@; exit 1)
+
+
+usbtest_mod_CFLAGS = $(COMMON_CFLAGS)
+usbtest_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For uhci.mod
+uhci_mod_SOURCES = bus/usb/uhci.c
+CLEANFILES += uhci.mod mod-uhci.o mod-uhci.c pre-uhci.o uhci_mod-bus_usb_uhci.o und-uhci.lst
+ifneq ($(uhci_mod_EXPORTS),no)
+CLEANFILES += def-uhci.lst
+DEFSYMFILES += def-uhci.lst
+endif
+MOSTLYCLEANFILES += uhci_mod-bus_usb_uhci.d
+UNDSYMFILES += und-uhci.lst
+
+uhci.mod: pre-uhci.o mod-uhci.o $(TARGET_OBJ2ELF)
+	-rm -f $@
+	$(TARGET_CC) $(uhci_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-uhci.o mod-uhci.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-uhci.o: $(uhci_mod_DEPENDENCIES) uhci_mod-bus_usb_uhci.o
+	-rm -f $@
+	$(TARGET_CC) $(uhci_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ uhci_mod-bus_usb_uhci.o
+
+mod-uhci.o: mod-uhci.c
+	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(uhci_mod_CFLAGS) -c -o $@ $<
+
+mod-uhci.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh 'uhci' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(uhci_mod_EXPORTS),no)
+def-uhci.lst: pre-uhci.o
+	$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 uhci/' > $@
+endif
+
+und-uhci.lst: pre-uhci.o
+	echo 'uhci' > $@
+	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+uhci_mod-bus_usb_uhci.o: bus/usb/uhci.c $(bus/usb/uhci.c_DEPENDENCIES)
+	$(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(uhci_mod_CFLAGS) -MD -c -o $@ $<
+-include uhci_mod-bus_usb_uhci.d
+
+CLEANFILES += cmd-uhci_mod-bus_usb_uhci.lst fs-uhci_mod-bus_usb_uhci.lst partmap-uhci_mod-bus_usb_uhci.lst
+COMMANDFILES += cmd-uhci_mod-bus_usb_uhci.lst
+FSFILES += fs-uhci_mod-bus_usb_uhci.lst
+PARTMAPFILES += partmap-uhci_mod-bus_usb_uhci.lst
+
+cmd-uhci_mod-bus_usb_uhci.lst: bus/usb/uhci.c $(bus/usb/uhci.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(uhci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh uhci > $@ || (rm -f $@; exit 1)
+
+fs-uhci_mod-bus_usb_uhci.lst: bus/usb/uhci.c $(bus/usb/uhci.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(uhci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh uhci > $@ || (rm -f $@; exit 1)
+
+partmap-uhci_mod-bus_usb_uhci.lst: bus/usb/uhci.c $(bus/usb/uhci.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(uhci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh uhci > $@ || (rm -f $@; exit 1)
+
+
+uhci_mod_CFLAGS = $(COMMON_CFLAGS)
+uhci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For ohci.mod
+ohci_mod_SOURCES = bus/usb/ohci.c
+CLEANFILES += ohci.mod mod-ohci.o mod-ohci.c pre-ohci.o ohci_mod-bus_usb_ohci.o und-ohci.lst
+ifneq ($(ohci_mod_EXPORTS),no)
+CLEANFILES += def-ohci.lst
+DEFSYMFILES += def-ohci.lst
+endif
+MOSTLYCLEANFILES += ohci_mod-bus_usb_ohci.d
+UNDSYMFILES += und-ohci.lst
+
+ohci.mod: pre-ohci.o mod-ohci.o $(TARGET_OBJ2ELF)
+	-rm -f $@
+	$(TARGET_CC) $(ohci_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-ohci.o mod-ohci.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-ohci.o: $(ohci_mod_DEPENDENCIES) ohci_mod-bus_usb_ohci.o
+	-rm -f $@
+	$(TARGET_CC) $(ohci_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ ohci_mod-bus_usb_ohci.o
+
+mod-ohci.o: mod-ohci.c
+	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(ohci_mod_CFLAGS) -c -o $@ $<
+
+mod-ohci.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh 'ohci' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(ohci_mod_EXPORTS),no)
+def-ohci.lst: pre-ohci.o
+	$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 ohci/' > $@
+endif
+
+und-ohci.lst: pre-ohci.o
+	echo 'ohci' > $@
+	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+ohci_mod-bus_usb_ohci.o: bus/usb/ohci.c $(bus/usb/ohci.c_DEPENDENCIES)
+	$(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(ohci_mod_CFLAGS) -MD -c -o $@ $<
+-include ohci_mod-bus_usb_ohci.d
+
+CLEANFILES += cmd-ohci_mod-bus_usb_ohci.lst fs-ohci_mod-bus_usb_ohci.lst partmap-ohci_mod-bus_usb_ohci.lst
+COMMANDFILES += cmd-ohci_mod-bus_usb_ohci.lst
+FSFILES += fs-ohci_mod-bus_usb_ohci.lst
+PARTMAPFILES += partmap-ohci_mod-bus_usb_ohci.lst
+
+cmd-ohci_mod-bus_usb_ohci.lst: bus/usb/ohci.c $(bus/usb/ohci.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(ohci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh ohci > $@ || (rm -f $@; exit 1)
+
+fs-ohci_mod-bus_usb_ohci.lst: bus/usb/ohci.c $(bus/usb/ohci.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(ohci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh ohci > $@ || (rm -f $@; exit 1)
+
+partmap-ohci_mod-bus_usb_ohci.lst: bus/usb/ohci.c $(bus/usb/ohci.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Ibus/usb -I$(srcdir)/bus/usb $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(ohci_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh ohci > $@ || (rm -f $@; exit 1)
+
+
+ohci_mod_CFLAGS = $(COMMON_CFLAGS)
+ohci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For usbms.mod
+usbms_mod_SOURCES = disk/usbms.c
+CLEANFILES += usbms.mod mod-usbms.o mod-usbms.c pre-usbms.o usbms_mod-disk_usbms.o und-usbms.lst
+ifneq ($(usbms_mod_EXPORTS),no)
+CLEANFILES += def-usbms.lst
+DEFSYMFILES += def-usbms.lst
+endif
+MOSTLYCLEANFILES += usbms_mod-disk_usbms.d
+UNDSYMFILES += und-usbms.lst
+
+usbms.mod: pre-usbms.o mod-usbms.o $(TARGET_OBJ2ELF)
+	-rm -f $@
+	$(TARGET_CC) $(usbms_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-usbms.o mod-usbms.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-usbms.o: $(usbms_mod_DEPENDENCIES) usbms_mod-disk_usbms.o
+	-rm -f $@
+	$(TARGET_CC) $(usbms_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ usbms_mod-disk_usbms.o
+
+mod-usbms.o: mod-usbms.c
+	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbms_mod_CFLAGS) -c -o $@ $<
+
+mod-usbms.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh 'usbms' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(usbms_mod_EXPORTS),no)
+def-usbms.lst: pre-usbms.o
+	$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 usbms/' > $@
+endif
+
+und-usbms.lst: pre-usbms.o
+	echo 'usbms' > $@
+	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+usbms_mod-disk_usbms.o: disk/usbms.c $(disk/usbms.c_DEPENDENCIES)
+	$(TARGET_CC) -Idisk -I$(srcdir)/disk $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(usbms_mod_CFLAGS) -MD -c -o $@ $<
+-include usbms_mod-disk_usbms.d
+
+CLEANFILES += cmd-usbms_mod-disk_usbms.lst fs-usbms_mod-disk_usbms.lst partmap-usbms_mod-disk_usbms.lst
+COMMANDFILES += cmd-usbms_mod-disk_usbms.lst
+FSFILES += fs-usbms_mod-disk_usbms.lst
+PARTMAPFILES += partmap-usbms_mod-disk_usbms.lst
+
+cmd-usbms_mod-disk_usbms.lst: disk/usbms.c $(disk/usbms.c_DEPENDENCIES) gencmdlist.sh
+	set -e; 	  $(TARGET_CC) -Idisk -I$(srcdir)/disk $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbms_mod_CFLAGS) -E $< 	  | sh $(srcdir)/gencmdlist.sh usbms > $@ || (rm -f $@; exit 1)
+
+fs-usbms_mod-disk_usbms.lst: disk/usbms.c $(disk/usbms.c_DEPENDENCIES) genfslist.sh
+	set -e; 	  $(TARGET_CC) -Idisk -I$(srcdir)/disk $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbms_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genfslist.sh usbms > $@ || (rm -f $@; exit 1)
+
+partmap-usbms_mod-disk_usbms.lst: disk/usbms.c $(disk/usbms.c_DEPENDENCIES) genpartmaplist.sh
+	set -e; 	  $(TARGET_CC) -Idisk -I$(srcdir)/disk $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usbms_mod_CFLAGS) -E $< 	  | sh $(srcdir)/genpartmaplist.sh usbms > $@ || (rm -f $@; exit 1)
+
+
+usbms_mod_CFLAGS = $(COMMON_CFLAGS)
+usbms_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For pxe.mod
 pxe_mod_SOURCES = fs/i386/pc/pxe.c
 CLEANFILES += pxe.mod mod-pxe.o mod-pxe.c pre-pxe.o pxe_mod-fs_i386_pc_pxe.o und-pxe.lst

Modified: trunk/grub2/conf/i386-pc.rmk
===================================================================
--- trunk/grub2/conf/i386-pc.rmk	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/conf/i386-pc.rmk	2009-02-08 17:58:32 UTC (rev 1982)
@@ -118,7 +118,7 @@
 	commands/search.c commands/blocklist.c commands/hexdump.c	\
 	lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c		\
 	commands/i386/cpuid.c						\
-	disk/host.c disk/loopback.c					\
+	disk/host.c disk/loopback.c disk/scsi.c				\
 	fs/fshelp.c 	\
 	\
 	io/gzio.c							\
@@ -147,8 +147,14 @@
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c		\
 	grub_emu_init.c
 
-grub_emu_LDFLAGS = $(LIBCURSES)
+grub_emu_LDFLAGS = $(LIBCURSES) 
 
+ifeq ($(enable_grub_emu_usb), yes)
+grub_emu_SOURCES += disk/usbms.c util/usb.c bus/usb/usb.c	\
+		commands/usbtest.c
+grub_emu_LDFLAGS += $(LIBCURSES) $(LIBUSB)
+endif
+
 # Scripts.
 sbin_SCRIPTS = grub-install
 bin_SCRIPTS = grub-mkrescue
@@ -165,7 +171,8 @@
 	vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
 	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
-	datehook.mod lsmmap.mod
+	datehook.mod lsmmap.mod \
+	usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -301,6 +308,31 @@
 bsd_mod_CFLAGS = $(COMMON_CFLAGS)
 bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For usb.mod
+usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
+usb_mod_CFLAGS = $(COMMON_CFLAGS)
+usb_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For usbtest.mod
+usbtest_mod_SOURCES = commands/usbtest.c
+usbtest_mod_CFLAGS = $(COMMON_CFLAGS)
+usbtest_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For uhci.mod
+uhci_mod_SOURCES = bus/usb/uhci.c
+uhci_mod_CFLAGS = $(COMMON_CFLAGS)
+uhci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For ohci.mod
+ohci_mod_SOURCES = bus/usb/ohci.c
+ohci_mod_CFLAGS = $(COMMON_CFLAGS)
+ohci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For usbms.mod
+usbms_mod_SOURCES = disk/usbms.c
+usbms_mod_CFLAGS = $(COMMON_CFLAGS)
+usbms_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For pxe.mod
 pxe_mod_SOURCES = fs/i386/pc/pxe.c
 pxe_mod_CFLAGS = $(COMMON_CFLAGS)

Modified: trunk/grub2/config.h.in
===================================================================
--- trunk/grub2/config.h.in	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/config.h.in	2009-02-08 17:58:32 UTC (rev 1982)
@@ -76,6 +76,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <usb.h> header file. */
+#undef HAVE_USB_H
+
 /* Define to 1 if you enable memory manager debugging. */
 #undef MM_DEBUG
 

Modified: trunk/grub2/configure
===================================================================
--- trunk/grub2/configure	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/configure	2009-02-08 17:58:32 UTC (rev 1982)
@@ -700,7 +700,9 @@
 TARGET_LDFLAGS
 MODULE_LDFLAGS
 LIBCURSES
+LIBUSB
 enable_grub_emu
+enable_grub_emu_usb
 enable_grub_fstest
 enable_grub_pe2elf
 FREETYPE
@@ -1303,6 +1305,8 @@
   --enable-lzo            use lzo to compress kernel (default is lzma)
   --enable-mm-debug       include memory manager debugging
   --enable-grub-emu       build and install the `grub-emu' debugging utility
+  --enable-grub-emu-usb   build and install the `grub-emu' debugging utility
+                          with USB support
   --enable-grub-fstest    build and install the `grub-fstest' debugging
                           utility
   --enable-grub-pe2elf    build and install the `grub-pe2elf' conversion
@@ -7832,6 +7836,11 @@
   enableval=$enable_grub_emu;
 fi
 
+# Check whether --enable-grub-emu-usb was given.
+if test "${enable_grub_emu_usb+set}" = set; then
+  enableval=$enable_grub_emu_usb;
+fi
+
 if [ x"$enable_grub_emu" = xyes ]; then
   # Check for curses libraries.
   { echo "$as_me:$LINENO: checking for wgetch in -lncurses" >&5
@@ -8413,9 +8422,235 @@
 
 done
 
+
+  if [ x"$enable_grub_emu_usb" = xyes ]; then
+    # Check for libusb libraries.
+    { echo "$as_me:$LINENO: checking for usb_claim_interface in -lusb" >&5
+echo $ECHO_N "checking for usb_claim_interface in -lusb... $ECHO_C" >&6; }
+if test "${ac_cv_lib_usb_usb_claim_interface+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lusb  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char usb_claim_interface ();
+int
+main ()
+{
+return usb_claim_interface ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_usb_usb_claim_interface=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_usb_usb_claim_interface=no
 fi
 
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_claim_interface" >&5
+echo "${ECHO_T}$ac_cv_lib_usb_usb_claim_interface" >&6; }
+if test $ac_cv_lib_usb_usb_claim_interface = yes; then
+  LIBUSB="-lusb"
+else
+  { { echo "$as_me:$LINENO: error: libusb libraries are required to build \`grub-emu' with USB support" >&5
+echo "$as_me: error: libusb libraries are required to build \`grub-emu' with USB support" >&2;}
+   { (exit 1); exit 1; }; }
+fi
 
+
+
+    # Check for headers.
+
+for ac_header in usb.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to [email protected] ##
+## ------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: libusb header file is required to build \`grub-emu' with USB support" >&5
+echo "$as_me: error: libusb header file is required to build \`grub-emu' with USB support" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+done
+
+  fi
+fi
+
+
+
 # Check whether --enable-grub-fstest was given.
 if test "${enable_grub_fstest+set}" = set; then
   enableval=$enable_grub_fstest;
@@ -9209,7 +9444,9 @@
 TARGET_LDFLAGS!$TARGET_LDFLAGS$ac_delim
 MODULE_LDFLAGS!$MODULE_LDFLAGS$ac_delim
 LIBCURSES!$LIBCURSES$ac_delim
+LIBUSB!$LIBUSB$ac_delim
 enable_grub_emu!$enable_grub_emu$ac_delim
+enable_grub_emu_usb!$enable_grub_emu_usb$ac_delim
 enable_grub_fstest!$enable_grub_fstest$ac_delim
 enable_grub_pe2elf!$enable_grub_pe2elf$ac_delim
 FREETYPE!$FREETYPE$ac_delim
@@ -9220,7 +9457,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 94; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 96; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -9239,7 +9476,7 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF
 cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
 _ACEOF
 sed '
 s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
@@ -9252,8 +9489,6 @@
 ' >>$CONFIG_STATUS <conf$$subs.sed
 rm -f conf$$subs.sed
 cat >>$CONFIG_STATUS <<_ACEOF
-:end
-s/|#_!!_#|//g
 CEOF$ac_eof
 _ACEOF
 
@@ -9501,7 +9736,7 @@
 s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
 s&@INSTALL@&$ac_INSTALL&;t t
 $ac_datarootdir_hack
-" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed 's/|#_!!_#|//g' >$tmp/out
 
 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
   { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&

Modified: trunk/grub2/configure.ac
===================================================================
--- trunk/grub2/configure.ac	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/configure.ac	2009-02-08 17:58:32 UTC (rev 1982)
@@ -382,6 +382,9 @@
 AC_ARG_ENABLE([grub-emu],
 	      [AS_HELP_STRING([--enable-grub-emu],
                              [build and install the `grub-emu' debugging utility])])
+AC_ARG_ENABLE([grub-emu-usb],
+	      [AS_HELP_STRING([--enable-grub-emu-usb],
+                             [build and install the `grub-emu' debugging utility with USB support])])
 [if [ x"$enable_grub_emu" = xyes ]; then
   # Check for curses libraries.]
   AC_CHECK_LIB([ncurses], [wgetch], [LIBCURSES="-lncurses"],
@@ -394,8 +397,20 @@
     [AC_CHECK_HEADERS([ncurses.h], [],
       [AC_CHECK_HEADERS([curses.h], [],
 	[AC_MSG_ERROR([(n)curses header files are required to build `grub-emu'])])])])
+
+  [if [ x"$enable_grub_emu_usb" = xyes ]; then
+    # Check for libusb libraries.]
+    AC_CHECK_LIB([usb], [usb_claim_interface], [LIBUSB="-lusb"],
+      [AC_MSG_ERROR([libusb libraries are required to build `grub-emu' with USB support])])
+    AC_SUBST([LIBUSB])
+
+    [# Check for headers.]
+    AC_CHECK_HEADERS([usb.h], [],
+      [AC_MSG_ERROR([libusb header file is required to build `grub-emu' with USB support])])
+  [fi]
 [fi]
 AC_SUBST([enable_grub_emu])
+AC_SUBST([enable_grub_emu_usb])
 
 AC_ARG_ENABLE([grub-fstest],
 	      [AS_HELP_STRING([--enable-grub-fstest],

Added: trunk/grub2/disk/usbms.c
===================================================================
--- trunk/grub2/disk/usbms.c	                        (rev 0)
+++ trunk/grub2/disk/usbms.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,393 @@
+/* usbms.c - USB Mass Storage Support.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/dl.h>
+#include <grub/mm.h>
+#include <grub/usb.h>
+#include <grub/scsi.h>
+#include <grub/scsicmd.h>
+#include <grub/misc.h>
+
+#define GRUB_USBMS_DIRECTION_BIT	7
+
+/* The USB Mass Storage Command Block Wrapper.  */
+struct grub_usbms_cbw
+{
+  grub_uint32_t signature;
+  grub_uint32_t tag;
+  grub_uint32_t transfer_length;
+  grub_uint8_t flags;
+  grub_uint8_t lun;
+  grub_uint8_t length;
+  grub_uint8_t cbwcb[16];
+} __attribute__ ((packed));
+
+struct grub_usbms_csw
+{
+  grub_uint32_t signature;
+  grub_uint32_t tag;
+  grub_uint32_t residue;
+  grub_uint8_t status;
+} __attribute__ ((packed));
+
+struct grub_usbms_dev
+{
+  struct grub_usb_device *dev;
+
+  int luns;
+
+  int interface;
+  struct grub_usb_desc_endp *in;
+  struct grub_usb_desc_endp *out;
+
+  int in_maxsz;
+  int out_maxsz;
+
+  struct grub_usbms_dev *next;
+};
+typedef struct grub_usbms_dev *grub_usbms_dev_t;
+
+static grub_usbms_dev_t grub_usbms_dev_list;
+
+static int devcnt;
+
+static grub_err_t
+grub_usbms_reset (grub_usb_device_t dev, int interface)
+{
+  return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
+}
+
+static void
+grub_usbms_finddevs (void)
+{
+  auto int usb_iterate (grub_usb_device_t dev);
+
+  int usb_iterate (grub_usb_device_t usbdev)
+    {
+      grub_usb_err_t err;
+      struct grub_usb_desc_device *descdev = &usbdev->descdev;
+      int i;
+
+      if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0)
+	return 0;
+
+      /* XXX: Just check configuration 0 for now.  */
+      for (i = 0; i < usbdev->config[0].descconf->numif; i++)
+	{
+	  struct grub_usbms_dev *usbms;
+	  struct grub_usb_desc_if *interf;
+	  int j;
+	  grub_uint8_t luns;
+
+	  interf = usbdev->config[0].interf[i].descif;
+
+	  /* If this is not a USB Mass Storage device with a supported
+	     protocol, just skip it.  */
+	  if (interf->class != GRUB_USB_CLASS_MASS_STORAGE
+	      || interf->subclass != GRUB_USBMS_SUBCLASS_BULK
+	      || interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
+	    {
+	      continue;
+	    }
+
+	  devcnt++;
+	  usbms = grub_malloc (sizeof (struct grub_usbms_dev));
+	  if (! usbms)
+	    return 1;
+
+	  usbms->dev = usbdev;
+	  usbms->interface = i;
+	  usbms->in = NULL;
+	  usbms->out = NULL;
+
+	  /* Iterate over all endpoints of this interface, at least a
+	     IN and OUT bulk endpoint are required.  */
+	  for (j = 0; j < interf->endpointcnt; j++)
+	    {
+	      struct grub_usb_desc_endp *endp;
+	      endp = &usbdev->config[0].interf[i].descendp[j];
+
+	      if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+		{
+		  /* Bulk IN endpoint.  */
+		  usbms->in = endp;
+		  grub_usb_clear_halt (usbdev, endp->endp_addr & 128);
+		  usbms->in_maxsz = endp->maxpacket;
+		}
+	      else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+		{
+		  /* Bulk OUT endpoint.  */
+		  usbms->out = endp;
+		  grub_usb_clear_halt (usbdev, endp->endp_addr & 128);
+		  usbms->out_maxsz = endp->maxpacket;
+		}
+	    }
+
+	  if (!usbms->in || !usbms->out)
+	    {
+	      grub_free (usbms);
+	      return 0;
+	    }
+
+	  /* Query the amount of LUNs.  */
+	  err = grub_usb_control_msg (usbdev, 0xA1, 254,
+				      0, i, 1, (char *) &luns);
+	  if (err)
+	    {
+	      /* In case of a stall, clear the stall.  */
+	      if (err == GRUB_USB_ERR_STALL)
+		{
+		  grub_usb_clear_halt (usbdev, usbms->in->endp_addr & 3);
+		  grub_usb_clear_halt (usbdev, usbms->out->endp_addr & 3);
+		}
+
+	      /* Just set the amount of LUNs to one.  */
+	      grub_errno = GRUB_ERR_NONE;
+	      usbms->luns = 1;
+	    }
+	  else
+	    usbms->luns = luns;
+
+	  /* XXX: Check the magic values, does this really make
+	     sense?  */
+	  grub_usb_control_msg (usbdev, (1 << 6) | 1, 255,
+				0, i, 0, 0);
+
+	  /* XXX: To make Qemu work?  */
+	  if (usbms->luns == 0)
+	    usbms->luns = 1;
+
+	  usbms->next = grub_usbms_dev_list;
+	  grub_usbms_dev_list = usbms;
+
+	  /* XXX: Activate the first configuration.  */
+	  grub_usb_set_configuration (usbdev, 1);
+
+	  /* Bolk-Only Mass Storage Reset, after the reset commands
+	     will be accepted.  */
+	  grub_usbms_reset (usbdev, i);
+
+	  return 0;
+	}
+
+      return 0;
+    }
+
+  grub_usb_iterate (usb_iterate);
+}
+
+
+
+static int
+grub_usbms_iterate (int (*hook) (const char *name, int luns))
+{
+  grub_usbms_dev_t p;
+  int cnt = 0;
+
+  for (p = grub_usbms_dev_list; p; p = p->next)
+    {
+      char devname[20];
+      grub_sprintf (devname, "usb%d", cnt);
+
+      if (hook (devname, p->luns))
+	return 1;
+      cnt++;
+    }
+
+  return 0;
+}
+
+static grub_err_t
+grub_usbms_tranfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+		    grub_size_t size, char *buf, int read_write)
+{
+  struct grub_usbms_cbw cbw;
+  grub_usbms_dev_t dev = (grub_usbms_dev_t) scsi->data;
+  struct grub_usbms_csw status;
+  static grub_uint32_t tag = 0;
+  grub_usb_err_t err;
+  int retrycnt = 3;
+
+ retry:
+  if (retrycnt == 0)
+    return err;
+
+  /* Setup the request.  */
+  grub_memset (&cbw, 0, sizeof (cbw));
+  cbw.signature = grub_cpu_to_le32 (0x43425355);
+  cbw.tag = tag++;
+  cbw.transfer_length = grub_cpu_to_le32 (size);
+  cbw.flags = (!read_write) << GRUB_USBMS_DIRECTION_BIT;
+  cbw.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+  cbw.length = cmdsize;
+  grub_memcpy (cbw.cbwcb, cmd, cmdsize);
+
+  /* Write the request.  */
+  err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr & 15,
+			     sizeof (cbw), (char *) &cbw);
+  if (err)
+    {
+      if (err == GRUB_USB_ERR_STALL)
+	{
+	  grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+	  goto retry;
+	}
+      return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed");;
+    }
+
+  /* Read/write the data.  */
+  if (read_write == 0)
+    {
+      err = grub_usb_bulk_read (dev->dev, dev->in->endp_addr & 15, size, buf);
+      grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL);
+      if (err)
+	{
+	  if (err == GRUB_USB_ERR_STALL)
+	    {
+	      grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+	      goto retry;
+	    }
+	  return grub_error (GRUB_ERR_READ_ERROR,
+			     "can't read from USB Mass Storage device");
+	}
+    }
+  else 
+    {
+      err = grub_usb_bulk_write (dev->dev, dev->in->endp_addr & 15, size, buf);
+      grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
+      if (err)
+	{
+	  if (err == GRUB_USB_ERR_STALL)
+	    {
+	      grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+	      goto retry;
+	    }
+	  return grub_error (GRUB_ERR_WRITE_ERROR,
+			     "can't write to USB Mass Storage device");
+	}
+    }
+
+  /* Read the status.  */
+  err = grub_usb_bulk_read (dev->dev, dev->in->endp_addr & 15,
+			    sizeof (status), (char *) &status);
+  if (err)
+    {
+      if (err == GRUB_USB_ERR_STALL)
+	{
+	  grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+	  goto retry;
+	}
+      return grub_error (GRUB_ERR_READ_ERROR,
+			 "can't read status from USB Mass Storage device");
+    }
+
+  /* XXX: Magic and check this code.  */
+  if (status.status == 2)
+    {
+      /* XXX: Phase error, reset device.  */
+      grub_usbms_reset (dev->dev, dev->interface);
+      grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+      grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+
+      retrycnt--;
+      if (retrycnt)
+	goto retry;
+    }
+
+  if (status.status)
+    return grub_error (GRUB_ERR_READ_ERROR,
+		       "error communication with USB Mass Storage device");
+
+  return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_usbms_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+		 grub_size_t size, char *buf)
+{
+  return grub_usbms_tranfer (scsi, cmdsize, cmd, size, buf, 0);
+}
+
+static grub_err_t
+grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+		  grub_size_t size, char *buf)
+{
+  return grub_usbms_tranfer (scsi, cmdsize, cmd, size, buf, 1);
+}
+
+static grub_err_t
+grub_usbms_open (const char *name, struct grub_scsi *scsi)
+{
+  grub_usbms_dev_t p;
+  int devnum;
+  int i = 0;
+
+  if (grub_strncmp (name, "usb", 3))
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+		       "not a USB Mass Storage device");
+
+  devnum = grub_strtoul (name + 3, NULL, 10);
+  for (p = grub_usbms_dev_list; p; p = p->next)
+    {
+      /* Check if this is the devnumth device.  */
+      if (devnum == i)
+	{
+	  scsi->data = p;
+	  scsi->name = grub_strdup (name);
+	  scsi->luns = p->luns;
+	  if (! scsi->name)
+	    return grub_errno;
+
+	  return GRUB_ERR_NONE;
+	}
+
+      i++;
+    }
+
+  return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+		     "not a USB Mass Storage device");
+}
+
+static void
+grub_usbms_close (struct grub_scsi *scsi)
+{
+  grub_free (scsi->name);
+}
+
+static struct grub_scsi_dev grub_usbms_dev =
+  {
+    .name = "usb",
+    .iterate = grub_usbms_iterate,
+    .open = grub_usbms_open,
+    .close = grub_usbms_close,
+    .read = grub_usbms_read,
+    .write = grub_usbms_write
+  }; 
+
+GRUB_MOD_INIT(usbms)
+{
+  grub_usbms_finddevs ();
+  grub_scsi_dev_register (&grub_usbms_dev);
+}
+
+GRUB_MOD_FINI(usbms)
+{
+  grub_scsi_dev_unregister (&grub_usbms_dev);
+}

Modified: trunk/grub2/include/grub/err.h
===================================================================
--- trunk/grub2/include/grub/err.h	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/include/grub/err.h	2009-02-08 17:58:32 UTC (rev 1982)
@@ -52,7 +52,8 @@
     GRUB_ERR_SYMLINK_LOOP,
     GRUB_ERR_BAD_GZIP_DATA,
     GRUB_ERR_MENU,
-    GRUB_ERR_TIMEOUT
+    GRUB_ERR_TIMEOUT,
+    GRUB_ERR_IO
   }
 grub_err_t;
 

Added: trunk/grub2/include/grub/usb.h
===================================================================
--- trunk/grub2/include/grub/usb.h	                        (rev 0)
+++ trunk/grub2/include/grub/usb.h	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,207 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#ifndef	GRUB_USB_H
+#define	GRUB_USB_H	1
+
+#include <grub/usbdesc.h>
+#include <grub/usbtrans.h>
+
+typedef struct grub_usb_device *grub_usb_device_t;
+typedef struct grub_usb_controller *grub_usb_controller_t;
+typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t;
+
+typedef enum
+  {
+    GRUB_USB_ERR_NONE,
+    GRUB_USB_ERR_INTERNAL,
+    GRUB_USB_ERR_STALL,
+    GRUB_USB_ERR_DATA,
+    GRUB_USB_ERR_NAK,
+    GRUB_USB_ERR_BABBLE,
+    GRUB_USB_ERR_TIMEOUT,
+    GRUB_USB_ERR_BITSTUFF
+  } grub_usb_err_t;
+
+typedef enum
+  {
+    GRUB_USB_SPEED_NONE,
+    GRUB_USB_SPEED_LOW,
+    GRUB_USB_SPEED_FULL,
+    GRUB_USB_SPEED_HIGH
+  } grub_usb_speed_t;
+
+/* Call HOOK with each device, until HOOK returns non-zero.  */
+int grub_usb_iterate (int (*hook) (grub_usb_device_t dev));
+
+grub_usb_err_t grub_usb_device_initialize (grub_usb_device_t dev);
+
+grub_usb_err_t grub_usb_get_descriptor (grub_usb_device_t dev,
+					grub_uint8_t type, grub_uint8_t index,
+					grub_size_t size, char *data);
+
+struct grub_usb_desc_endp *
+grub_usb_get_endpdescriptor (grub_usb_device_t usbdev, int addr);
+
+grub_usb_err_t grub_usb_clear_halt (grub_usb_device_t dev, int endpoint);
+
+
+grub_usb_err_t grub_usb_set_configuration (grub_usb_device_t dev,
+					   int configuration);
+
+grub_usb_err_t grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index,
+				    int langid, char **string);
+
+void grub_usb_controller_dev_register (grub_usb_controller_dev_t usb);
+
+void grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb);
+
+int grub_usb_controller_iterate (int (*hook) (grub_usb_controller_t dev));
+
+
+grub_usb_err_t grub_usb_control_msg (grub_usb_device_t dev, grub_uint8_t reqtype,
+				     grub_uint8_t request, grub_uint16_t value,
+				     grub_uint16_t index, grub_size_t size,
+				     char *data);
+
+grub_usb_err_t
+grub_usb_bulk_read (grub_usb_device_t dev,
+		    int endpoint, grub_size_t size, char *data);
+grub_usb_err_t
+grub_usb_bulk_write (grub_usb_device_t dev,
+		     int endpoint, grub_size_t size, char *data);
+
+grub_usb_err_t
+grub_usb_root_hub (grub_usb_controller_t controller);
+
+
+/* XXX: All handled by libusb for now.  */
+struct grub_usb_controller_dev
+{
+  /* The device name.  */
+  const char *name;
+
+  int (*iterate) (int (*hook) (grub_usb_controller_t dev));
+
+  grub_usb_err_t (*transfer) (grub_usb_controller_t dev,
+			      grub_usb_transfer_t transfer);
+
+  int (*hubports) (grub_usb_controller_t dev);
+
+  grub_err_t (*portstatus) (grub_usb_controller_t dev, unsigned int port,
+			    unsigned int enable);
+
+  grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port);
+
+  /* The next host controller.  */
+  struct grub_usb_controller_dev *next;
+};
+
+struct grub_usb_controller
+{
+  /* The underlying USB Host Controller device.  */
+  grub_usb_controller_dev_t dev;
+
+  /* Data used by the USB Host Controller Driver.  */
+  void *data;
+};
+
+
+struct grub_usb_interface
+{
+  struct grub_usb_desc_if *descif;
+
+  struct grub_usb_desc_endp *descendp;
+};
+
+struct grub_usb_configuration
+{
+  /* Configuration descriptors .  */
+  struct grub_usb_desc_config *descconf;
+
+  /* Interfaces associated to this configuration.  */
+  struct grub_usb_interface interf[32];
+};
+
+struct grub_usb_device
+{
+  /* The device descriptor of this device.  */
+  struct grub_usb_desc_device descdev;
+
+  /* The controller the device is connected to.  */
+  struct grub_usb_controller controller;
+
+  /* Device configurations (after opening the device).  */
+  struct grub_usb_configuration config[8];
+
+  /* Device address.  */
+  int addr;
+
+  /* Device speed.  */
+  grub_usb_speed_t speed;
+
+  /* All desciptors are read if this is set to 1.  */
+  int initialized;
+
+  /* Data toggle values (used for bulk transfers only).  */
+  int toggle[16];
+
+  /* Device-specific data.  */
+  void *data;
+};
+
+
+
+typedef enum
+  {
+    GRUB_USB_CLASS_NOTHERE,
+    GRUB_USB_CLASS_AUDIO,
+    GRUB_USB_CLASS_COMMUNICATION,
+    GRUB_USB_CLASS_HID,
+    GRUB_USB_CLASS_XXX,
+    GRUB_USB_CLASS_PHYSICAL,
+    GRUB_USB_CLASS_IMAGE,
+    GRUB_USB_CLASS_PRINTER,
+    GRUB_USB_CLASS_MASS_STORAGE,
+    GRUB_USB_CLASS_HUB,
+    GRUB_USB_CLASS_DATA_INTERFACE,
+    GRUB_USB_CLASS_SMART_CARD,
+    GRUB_USB_CLASS_CONTENT_SECURITY,
+    GRUB_USB_CLASS_VIDEO
+  } grub_usb_classes_t;
+
+typedef enum
+  {
+    GRUB_USBMS_SUBCLASS_BULK = 0x06
+  } grub_usbms_subclass_t;
+
+typedef enum
+  {
+    GRUB_USBMS_PROTOCOL_BULK = 0x50
+  } grub_usbms_protocol_t;
+
+static inline struct grub_usb_desc_if *
+grub_usb_get_config_interface (struct grub_usb_desc_config *config)
+{
+  struct grub_usb_desc_if *interf;
+
+  interf = (struct grub_usb_desc_if *) (sizeof (*config) + (char *) config);
+  return interf;
+}
+
+#endif /* GRUB_USB_H */

Added: trunk/grub2/include/grub/usbdesc.h
===================================================================
--- trunk/grub2/include/grub/usbdesc.h	                        (rev 0)
+++ trunk/grub2/include/grub/usbdesc.h	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,119 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#ifndef	GRUB_USBDESC_H
+#define	GRUB_USBDESC_H	1
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+
+typedef enum {
+  GRUB_USB_DESCRIPTOR_DEVICE = 1,
+  GRUB_USB_DESCRIPTOR_CONFIG,
+  GRUB_USB_DESCRIPTOR_STRING,
+  GRUB_USB_DESCRIPTOR_INTERFACE,
+  GRUB_USB_DESCRIPTOR_ENDPOINT,
+  GRUB_USB_DESCRIPTOR_HUB = 0x29
+} grub_usb_descriptor_t;
+
+struct grub_usb_desc_device
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint16_t usbrel;
+  grub_uint8_t class;
+  grub_uint8_t subclass;
+  grub_uint8_t protocol;
+  grub_uint8_t maxsize0;
+  grub_uint16_t vendorid;
+  grub_uint16_t prodid;
+  grub_uint16_t devrel;
+  grub_uint8_t strvendor;
+  grub_uint8_t strprod;
+  grub_uint8_t strserial;
+  grub_uint8_t configcnt;  
+} __attribute__ ((packed));
+
+struct grub_usb_desc_config
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint16_t totallen;
+  grub_uint8_t numif;
+  grub_uint8_t config;
+  grub_uint8_t strconfig;
+  grub_uint8_t attrib;
+  grub_uint8_t maxpower;
+} __attribute__ ((packed));
+
+#if 0
+struct grub_usb_desc_ifassosiation
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint8_t firstif;
+  grub_uint8_t ifcnt;
+  grub_uint8_t class;
+  grub_uint8_t subclass;
+  grub_uint8_t protocol;
+  grub_uint8_t function;
+} __attribute__ ((packed));
+#endif
+
+struct grub_usb_desc_if
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint8_t ifnum;
+  grub_uint8_t altsetting;
+  grub_uint8_t endpointcnt;
+  grub_uint8_t class;
+  grub_uint8_t subclass;
+  grub_uint8_t protocol;
+  grub_uint8_t strif;
+} __attribute__ ((packed));
+
+struct grub_usb_desc_endp
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint8_t endp_addr;
+  grub_uint8_t attrib;
+  grub_uint16_t maxpacket;
+  grub_uint8_t interval;
+} __attribute__ ((packed));
+
+struct grub_usb_desc_str
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint16_t str[0];
+} __attribute__ ((packed));
+
+struct grub_usb_usb_hubdesc
+{
+  grub_uint8_t length;
+  grub_uint8_t type;
+  grub_uint8_t portcnt;
+  grub_uint16_t characteristics;
+  grub_uint8_t pwdgood;
+  grub_uint8_t current;
+  /* Removable and power control bits follow.  */
+} __attribute__ ((packed));
+
+#endif /* GRUB_USBDESC_H */

Added: trunk/grub2/include/grub/usbtrans.h
===================================================================
--- trunk/grub2/include/grub/usbtrans.h	                        (rev 0)
+++ trunk/grub2/include/grub/usbtrans.h	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,107 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#ifndef	GRUB_USBTRANS_H
+#define	GRUB_USBTRANS_H	1
+
+typedef enum
+  {
+    GRUB_USB_TRANSFER_TYPE_IN,
+    GRUB_USB_TRANSFER_TYPE_OUT,
+    GRUB_USB_TRANSFER_TYPE_SETUP
+  } grub_transfer_type_t;
+
+typedef enum
+  {
+    GRUB_USB_TRANSACTION_TYPE_CONTROL,
+    GRUB_USB_TRANSACTION_TYPE_BULK
+  } grub_transaction_type_t;
+
+struct grub_usb_transaction
+{
+  int size;
+  int toggle;
+  grub_transfer_type_t pid;
+  char *data;
+};
+typedef struct grub_usb_transaction *grub_usb_transaction_t;
+
+struct grub_usb_transfer
+{
+  int devaddr;
+
+  int endpoint;
+
+  int size;
+
+  int transcnt;
+
+  int max;
+
+  grub_transaction_type_t type;
+
+  struct grub_usb_device *dev;
+
+  struct grub_usb_transaction *transactions;
+};
+typedef struct grub_usb_transfer *grub_usb_transfer_t;
+
+
+#define GRUB_USB_REQTYPE_IN		(1 << 7)
+#define GRUB_USB_REQTYPE_OUT		(0 << 7)
+#define GRUB_USB_REQTYPE_STANDARD	(0 << 5)
+#define GRUB_USB_REQTYPE_CLASS		(1 << 5)
+#define GRUB_USB_REQTYPE_VENDOR		(2 << 5)
+#define GRUB_USB_REQTYPE_TARGET_DEV	(0 << 0)
+#define GRUB_USB_REQTYPE_TARGET_INTERF	(1 << 0)
+#define GRUB_USB_REQTYPE_TARGET_ENDP	(2 << 0)
+#define GRUB_USB_REQTYPE_TARGET_OTHER	(3 << 0)
+
+#define GRUB_USB_REQ_GET_STATUS		0x00
+#define GRUB_USB_REQ_CLEAR_FEATURE	0x01
+#define GRUB_USB_REQ_SET_FEATURE	0x03
+#define GRUB_USB_REQ_SET_ADDRESS	0x05
+#define GRUB_USB_REQ_GET_DESCRIPTOR	0x06
+#define GRUB_USB_REQ_SET_DESCRIPTOR	0x07
+#define GRUB_USB_REQ_GET_CONFIGURATION	0x08
+#define GRUB_USB_REQ_SET_CONFIGURATION	0x09
+#define GRUB_USB_REQ_GET_INTERFACE	0x0A
+#define GRUB_USB_REQ_SET_INTERFACE	0x0B
+#define GRUB_USB_REQ_SYNC_FRAME		0x0C
+
+#define GRUB_USB_REQ_HUB_GET_PORT_STATUS 0x00
+
+#define GRUB_USB_FEATURE_ENDP_HALT	0x01
+#define GRUB_USB_FEATURE_DEV_REMOTE_WU	0x02
+#define GRUB_USB_FEATURE_TEST_MODE	0x04
+
+#define GRUB_USB_HUB_STATUS_CONNECTED	(1 << 0)
+#define GRUB_USB_HUB_STATUS_LOWSPEED	(1 << 9)
+#define GRUB_USB_HUB_STATUS_HIGHSPEED	(1 << 10)
+
+struct grub_usb_packet_setup
+{
+  grub_uint8_t reqtype;
+  grub_uint8_t request;
+  grub_uint16_t value;
+  grub_uint16_t index;
+  grub_uint16_t length;
+} __attribute__((packed));
+
+
+#endif /* GRUB_USBTRANS_H */

Modified: trunk/grub2/util/grub-emu.c
===================================================================
--- trunk/grub2/util/grub-emu.c	2009-02-08 10:52:03 UTC (rev 1981)
+++ trunk/grub2/util/grub-emu.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -187,6 +187,10 @@
   /* XXX: This is a bit unportable.  */
   grub_util_biosdisk_init (dev_map);
 
+#if HAVE_USB_H
+  grub_libusb_init ();
+#endif
+
   grub_init_all ();
 
   /* Make sure that there is a root device.  */

Added: trunk/grub2/util/usb.c
===================================================================
--- trunk/grub2/util/usb.c	                        (rev 0)
+++ trunk/grub2/util/usb.c	2009-02-08 17:58:32 UTC (rev 1982)
@@ -0,0 +1,191 @@
+/*  usb.c -- libusb USB support for GRUB.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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 <config.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <usb.h>
+#include <grub/usb.h>
+#include <grub/dl.h>
+
+
+static struct grub_usb_controller_dev usb_controller =
+{
+  .name = "libusb"
+};
+
+static struct grub_usb_device *grub_usb_devs[128];
+
+struct usb_bus *busses;
+
+static grub_err_t
+grub_libusb_devices (void)
+
+{
+  struct usb_bus *bus;
+  int last = 0;
+
+  busses = usb_get_busses();
+
+  for (bus = busses; bus; bus = bus->next)
+    {
+      struct usb_device *usbdev;
+      struct grub_usb_device *dev;
+
+      for (usbdev = bus->devices; usbdev; usbdev = usbdev->next)
+	{
+	  struct usb_device_descriptor *desc = &usbdev->descriptor;
+
+	  if (! desc->bcdUSB)
+	    continue;
+
+	  dev = grub_malloc (sizeof (*dev));
+	  if (! dev)
+	    return grub_errno;
+
+	  dev->data = usbdev;
+
+	  /* Fill in all descriptors.  */
+	  grub_usb_device_initialize (dev);
+
+	  /* Register the device.  */
+	  grub_usb_devs[last++] = dev;
+	}
+    }
+
+  return GRUB_USB_ERR_NONE;
+}
+
+grub_err_t
+grub_libusb_init (void)
+{
+  usb_init();
+  usb_find_busses();
+  usb_find_devices();
+
+  if (grub_libusb_devices ())
+    return grub_errno;
+
+  grub_usb_controller_dev_register (&usb_controller);  
+
+  return 0;
+}
+
+grub_err_t
+grub_libusb_fini (void)
+{
+  return 0;
+}
+
+
+int
+grub_usb_iterate (int (*hook) (grub_usb_device_t dev))
+{
+  int i;
+
+  for (i = 0; i < 128; i++)
+    {
+      if (grub_usb_devs[i])
+	{
+	  if (hook (grub_usb_devs[i]))
+	      return 1;
+	}
+    }
+
+  return 0;
+}
+
+grub_usb_err_t
+grub_usb_root_hub (grub_usb_controller_t controller __attribute__((unused)))
+{
+  return GRUB_USB_ERR_NONE;
+}
+
+grub_usb_err_t
+grub_usb_control_msg (grub_usb_device_t dev, grub_uint8_t reqtype,
+		      grub_uint8_t request, grub_uint16_t value,
+		      grub_uint16_t index, grub_size_t size, char *data)
+{
+  usb_dev_handle *devh;
+  struct usb_device *d = dev->data;
+
+  devh = usb_open (d);
+  if (usb_control_msg (devh, reqtype, request,
+		       value, index, data, size, 20) < 0)
+    {
+      usb_close (devh);
+      return GRUB_USB_ERR_STALL;
+    }
+
+  usb_close (devh);
+
+  return GRUB_USB_ERR_NONE;
+}
+
+grub_usb_err_t
+grub_usb_bulk_read (grub_usb_device_t dev,
+		    int endpoint, grub_size_t size, char *data)
+{
+  usb_dev_handle *devh;
+  struct usb_device *d = dev->data;
+
+  devh = usb_open (d);
+  if (usb_claim_interface (devh, 0) < 1)
+    {
+      usb_close (devh);
+      return GRUB_USB_ERR_STALL;
+    }
+
+  if (usb_bulk_read (devh, endpoint, data, size, 20) < 1)
+    {
+      usb_close (devh);
+      return GRUB_USB_ERR_STALL;
+    }
+
+  usb_release_interface (devh, 0);
+  usb_close (devh);
+
+  return GRUB_USB_ERR_NONE;
+}
+
+grub_usb_err_t
+grub_usb_bulk_write (grub_usb_device_t dev,
+		     int endpoint, grub_size_t size, char *data)
+{
+  usb_dev_handle *devh;
+  struct usb_device *d = dev->data;
+
+  devh = usb_open (d);
+  if (usb_claim_interface (devh, 0) < 0)
+    goto fail;
+
+  if (usb_bulk_write (devh, endpoint, data, size, 20) < 0)
+    goto fail;
+
+  if (usb_release_interface (devh, 0) < 0)
+    goto fail;
+
+  usb_close (devh);
+
+  return GRUB_USB_ERR_NONE;
+
+ fail:
+  usb_close (devh);
+  return GRUB_USB_ERR_STALL;
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.