commit-grub
[Top][All Lists]
Advanced

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

[1982] 2009-02-08 Marco Gerards <address@hidden>


From: Robert Millan
Subject: [1982] 2009-02-08 Marco Gerards <address@hidden>
Date: Sun, 08 Feb 2009 17:58:33 +0000

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  <address@hidden>

        * 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  <address@hidden>
+
+       * 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  <address@hidden>
 
        * 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_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
-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_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
+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_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
+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_emu-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-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-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_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-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 address@hidden ##
+## ------------------------------- ##
+_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;
+}






reply via email to

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