On Wed, Jul 15, 2009 at 10:51 PM, Vladimir 'phcoder'
Serbinenko<phco...@gmail.com> wrote:
> Hello, some BIOSes don't conform semaphore specification about handing
> over the control on UHCI and/or EHCI controller. Most OS cope with it
> by taking ownership regardless after some timeout. This however
> increases booting time. Also some OSes don't cope with this quirk
> correctly and are unable to access some devices. Here is a module to
> forcibly remove BIOS ownership without timeout. It adds 2 commands:
> ehcireste and uhcireset. I choose to name both functions analogously
> even if actually only UHCI is really reset
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>
> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
diff --git a/ChangeLog b/ChangeLog
index fd9b9e4..28ef356 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2009-07-15  Vladimir Serbinenko  <phco...@gmail.com>
+
+       Reset USB controller
+
+       * commands/usbreset.c: new file
+       * conf/i386-pc.rmk (pkglib_MODULES): add usbreset.mod
+       (usbreset_mod_SOURCES): new variable
+       (usbreset_mod_CFLAGS): likewise
+       (usbreset_mod_LFFLAGS): likewise
+
 2009-07-15  Pavel Roskin  <pro...@gnu.org>
 
        * include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_BPB_END):
diff --git a/commands/usbreset.c b/commands/usbreset.c
new file mode 100644
index 0000000..7615e88
--- /dev/null
+++ b/commands/usbreset.c
@@ -0,0 +1,182 @@
+/* usbreset.c - reset usb controllers */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/err.h>
+#include <grub/command.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/loader.h>
+#include <grub/pci.h>
+
+static grub_err_t
+preboot_ehci (int noreturn __attribute__ ((unused)))
+{
+  auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                      grub_pci_id_t pciid);
+
+  int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                 grub_pci_id_t pciid __attribute__ ((unused)))
+  {
+    grub_pci_address_t addr;
+    grub_uint32_t class;
+    grub_uint32_t subclass;
+    grub_uint32_t base;
+    grub_uint32_t eecp;
+
+    addr = grub_pci_make_address (bus, dev, func, 2);
+
+    class = grub_pci_read (addr);
+
+    subclass = (class >> 16) & 0xFF;
+    class >>= 24;
+
+    /* If this is not an EHCI controller, just return.  */
+    if (class != 0x0c || subclass != 0x03 || func != 7)
+      return 0;
+
+    /* Determine IO base address.  */
+    addr = grub_pci_make_address (bus, dev, func, 4);
+    base = grub_pci_read (addr);
+    base &= ~0xff;
+
+    eecp = *((grub_uint8_t *) (base + 9));
+
+    if (! eecp)
+      return 0;
+
+    addr = grub_pci_make_address (bus, dev, func, 0);
+    grub_pci_write_byte (addr + eecp + 3, 1);
+    grub_pci_write_byte (addr + eecp + 2, 0);
+    grub_pci_write_byte (addr + eecp + 4, 0);
+    grub_pci_write_byte (addr + eecp + 5, 0);
+
+    return 0;
+  }
+
+  grub_pci_iterate (find_card);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+preboot_uhci (int noreturn __attribute__ ((unused)))
+{
+  auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                      grub_pci_id_t pciid);
+
+  int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                 grub_pci_id_t pciid __attribute__ ((unused)))
+  {
+    grub_pci_address_t addr;
+    grub_uint32_t class;
+    grub_uint32_t subclass;
+    grub_uint32_t base;
+
+    addr = grub_pci_make_address (bus, dev, func, 2);
+
+    class = grub_pci_read (addr);
+
+    subclass = (class >> 16) & 0xFF;
+    class >>= 24;
+
+    /* If this is not an EHCI controller, just return.  */
+    if (class != 0x0c || subclass != 0x03 || func == 7)
+      return 0;
+
+    /* Determine IO base address.  */
+    addr = grub_pci_make_address (bus, dev, func, 8);
+    base = grub_pci_read (addr);
+    base = (base >> 5) & 0x7ff;
+
+    addr = grub_pci_make_address (bus, dev, func, 0x30);
+
+    grub_pci_write_word (addr, 0x8f00);
+
+    grub_outw (base, 0x0002);
+    grub_millisleep (10);
+    grub_outw (base + 4, 0);
+    grub_millisleep (10);
+    grub_outw (base, 0);
+
+    return 0;
+  }
+
+  grub_pci_iterate (find_card);
+
+  return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+preboot_rest (void)
+{
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_ehcireset (grub_command_t cmd __attribute__ ((unused)),
+                   int argc __attribute__ ((unused)),
+                   char *args[] __attribute__ ((unused)))
+{
+  void *preb_handle;
+  preb_handle
+    = grub_loader_register_preboot_hook (preboot_ehci, preboot_rest, 
+                                        GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE);
+  if (! preb_handle)
+    return grub_errno;
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_uhcireset (grub_command_t cmd __attribute__ ((unused)),
+                   int argc __attribute__ ((unused)),
+                   char *args[] __attribute__ ((unused)))
+{
+  void *preb_handle;
+  preb_handle
+    = grub_loader_register_preboot_hook (preboot_uhci, preboot_rest,
+                                        GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE);
+  if (! preb_handle)
+    return grub_errno;
+  return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_ehcireset, cmd_uhcireset;
+
+GRUB_MOD_INIT(usbreset)
+{
+  (void) mod;                  /* To stop warning. */
+  cmd_ehcireset = grub_register_command ("ehcireset",
+                                        grub_cmd_ehcireset,
+                                        "ehcireset",
+                                        "Reset EHCI controller");
+  cmd_uhcireset = grub_register_command ("uhcireset",
+                                        grub_cmd_uhcireset,
+                                        "uhcireset",
+                                        "Reset UHCI controller");
+}
+
+GRUB_MOD_FINI(usbreset)
+{
+  grub_unregister_command (cmd_ehcireset);
+  grub_unregister_command (cmd_uhcireset);
+}
+
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index f1915b6..53d8510 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -189,7 +189,7 @@ pkglib_MODULES = biosdisk.mod chain.mod \
        aout.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
        datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
        usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \
-       efiemu.mod mmap.mod acpi.mod drivemap.mod
+       efiemu.mod mmap.mod acpi.mod drivemap.mod usbreset.mod
 
 # For boot.mod.
 pkglib_MODULES += boot.mod 
@@ -214,6 +214,11 @@ efiemu_mod_SOURCES = efiemu/main.c 
efiemu/i386/loadcore32.c \
 efiemu_mod_CFLAGS = $(COMMON_CFLAGS)
 efiemu_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For usbreset.mod.
+usbreset_mod_SOURCES = commands/usbreset.c
+usbreset_mod_CFLAGS = $(COMMON_CFLAGS)
+usbreset_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For acpi.mod.
 acpi_mod_SOURCES = commands/acpi.c commands/i386/pc/acpi.c
 acpi_mod_CFLAGS = $(COMMON_CFLAGS)
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to