From d64399b562efdc862fc76ed509f8977085138626 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 8 Feb 2009 17:58:32 +0000 Subject: [PATCH] 2009-02-08 Marco Gerards * 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'. --- ChangeLog | 44 +++ DISTLIST | 11 + Makefile.in | 1 + bus/usb/ohci.c | 608 ++++++++++++++++++++++++++++++++++++ bus/usb/uhci.c | 675 ++++++++++++++++++++++++++++++++++++++++ bus/usb/usb.c | 263 ++++++++++++++++ bus/usb/usbhub.c | 193 ++++++++++++ bus/usb/usbtrans.c | 212 +++++++++++++ commands/usbtest.c | 160 ++++++++++ conf/i386-pc.mk | 370 +++++++++++++++++++++- conf/i386-pc.rmk | 38 ++- config.h.in | 3 + configure | 245 ++++++++++++++- configure.ac | 15 + disk/usbms.c | 393 +++++++++++++++++++++++ include/grub/err.h | 3 +- include/grub/usb.h | 207 ++++++++++++ include/grub/usbdesc.h | 119 +++++++ include/grub/usbtrans.h | 107 +++++++ util/grub-emu.c | 4 + util/usb.c | 191 ++++++++++++ 21 files changed, 3846 insertions(+), 16 deletions(-) create mode 100644 bus/usb/ohci.c create mode 100644 bus/usb/uhci.c create mode 100644 bus/usb/usb.c create mode 100644 bus/usb/usbhub.c create mode 100644 bus/usb/usbtrans.c create mode 100644 commands/usbtest.c create mode 100644 disk/usbms.c create mode 100644 include/grub/usb.h create mode 100644 include/grub/usbdesc.h create mode 100644 include/grub/usbtrans.h create mode 100644 util/usb.c diff --git a/ChangeLog b/ChangeLog index 34f5f66a9..f806b40a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +2009-02-08 Marco Gerards + + * 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 * kern/mm.c: Add more comments. diff --git a/DISTLIST b/DISTLIST index d8a181a09..a9e879d18 100644 --- a/DISTLIST +++ b/DISTLIST @@ -35,6 +35,11 @@ boot/i386/pc/diskboot.S 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/search.c 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/raid.c 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/terminfo.h 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/misc.c 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 diff --git a/Makefile.in b/Makefile.in index ea193d8b6..398f92816 100644 --- a/Makefile.in +++ b/Makefile.in @@ -92,6 +92,7 @@ UNIFONT_BDF = @UNIFONT_BDF@ # 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@ diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c new file mode 100644 index 000000000..d2e78d4c9 --- /dev/null +++ b/bus/usb/ohci.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c new file mode 100644 index 000000000..c59c0ca7d --- /dev/null +++ b/bus/usb/uhci.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/bus/usb/usb.c b/bus/usb/usb.c new file mode 100644 index 000000000..a30598f00 --- /dev/null +++ b/bus/usb/usb.c @@ -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 . + */ + +#include +#include +#include +#include + +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; +} diff --git a/bus/usb/usbhub.c b/bus/usb/usbhub.c new file mode 100644 index 000000000..ba0925a33 --- /dev/null +++ b/bus/usb/usbhub.c @@ -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 . + */ + +#include +#include +#include +#include + +/* 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; +} diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c new file mode 100644 index 000000000..8b2d5ad01 --- /dev/null +++ b/bus/usb/usbtrans.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +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); +} diff --git a/commands/usbtest.c b/commands/usbtest.c new file mode 100644 index 000000000..8262b2e64 --- /dev/null +++ b/commands/usbtest.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +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"); +} diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index 63d0b239c..5345475e3 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -525,7 +525,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ 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 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ 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 @@ grub_emu-disk_loopback.o: disk/loopback.c $(disk/loopback.c_DEPENDENCIES) $(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,7 +916,35 @@ grub_emu-grub_emu_init.o: grub_emu_init.c $(grub_emu_init.c_DEPENDENCIES) -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 @@ -942,7 +974,8 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ 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 @@ partmap-bsd_mod-loader_i386_bsd_normal.lst: loader/i386/bsd_normal.c $(loader/i3 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 diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index e7de5e9a7..0b405e306 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -118,7 +118,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ 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,7 +147,13 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ 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 @@ -165,7 +171,8 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ 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_SOURCES = loader/i386/bsd_normal.c 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) diff --git a/config.h.in b/config.h.in index dbd87d992..91e9615f8 100644 --- a/config.h.in +++ b/config.h.in @@ -76,6 +76,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_USB_H + /* Define to 1 if you enable memory manager debugging. */ #undef MM_DEBUG diff --git a/configure b/configure index e1c8c9691..74c400f63 100644 --- a/configure +++ b/configure @@ -700,7 +700,9 @@ TARGET_CPPFLAGS TARGET_LDFLAGS MODULE_LDFLAGS LIBCURSES +LIBUSB enable_grub_emu +enable_grub_emu_usb enable_grub_fstest enable_grub_pe2elf FREETYPE @@ -1303,6 +1305,8 @@ Optional Features: --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 @@ if test "${enable_grub_emu+set}" = set; then 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,8 +8422,234 @@ fi 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 bug-grub@gnu.org ## +## ------------------------------- ## +_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 @@ -9209,7 +9444,9 @@ TARGET_CPPFLAGS!$TARGET_CPPFLAGS$ac_delim 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 @@ LIBOBJS!$LIBOBJS$ac_delim 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 @@ fi 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 @@ N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n ' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF -:end -s/|#_!!_#|//g CEOF$ac_eof _ACEOF @@ -9501,7 +9736,7 @@ s&@abs_builddir@&$ac_abs_builddir&;t t 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"; } && diff --git a/configure.ac b/configure.ac index e563c14df..1df449600 100644 --- a/configure.ac +++ b/configure.ac @@ -382,6 +382,9 @@ AC_ARG_ENABLE([mm-debug], 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_ARG_ENABLE([grub-emu], [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], diff --git a/disk/usbms.c b/disk/usbms.c new file mode 100644 index 000000000..d08256b65 --- /dev/null +++ b/disk/usbms.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/include/grub/err.h b/include/grub/err.h index 50a9ea455..3435fb769 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -52,7 +52,8 @@ typedef enum GRUB_ERR_SYMLINK_LOOP, GRUB_ERR_BAD_GZIP_DATA, GRUB_ERR_MENU, - GRUB_ERR_TIMEOUT + GRUB_ERR_TIMEOUT, + GRUB_ERR_IO } grub_err_t; diff --git a/include/grub/usb.h b/include/grub/usb.h new file mode 100644 index 000000000..9c9e58bcd --- /dev/null +++ b/include/grub/usb.h @@ -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 . + */ + +#ifndef GRUB_USB_H +#define GRUB_USB_H 1 + +#include +#include + +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 */ diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h new file mode 100644 index 000000000..97947dc1b --- /dev/null +++ b/include/grub/usbdesc.h @@ -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 . + */ + +#ifndef GRUB_USBDESC_H +#define GRUB_USBDESC_H 1 + +#include +#include + +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 */ diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h new file mode 100644 index 000000000..7e4a9d7ee --- /dev/null +++ b/include/grub/usbtrans.h @@ -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 . + */ + +#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 */ diff --git a/util/grub-emu.c b/util/grub-emu.c index 4569d9ed9..59392fe35 100644 --- a/util/grub-emu.c +++ b/util/grub-emu.c @@ -187,6 +187,10 @@ main (int argc, char *argv[]) /* 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. */ diff --git a/util/usb.c b/util/usb.c new file mode 100644 index 000000000..744ad86c9 --- /dev/null +++ b/util/usb.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + + +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; +}