merge with mainline

This commit is contained in:
BVK Chaitanya 2010-08-22 21:00:22 +05:30
commit d84666e6bb
37 changed files with 2533 additions and 641 deletions

134
ChangeLog
View file

@ -1,3 +1,137 @@
2010-08-21 Vladimir Serbinenko <phcoder@gmail.com>
* include/grub/usb.h (grub_usb_device): Add 'data' field back. It's
needed by libusb wrapper.
2010-08-21 Samuel Thibault <samuel.thibault@ens-lyon.org>
* docs/grub.texi (GNU/Hurd): Document booting GNU/Hurd.
2010-08-21 Vladimir Serbinenko <phcoder@gmail.com>
* loader/multiboot.c (grub_cmd_module): Don't unzip module if
--nounzip is passed.
2010-08-20 Vladimir Serbinenko <phcoder@gmail.com>
USB hotunplugging and USB serial support.
* bus/usb/ohci.c (grub_ohci_transfer): Fill *actual and respect timeout.
* bus/usb/uhci.c (grub_free_queue): Compute *actual.
(grub_uhci_transfer): Respect timeout and set *actual.
* bus/usb/usb.c (grub_usb_device_initialize): Correctly skip fields of
non-standard length.
(grub_usb_device_attach): Autoload modules.
(GRUB_MOD_INIT): Set grub_term_poll_usb.
(GRUB_MOD_FINI): Unset grub_term_poll_usb.
* bus/usb/usbhub.c (grub_usb_hub): Replace speed with devices. All
users updated.
(grub_usb_add_hub): Fill nports and children.
(attach_root_port): Receive hub instead of controller.
All users updated. Fill hub->devices.
(grub_usb_root_hub): Allocate hub->devices.
(detach_device): New function.
(poll_nonroot_hub): Fill children and detach devices.
* bus/usb/usbtrans.c (grub_usb_bulk_readwrite): Accept timeout and
actual arguments. All users updated.
(grub_usb_bulk_read_extended): New function.
* bus/usb/serial/common.c: New file.
* bus/usb/serial/ftdi.c: Likewise.
* bus/usb/serial/pl2303.c: Likewise.
* commands/terminal.c (handle_command): Support wildcard.
* commands/usbtest.c: Output "Unknown" instead of empty string.
* conf/any-emu.rmk (pkglib_MODULES): Add usbserial_common.mod.
(usbserial_common_mod_SOURCES): New variable.
(usbserial_common_mod_CFLAGS): Likewise.
(usbserial_common_mod_LDFLAGS): Likewise.
(pkglib_MODULES): Add usbserial_pl2303.mod.
(usbserial_pl2303_mod_SOURCES): New variable.
(usbserial_pl2303_mod_CFLAGS): Likewise.
(usbserial_pl2303_mod_LDFLAGS): Likewise.
(pkglib_MODULES): Add usbserial_ftdi.mod.
(usbserial_ftdi_mod_SOURCES): New variable.
(usbserial_ftdi_mod_CFLAGS): Likewise.
(usbserial_ftdi_mod_LDFLAGS): Likewise.
(pkglib_MODULES): Add serial.mod.
(serial_mod_SOURCES): New variable.
(serial_mod_CFLAGS): Likewise.
(serial_mod_LDFLAGS): Likewise.
* conf/i386-pc.rmk: Likewise.
* conf/mips-yeeloong.rmk: Likewise.
* conf/i386.rmk (serial_mod_SOURCES): Add term/ns8250.c.
* conf/mips-yeeloong.rmk (kernel_img_SOURCES): Likewise.
* disk/usbms.c (first_available_slot): New variable.
(grub_usbms_attach): Don't reuse free slots due to potential cache
problems.
* include/grub/serial.h: Moved to ..
* include/grub/ns8250.h: ...this.
* include/grub/serial.h: New file.
* include/grub/term.h (grub_term_poll_usb): New variable.
* include/grub/terminfo.h (grub_terminfo_input_state): Pass term to
readkey. All users updated.
(grub_terminfo_output_state): Pass term to put.
* include/grub/usb.h (GRUB_USB_REQTYPE): New enum.
(grub_usb_controller_dev): Add timeout and actual arguments to
transfer. All users updated.
(grub_usb_interface): New field detach_data.
(grub_usb_device): New fields children and nports.
(grub_usb_ep_type_t): New type.
(grub_usb_get_ep_type): New function.
(grub_usb_bulk_read_extended): Likewise.
* include/grub/usbdesc.h (grub_usb_desc): New type.
* include/grub/usbserial.h: New file.
* include/grub/usbtrans.h (grub_usb_transaction): New field preceding.
* kern/term.c (grub_term_poll_usb): New variable.
(grub_getkey): Call grub_term_poll_usb if set.
(grub_checkkey): Likewise.
(grub_getkeystatus): Likewise.
* term/serial.c: Moved controller-specific parts to ...
* term/ns8250.c: ... here.
* term/serial.c: Mostly rewritten.
* term/usb_keyboard.c: Reorganised to use GET_REPORT only on attaching
according to spec.
2010-08-20 Robert Millan <rmh@gnu.org>
Make kFreeBSD code more generic to support ext2fs as root, ufs as
a separate module and maybe other interesting combinations.
* util/grub.d/10_kfreebsd.in (load_kfreebsd_module): New function.
(kfreebsd_entry): Use load_kfreebsd_module() to load modules.
(kfreebsd_entry): Add generic filesystem module load routine.
Map GRUB `ext2' to kFreeBSD `ext2fs'.
2010-08-20 Colin Watson <cjwatson@ubuntu.com>
* commands/i386/pc/sendkey.c (keysym_table): Rename "numlock" to
"numcenter" (I misunderstood the purpose of this entry).
* docs/grub.texi (sendkey): Likewise.
2010-08-20 Colin Watson <cjwatson@ubuntu.com>
* commands/i386/pc/sendkey.c (options): Remove "keep" from all
status flag options; simply omitting the option is equivalent and
simpler. Rename "wait" to "pause". Rename "sysreq" to "sysrq".
(keysym_table): Rename "num5numlock" to "numlock".
(grub_cmd_sendkey): Reinitialise `andmask' and `ormask', so that we
can uniformly say that only the last of multiple `sendkey'
invocations has any effect.
* docs/grub.texi (sendkey): New section.
2010-08-19 Colin Watson <cjwatson@ubuntu.com>
* commands/i386/pc/sendkey.c (options): Fix three typos.
2010-08-19 Vladimir Serbinenko <phcoder@gmail.com>
Implement sendkey support.
* commands/i386/pc/sendkey.c: New file.
* conf/i386-pc.rmk (pkglib_MODULES): Add sendkey.mod.
(sendkey_mod_SOURCES): New variable.
(sendkey_mod_CFLAGS): Likewise.
(sendkey_mod_LDFLAGS): Likewise.
2010-08-18 Colin Watson <cjwatson@ubuntu.com> 2010-08-18 Colin Watson <cjwatson@ubuntu.com>
* configure.ac: Move AM_INIT_AUTOMAKE after AC_CANONICAL_TARGET to * configure.ac: Move AM_INIT_AUTOMAKE after AC_CANONICAL_TARGET to

View file

@ -31,7 +31,7 @@ endif
# Other options # Other options
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"`echo $< | sed "s@$(top_srcdir)/@@g"`\" CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir),,$<)\"
CPPFLAGS_DEFAULT += -I$(builddir) CPPFLAGS_DEFAULT += -I$(builddir)
CPPFLAGS_DEFAULT += -I$(srcdir) CPPFLAGS_DEFAULT += -I$(srcdir)
CPPFLAGS_DEFAULT += -I$(top_builddir) CPPFLAGS_DEFAULT += -I$(top_builddir)

View file

@ -67,6 +67,30 @@ usbms_mod_SOURCES = disk/usbms.c
usbms_mod_CFLAGS = $(COMMON_CFLAGS) usbms_mod_CFLAGS = $(COMMON_CFLAGS)
usbms_mod_LDFLAGS = $(COMMON_LDFLAGS) usbms_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_common.mod
usbserial_common_mod_SOURCES = bus/usb/serial/common.c
usbserial_common_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_common_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_pl2303.mod
usbserial_pl2303_mod_SOURCES = bus/usb/serial/pl2303.c
usbserial_pl2303_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_pl2303_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_ftdi.mod
usbserial_ftdi_mod_SOURCES = bus/usb/serial/ftdi.c
usbserial_ftdi_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_ftdi_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += serial.mod
serial_mod_SOURCES = term/serial.c
serial_mod_CFLAGS = $(COMMON_CFLAGS)
serial_mod_LDFLAGS = $(COMMON_LDFLAGS)
grub_emu_LDFLAGS += $(LIBUSB) grub_emu_LDFLAGS += $(LIBUSB)
endif endif

View file

@ -195,6 +195,24 @@ usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
usb_mod_CFLAGS = $(COMMON_CFLAGS) usb_mod_CFLAGS = $(COMMON_CFLAGS)
usb_mod_LDFLAGS = $(COMMON_LDFLAGS) usb_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_common.mod
usbserial_common_mod_SOURCES = bus/usb/serial/common.c
usbserial_common_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_common_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_pl2303.mod
usbserial_pl2303_mod_SOURCES = bus/usb/serial/pl2303.c
usbserial_pl2303_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_pl2303_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_ftdi.mod
usbserial_ftdi_mod_SOURCES = bus/usb/serial/ftdi.c
usbserial_ftdi_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_ftdi_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For usbtest.mod # For usbtest.mod
usbtest_mod_SOURCES = commands/usbtest.c usbtest_mod_SOURCES = commands/usbtest.c
usbtest_mod_CFLAGS = $(COMMON_CFLAGS) usbtest_mod_CFLAGS = $(COMMON_CFLAGS)
@ -235,6 +253,12 @@ datetime_mod_SOURCES = lib/cmos_datetime.c
datetime_mod_CFLAGS = $(COMMON_CFLAGS) datetime_mod_CFLAGS = $(COMMON_CFLAGS)
datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For sendkey.mod
pkglib_MODULES += sendkey.mod
sendkey_mod_SOURCES = commands/i386/pc/sendkey.c
sendkey_mod_CFLAGS = $(COMMON_CFLAGS)
sendkey_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For ata_pthru.mod. # For ata_pthru.mod.
ata_pthru_mod_SOURCES = disk/ata_pthru.c ata_pthru_mod_SOURCES = disk/ata_pthru.c
ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS) ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS)

View file

@ -56,7 +56,7 @@ multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS)
# For serial.mod. # For serial.mod.
pkglib_MODULES += serial.mod pkglib_MODULES += serial.mod
serial_mod_SOURCES = term/serial.c serial_mod_SOURCES = term/serial.c term/ns8250.c
serial_mod_CFLAGS = $(COMMON_CFLAGS) serial_mod_CFLAGS = $(COMMON_CFLAGS)
serial_mod_LDFLAGS = $(COMMON_LDFLAGS) serial_mod_LDFLAGS = $(COMMON_LDFLAGS)

View file

@ -5,7 +5,7 @@ COMMON_CFLAGS += -march=mips3
COMMON_ASFLAGS += -march=mips3 COMMON_ASFLAGS += -march=mips3
kernel_img_HEADERS += pci.h bitmap.h video.h gfxterm.h font.h \ kernel_img_HEADERS += pci.h bitmap.h video.h gfxterm.h font.h \
bitmap_scale.h bufio.h cs5536.h machine/pci.h bitmap_scale.h bufio.h cs5536.h machine/pci.h serial.h
include $(srcdir)/conf/mips.mk include $(srcdir)/conf/mips.mk
@ -27,7 +27,7 @@ kernel_img_SOURCES = kern/$(target_cpu)/startup.S \
video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \ video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \
video/bitmap_scale.c video/sm712.c bus/pci.c bus/bonito.c \ video/bitmap_scale.c video/sm712.c bus/pci.c bus/bonito.c \
term/gfxterm.c commands/extcmd.c lib/arg.c \ term/gfxterm.c commands/extcmd.c lib/arg.c \
bus/cs5536.c term/serial.c term/terminfo.c term/tparm.c \ bus/cs5536.c term/serial.c term/ns8250.c term/terminfo.c term/tparm.c \
symlist.c symlist.c
kernel_img_CFLAGS = $(COMMON_CFLAGS) -DUSE_ASCII_FAILBACK kernel_img_CFLAGS = $(COMMON_CFLAGS) -DUSE_ASCII_FAILBACK
kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
@ -97,6 +97,24 @@ usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
usb_mod_CFLAGS = $(COMMON_CFLAGS) usb_mod_CFLAGS = $(COMMON_CFLAGS)
usb_mod_LDFLAGS = $(COMMON_LDFLAGS) usb_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_common.mod
usbserial_common_mod_SOURCES = bus/usb/serial/common.c
usbserial_common_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_common_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_pl2303.mod
usbserial_pl2303_mod_SOURCES = bus/usb/serial/pl2303.c
usbserial_pl2303_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_pl2303_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For serial.mod.
pkglib_MODULES += usbserial_ftdi.mod
usbserial_ftdi_mod_SOURCES = bus/usb/serial/ftdi.c
usbserial_ftdi_mod_CFLAGS = $(COMMON_CFLAGS)
usbserial_ftdi_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For usbtest.mod # For usbtest.mod
pkglib_MODULES += usbtest.mod pkglib_MODULES += usbtest.mod
usbtest_mod_SOURCES = commands/usbtest.c usbtest_mod_SOURCES = commands/usbtest.c

View file

@ -828,11 +828,30 @@ Since GNU/Hurd is Multiboot-compliant, it is easy to boot it; there is
nothing special about it. But do not forget that you have to specify a nothing special about it. But do not forget that you have to specify a
root partition to the kernel. root partition to the kernel.
FIXME: this section is incomplete.
@enumerate @enumerate
@item @item
Run the command @command{boot} (@pxref{boot}). Set GRUB's root device to the same drive as GNU/Hurd's. The command
@code{search --file --set /boot/gnumach.gz} or similar may help you
(@pxref{search}).
@item
Load the kernel and the modules, like this:
@example
@group
grub> @kbd{multiboot /boot/gnumach.gz root=device:hd0s1}
grub> @kbd{module /hurd/ext2fs.static ext2fs --readonly \
--multiboot-command-line='$@{kernel-command-line@}' \
--host-priv-port='$@{host-port@}' \
--device-master-port='$@{device-port@}' \
--exec-server-task='$@{exec-task@}' -T typed '$@{root@}' \
'$(task-create)' '$(task-resume)'}
grub> @kbd{module /lib/ld.so.1 exec /hurd/exec '$(exec-task=task-create)'}
@end group
@end example
@item
Finally, run the command @command{boot} (@pxref{boot}).
@end enumerate @end enumerate
@ -2094,6 +2113,7 @@ you forget a command, you can run the command @command{help}
* pxe_unload:: Unload the PXE environment * pxe_unload:: Unload the PXE environment
* reboot:: Reboot your computer * reboot:: Reboot your computer
* search:: Search devices by file, label, or UUID * search:: Search devices by file, label, or UUID
* sendkey:: Emulate keystrokes
* set:: Set an environment variable * set:: Set an environment variable
* unset:: Unset an environment variable * unset:: Unset an environment variable
* uppermem:: Set the upper memory size * uppermem:: Set the upper memory size
@ -2604,6 +2624,154 @@ commands are aliases for @samp{search --file}, @samp{search --label}, and
@end deffn @end deffn
@node sendkey
@subsection sendkey
@deffn Command sendkey @
[@option{--num}|@option{--caps}|@option{--scroll}|@option{--insert}|@
@option{--pause}|@option{--left-shift}|@option{--right-shift}|@
@option{--sysrq}|@option{--numkey}|@option{--capskey}|@option{--scrollkey}|@
@option{--insertkey}|@option{--left-alt}|@option{--right-alt}|@
@option{--left-ctrl}|@option{--right-ctrl} @
@samp{on}|@samp{off}]@dots{} @
[@option{no-led}] @
keystroke
Insert keystrokes into the keyboard buffer when booting. Sometimes an
operating system or chainloaded boot loader requires particular keys to be
pressed: for example, one might need to press a particular key to enter
"safe mode", or when chainloading another boot loader one might send
keystrokes to it to navigate its menu.
You may provide up to 16 keystrokes (the length of the BIOS keyboard
buffer). Keystroke names may be upper-case or lower-case letters, digits,
or taken from the following table:
@c Please keep this table in the same order as in
@c commands/i386/pc/sendkey.c, for ease of maintenance.
@c Exception: The function and numeric keys are sorted, for aesthetics.
@multitable @columnfractions .4 .5
@headitem Name @tab Key
@item escape @tab Escape
@item exclam @tab !
@item at @tab @@
@item numbersign @tab #
@item dollar @tab $
@item percent @tab %
@item caret @tab ^
@item ampersand @tab &
@item asterisk @tab *
@item parenleft @tab (
@item parenright @tab )
@item minus @tab -
@item underscore @tab _
@item equal @tab =
@item plus @tab +
@item backspace @tab Backspace
@item tab @tab Tab
@item bracketleft @tab [
@item braceleft @tab @{
@item bracketright @tab ]
@item braceright @tab @}
@item enter @tab Enter
@item control @tab press and release Control
@item semicolon @tab ;
@item colon @tab :
@item quote @tab '
@item doublequote @tab "
@item backquote @tab `
@item tilde @tab ~
@item shift @tab press and release left Shift
@item backslash @tab \
@item bar @tab |
@item comma @tab ,
@item less @tab <
@item period @tab .
@item greater @tab >
@item slash @tab /
@item question @tab ?
@item rshift @tab press and release right Shift
@item alt @tab press and release Alt
@item space @tab space bar
@item capslock @tab Caps Lock
@item F1 @tab F1
@item F2 @tab F2
@item F3 @tab F3
@item F4 @tab F4
@item F5 @tab F5
@item F6 @tab F6
@item F7 @tab F7
@item F8 @tab F8
@item F9 @tab F9
@item F10 @tab F10
@item F11 @tab F11
@item F12 @tab F12
@item num1 @tab 1 (numeric keypad)
@item num2 @tab 2 (numeric keypad)
@item num3 @tab 3 (numeric keypad)
@item num4 @tab 4 (numeric keypad)
@item num5 @tab 5 (numeric keypad)
@item num6 @tab 6 (numeric keypad)
@item num7 @tab 7 (numeric keypad)
@item num8 @tab 8 (numeric keypad)
@item num9 @tab 9 (numeric keypad)
@item num0 @tab 0 (numeric keypad)
@item numperiod @tab . (numeric keypad)
@item numend @tab End (numeric keypad)
@item numdown @tab Down (numeric keypad)
@item numpgdown @tab Page Down (numeric keypad)
@item numleft @tab Left (numeric keypad)
@item numcenter @tab 5 with Num Lock inactive (numeric keypad)
@item numright @tab Right (numeric keypad)
@item numhome @tab Home (numeric keypad)
@item numup @tab Up (numeric keypad)
@item numpgup @tab Page Up (numeric keypad)
@item numinsert @tab Insert (numeric keypad)
@item numdelete @tab Delete (numeric keypad)
@item numasterisk @tab * (numeric keypad)
@item numminus @tab - (numeric keypad)
@item numplus @tab + (numeric keypad)
@item numslash @tab / (numeric keypad)
@item numenter @tab Enter (numeric keypad)
@item delete @tab Delete
@item insert @tab Insert
@item home @tab Home
@item end @tab End
@item pgdown @tab Page Down
@item pgup @tab Page Up
@item down @tab Down
@item up @tab Up
@item left @tab Left
@item right @tab Right
@end multitable
As well as keystrokes, the @command{sendkey} command takes various options
that affect the BIOS keyboard status flags. These options take an @samp{on}
or @samp{off} parameter, specifying that the corresponding status flag be
set or unset; omitting the option for a given status flag will leave that
flag at its initial state at boot. The @option{--num}, @option{--caps},
@option{--scroll}, and @option{--insert} options emulate setting the
corresponding mode, while the @option{--numkey}, @option{--capskey},
@option{--scrollkey}, and @option{--insertkey} options emulate pressing and
holding the corresponding key. The other status flag options are
self-explanatory.
If the @option{--no-led} option is given, the status flag options will have
no effect on keyboard LEDs.
If the @command{sendkey} command is given multiple times, then only the last
invocation has any effect.
Since @command{sendkey} manipulates the BIOS keyboard buffer, it may cause
hangs, reboots, or other misbehaviour on some systems. If the operating
system or boot loader that runs after GRUB uses its own keyboard driver
rather than the BIOS keyboard functions, then @command{sendkey} will have no
effect.
This command is only available on PC BIOS systems.
@end deffn
@node set @node set
@subsection set @subsection set

View file

@ -176,6 +176,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h
endif endif
if COND_powerpc_ieee1275 if COND_powerpc_ieee1275

View file

@ -121,6 +121,7 @@ kernel = {
i386_ieee1275 = kern/i386/ieee1275/init.c; i386_ieee1275 = kern/i386/ieee1275/init.c;
i386_ieee1275 = kern/ieee1275/init.c; i386_ieee1275 = kern/ieee1275/init.c;
mips_yeeloong = term/ns8250.c;
mips_yeeloong = bus/bonito.c; mips_yeeloong = bus/bonito.c;
mips_yeeloong = bus/cs5536.c; mips_yeeloong = bus/cs5536.c;
mips_yeeloong = bus/pci.c; mips_yeeloong = bus/pci.c;
@ -309,6 +310,30 @@ module = {
emu_condition = COND_GRUB_EMU_USB; emu_condition = COND_GRUB_EMU_USB;
}; };
module = {
name = usbserial_common;
common = bus/usb/serial/common.c;
enable = emu;
enable = i386_pc;
enable = mips_yeeloong;
};
module = {
name = usbserial_pl2303;
common = bus/usb/serial/pl2303.c;
enable = emu;
enable = i386_pc;
enable = mips_yeeloong;
};
module = {
name = usbserial_ftdi;
common = bus/usb/serial/ftdi.c;
enable = emu;
enable = i386_pc;
enable = mips_yeeloong;
};
module = { module = {
name = uhci; name = uhci;
common = bus/usb/uhci.c; common = bus/usb/uhci.c;
@ -1221,7 +1246,17 @@ module = {
module = { module = {
name = serial; name = serial;
common = term/serial.c; common = term/serial.c;
x86 = term/ns8250.c;
enable = emu;
enable = i386; enable = i386;
enable = x86_64_efi;
};
module = {
name = sendkey;
i386_pc = commands/i386/pc/sendkey.c;
enable = i386_pc;
}; };
module = { module = {

View file

@ -20,7 +20,8 @@
#include <grub/mips/yeeloong/pci.h> #include <grub/mips/yeeloong/pci.h>
#include <grub/mips/loongson.h> #include <grub/mips/loongson.h>
#include <grub/pci.h> #include <grub/pci.h>
#include <grub/serial.h> #include <grub/machine/serial.h>
#include <grub/ns8250.h>
#include <grub/cs5536.h> #include <grub/cs5536.h>
#include <grub/smbus.h> #include <grub/smbus.h>

View file

@ -654,7 +654,8 @@ grub_ohci_transaction (grub_ohci_td_t td,
static grub_usb_err_t static grub_usb_err_t
grub_ohci_transfer (grub_usb_controller_t dev, grub_ohci_transfer (grub_usb_controller_t dev,
grub_usb_transfer_t transfer) grub_usb_transfer_t transfer, int timeout,
grub_size_t *actual)
{ {
struct grub_ohci *o = (struct grub_ohci *) dev->data; struct grub_ohci *o = (struct grub_ohci *) dev->data;
grub_ohci_ed_t ed_virt; grub_ohci_ed_t ed_virt;
@ -680,6 +681,8 @@ grub_ohci_transfer (grub_usb_controller_t dev,
int err_unrec = 0; int err_unrec = 0;
grub_uint32_t intstatus; grub_uint32_t intstatus;
*actual = 0;
/* Pre-set target for ED - we need it to find proper ED */ /* Pre-set target for ED - we need it to find proper ED */
/* Set the device address. */ /* Set the device address. */
target = transfer->devaddr; target = transfer->devaddr;
@ -832,7 +835,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
} }
/* Safety measure to avoid a hang. */ /* Safety measure to avoid a hang. */
maxtime = grub_get_time_ms () + 1000; maxtime = grub_get_time_ms () + timeout;
/* Wait until the transfer is completed or STALLs. */ /* Wait until the transfer is completed or STALLs. */
do do
@ -986,6 +989,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
transfer->last_trans = tderr_virt->tr_index; transfer->last_trans = tderr_virt->tr_index;
else else
transfer->last_trans = -1; transfer->last_trans = -1;
*actual = transfer->size + 1;
} }
else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */ else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */
@ -1032,7 +1036,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
{ {
case 0: case 0:
/* XXX: Should not happen! */ /* XXX: Should not happen! */
grub_error (GRUB_ERR_IO, "OHCI without reporting the reason"); grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason");
err = GRUB_USB_ERR_INTERNAL; err = GRUB_USB_ERR_INTERNAL;
break; break;
@ -1078,12 +1082,14 @@ grub_ohci_transfer (grub_usb_controller_t dev,
case 9: case 9:
/* XXX: Data underrun error. */ /* XXX: Data underrun error. */
err = GRUB_USB_ERR_DATA;
grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",
tderr_virt, tderr_virt->tr_index); tderr_virt, tderr_virt->tr_index);
grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n", if (transfer->last_trans == -1)
1 + grub_le_to_cpu32 (tderr_virt->buffer_end) break;
- grub_le_to_cpu32 (tderr_virt->buffer)); *actual = transfer->transactions[transfer->last_trans].size
- (grub_le_to_cpu32 (tderr_virt->buffer_end)
- grub_le_to_cpu32 (tderr_virt->buffer))
+ transfer->transactions[transfer->last_trans].preceding;
break; break;
case 10: case 10:
@ -1172,12 +1178,10 @@ grub_ohci_transfer (grub_usb_controller_t dev,
transfer->last_trans = tderr_virt->tr_index; transfer->last_trans = tderr_virt->tr_index;
else else
transfer->last_trans = -1; transfer->last_trans = -1;
} }
/* Set empty ED - set HEAD = TAIL = last (not processed) TD */ /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
ed_virt->td_head = grub_cpu_to_le32 ( grub_le_to_cpu32 ( ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf);
ed_virt->td_tail) & ~0xf);
/* At this point always should be: /* At this point always should be:
* ED has skip bit set and halted or empty or after next SOF, * ED has skip bit set and halted or empty or after next SOF,

View file

@ -0,0 +1,125 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/serial.h>
#include <grub/usbserial.h>
void
grub_usbserial_fini (struct grub_serial_port *port)
{
port->usbdev->config[port->configno].interf[port->interfno].detach_hook = 0;
port->usbdev->config[port->configno].interf[port->interfno].attached = 0;
}
void
grub_usbserial_detach (grub_usb_device_t usbdev, int configno, int interfno)
{
static struct grub_serial_port *port;
port = usbdev->config[configno].interf[interfno].detach_data;
grub_serial_unregister (port);
}
static int usbnum = 0;
int
grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
struct grub_serial_driver *driver)
{
struct grub_serial_port *port;
int j;
struct grub_usb_desc_if *interf;
interf = usbdev->config[configno].interf[interfno].descif;
port = grub_malloc (sizeof (*port));
if (!port)
{
grub_print_error ();
return 0;
}
port->name = grub_xasprintf ("usb%d", usbnum++);
if (!port->name)
{
grub_free (port);
grub_print_error ();
return 0;
}
port->usbdev = usbdev;
port->driver = driver;
for (j = 0; j < interf->endpointcnt; j++)
{
struct grub_usb_desc_endp *endp;
endp = &usbdev->config[0].interf[interfno].descendp[j];
if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
{
/* Bulk IN endpoint. */
port->in_endp = endp;
}
else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
{
/* Bulk OUT endpoint. */
port->out_endp = endp;
}
}
if (!port->out_endp || !port->in_endp)
{
grub_free (port->name);
grub_free (port);
return 0;
}
port->configno = configno;
port->interfno = interfno;
grub_serial_config_defaults (port);
grub_serial_register (port);
port->usbdev->config[port->configno].interf[port->interfno].detach_hook
= grub_usbserial_detach;
port->usbdev->config[port->configno].interf[port->interfno].detach_data
= port;
return 1;
}
int
grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size)
{
grub_usb_err_t err;
grub_size_t actual;
if (port->bufstart < port->bufend)
return port->buf[port->bufstart++];
err = grub_usb_bulk_read_extended (port->usbdev, port->in_endp->endp_addr,
sizeof (port->buf), port->buf, 10,
&actual);
if (err != GRUB_USB_ERR_NONE)
return -1;
port->bufstart = header_size;
port->bufend = actual;
if (port->bufstart >= port->bufend)
return -1;
return port->buf[port->bufstart++];
}

View file

@ -0,0 +1,205 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/serial.h>
#include <grub/types.h>
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/usb.h>
#include <grub/usbserial.h>
enum
{
GRUB_FTDI_MODEM_CTRL = 0x01,
GRUB_FTDI_FLOW_CTRL = 0x02,
GRUB_FTDI_SPEED_CTRL = 0x03,
GRUB_FTDI_DATA_CTRL = 0x04
};
#define GRUB_FTDI_MODEM_CTRL_DTRRTS 3
#define GRUB_FTDI_FLOW_CTRL_DTRRTS 3
/* Convert speed to divisor. */
static grub_uint32_t
get_divisor (unsigned int speed)
{
unsigned int i;
/* The structure for speed vs. divisor. */
struct divisor
{
unsigned int speed;
grub_uint32_t div;
};
/* The table which lists common configurations. */
/* Computed with a division formula with 3MHz as base frequency. */
static struct divisor divisor_tab[] =
{
{ 2400, 0x04e2 },
{ 4800, 0x0271 },
{ 9600, 0x4138 },
{ 19200, 0x809c },
{ 38400, 0xc04e },
{ 57600, 0xc034 },
{ 115200, 0x001a }
};
/* Set the baud rate. */
for (i = 0; i < ARRAY_SIZE (divisor_tab); i++)
if (divisor_tab[i].speed == speed)
return divisor_tab[i].div;
return 0;
}
static void
real_config (struct grub_serial_port *port)
{
grub_uint32_t divisor;
const grub_uint16_t parities[] = {
[GRUB_SERIAL_PARITY_NONE] = 0x0000,
[GRUB_SERIAL_PARITY_ODD] = 0x0100,
[GRUB_SERIAL_PARITY_EVEN] = 0x0200
};
const grub_uint16_t stop_bits[] = {
[GRUB_SERIAL_STOP_BITS_1] = 0x0000,
[GRUB_SERIAL_STOP_BITS_2] = 0x1000,
};
if (port->configured)
return;
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_FTDI_MODEM_CTRL,
GRUB_FTDI_MODEM_CTRL_DTRRTS, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_FTDI_FLOW_CTRL,
GRUB_FTDI_FLOW_CTRL_DTRRTS, 0, 0, 0);
divisor = get_divisor (port->config.speed);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_FTDI_SPEED_CTRL,
divisor & 0xffff, divisor >> 16, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_FTDI_DATA_CTRL,
parities[port->config.parity]
| stop_bits[port->config.stop_bits]
| port->config.word_len, 0, 0, 0);
port->configured = 1;
}
/* Fetch a key. */
static int
ftdi_hw_fetch (struct grub_serial_port *port)
{
real_config (port);
return grub_usbserial_fetch (port, 2);
}
/* Put a character. */
static void
ftdi_hw_put (struct grub_serial_port *port, const int c)
{
char cc = c;
real_config (port);
grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
}
static grub_err_t
ftdi_hw_configure (struct grub_serial_port *port,
struct grub_serial_config *config)
{
grub_uint16_t divisor;
divisor = get_divisor (config->speed);
if (divisor == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
if (config->parity != GRUB_SERIAL_PARITY_NONE
&& config->parity != GRUB_SERIAL_PARITY_ODD
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
if (config->word_len < 5 || config->word_len > 8)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
port->config = *config;
port->configured = 0;
return GRUB_ERR_NONE;
}
static struct grub_serial_driver grub_ftdi_driver =
{
.configure = ftdi_hw_configure,
.fetch = ftdi_hw_fetch,
.put = ftdi_hw_put,
.fini = grub_usbserial_fini
};
static const struct
{
grub_uint16_t vendor, product;
} products[] =
{
{0x0403, 0x6001} /* QEMU virtual USBserial. */
};
static int
grub_ftdi_attach (grub_usb_device_t usbdev, int configno, int interfno)
{
unsigned j;
for (j = 0; j < ARRAY_SIZE (products); j++)
if (usbdev->descdev.vendorid == products[j].vendor
&& usbdev->descdev.prodid == products[j].product)
break;
if (j == ARRAY_SIZE (products))
return 0;
return grub_usbserial_attach (usbdev, configno, interfno,
&grub_ftdi_driver);
}
static struct grub_usb_attach_desc attach_hook =
{
.class = 0xff,
.hook = grub_ftdi_attach
};
GRUB_MOD_INIT(usbserial_ftdi)
{
grub_usb_register_attach_hook_class (&attach_hook);
}
GRUB_MOD_FINI(usbserial_ftdi)
{
grub_serial_unregister_driver (&grub_ftdi_driver);
grub_usb_unregister_attach_hook_class (&attach_hook);
}

View file

@ -0,0 +1,218 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/serial.h>
#include <grub/types.h>
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/usb.h>
#include <grub/usbserial.h>
/* Convert speed to divisor. */
static grub_uint32_t
is_speed_supported (unsigned int speed)
{
unsigned int i;
unsigned int supported[] = { 2400, 4800, 9600, 19200, 38400, 57600, 115200};
for (i = 0; i < ARRAY_SIZE (supported); i++)
if (supported[i] == speed)
return 1;
return 0;
}
#define GRUB_PL2303_REQUEST_SET_CONFIG 0x20
#define GRUB_PL2303_STOP_BITS_1 0x0
#define GRUB_PL2303_STOP_BITS_2 0x2
#define GRUB_PL2303_PARITY_NONE 0
#define GRUB_PL2303_PARITY_ODD 1
#define GRUB_PL2303_PARITY_EVEN 2
struct grub_pl2303_config
{
grub_uint32_t speed;
grub_uint8_t stop_bits;
grub_uint8_t parity;
grub_uint8_t word_len;
} __attribute__ ((packed));
static void
real_config (struct grub_serial_port *port)
{
struct grub_pl2303_config config_pl2303;
char xx;
if (port->configured)
return;
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8484, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 0x0404, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8484, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8383, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8484, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 0x0404, 1, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8484, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
1, 0x8383, 0, 1, &xx);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 0, 1, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 1, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 2, 0x44, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 8, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 9, 0, 0, 0);
if (port->config.stop_bits == GRUB_SERIAL_STOP_BITS_2)
config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_2;
else
config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_1;
switch (port->config.parity)
{
case GRUB_SERIAL_PARITY_NONE:
config_pl2303.parity = GRUB_PL2303_PARITY_NONE;
break;
case GRUB_SERIAL_PARITY_ODD:
config_pl2303.parity = GRUB_PL2303_PARITY_ODD;
break;
case GRUB_SERIAL_PARITY_EVEN:
config_pl2303.parity = GRUB_PL2303_PARITY_EVEN;
break;
}
config_pl2303.word_len = port->config.word_len;
config_pl2303.speed = port->config.speed;
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
GRUB_PL2303_REQUEST_SET_CONFIG, 0, 0,
sizeof (config_pl2303), (char *) &config_pl2303);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
0x22, 3, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 0, 0x61, 0, 0);
port->configured = 1;
}
/* Fetch a key. */
static int
pl2303_hw_fetch (struct grub_serial_port *port)
{
real_config (port);
return grub_usbserial_fetch (port, 0);
}
/* Put a character. */
static void
pl2303_hw_put (struct grub_serial_port *port, const int c)
{
char cc = c;
real_config (port);
grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
}
static grub_err_t
pl2303_hw_configure (struct grub_serial_port *port,
struct grub_serial_config *config)
{
if (!is_speed_supported (config->speed))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
if (config->parity != GRUB_SERIAL_PARITY_NONE
&& config->parity != GRUB_SERIAL_PARITY_ODD
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
if (config->word_len < 5 || config->word_len > 8)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
port->config = *config;
port->configured = 0;
return GRUB_ERR_NONE;
}
static struct grub_serial_driver grub_pl2303_driver =
{
.configure = pl2303_hw_configure,
.fetch = pl2303_hw_fetch,
.put = pl2303_hw_put,
.fini = grub_usbserial_fini
};
static const struct
{
grub_uint16_t vendor, product;
} products[] =
{
{0x067b, 0x2303}
};
static int
grub_pl2303_attach (grub_usb_device_t usbdev, int configno, int interfno)
{
unsigned j;
for (j = 0; j < ARRAY_SIZE (products); j++)
if (usbdev->descdev.vendorid == products[j].vendor
&& usbdev->descdev.prodid == products[j].product)
break;
if (j == ARRAY_SIZE (products))
return 0;
return grub_usbserial_attach (usbdev, configno, interfno,
&grub_pl2303_driver);
}
static struct grub_usb_attach_desc attach_hook =
{
.class = 0xff,
.hook = grub_pl2303_attach
};
GRUB_MOD_INIT(usbserial_pl2303)
{
grub_usb_register_attach_hook_class (&attach_hook);
}
GRUB_MOD_FINI(usbserial_pl2303)
{
grub_serial_unregister_driver (&grub_pl2303_driver);
grub_usb_unregister_attach_hook_class (&attach_hook);
}

View file

@ -333,10 +333,12 @@ grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
static void static void
grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td, grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
grub_usb_transfer_t transfer) grub_usb_transfer_t transfer, grub_size_t *actual)
{ {
int i; /* Index of TD in transfer */ int i; /* Index of TD in transfer */
*actual = 0;
/* Free the TDs in this queue and set last_trans. */ /* Free the TDs in this queue and set last_trans. */
for (i=0; td; i++) for (i=0; td; i++)
{ {
@ -346,6 +348,8 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
if (transfer && (td->linkptr & 1)) if (transfer && (td->linkptr & 1))
transfer->last_trans = i; transfer->last_trans = i;
*actual += (td->ctrl_status + 1) & 0x7ff;
/* Unlink the queue. */ /* Unlink the queue. */
tdprev = td; tdprev = td;
td = (grub_uhci_td_t) td->linkptr2; td = (grub_uhci_td_t) td->linkptr2;
@ -436,7 +440,8 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
static grub_usb_err_t static grub_usb_err_t
grub_uhci_transfer (grub_usb_controller_t dev, grub_uhci_transfer (grub_usb_controller_t dev,
grub_usb_transfer_t transfer) grub_usb_transfer_t transfer,
int timeout, grub_size_t *actual)
{ {
struct grub_uhci *u = (struct grub_uhci *) dev->data; struct grub_uhci *u = (struct grub_uhci *) dev->data;
grub_uhci_qh_t qh; grub_uhci_qh_t qh;
@ -447,10 +452,12 @@ grub_uhci_transfer (grub_usb_controller_t dev,
int i; int i;
grub_uint64_t endtime; grub_uint64_t endtime;
*actual = 0;
/* Allocate a queue head for the transfer queue. */ /* Allocate a queue head for the transfer queue. */
qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
if (! qh) if (! qh)
return grub_errno; return GRUB_USB_ERR_INTERNAL;
grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase); grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
@ -468,7 +475,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
td_prev->linkptr = 1; td_prev->linkptr = 1;
if (td_first) if (td_first)
grub_free_queue (u, td_first, NULL); grub_free_queue (u, td_first, NULL, actual);
return GRUB_USB_ERR_INTERNAL; return GRUB_USB_ERR_INTERNAL;
} }
@ -496,7 +503,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
/* Wait until either the transaction completed or an error /* Wait until either the transaction completed or an error
occurred. */ occurred. */
endtime = grub_get_time_ms () + 1000; endtime = grub_get_time_ms () + timeout;
for (;;) for (;;)
{ {
grub_uhci_td_t errtd; grub_uhci_td_t errtd;
@ -512,11 +519,6 @@ grub_uhci_transfer (grub_usb_controller_t dev,
grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); 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. */ /* Check if the endpoint is stalled. */
if (errtd->ctrl_status & (1 << 22)) if (errtd->ctrl_status & (1 << 22))
err = GRUB_USB_ERR_STALL; err = GRUB_USB_ERR_STALL;
@ -547,7 +549,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
/* Fall through, no errors occurred, so the QH might be /* Fall through, no errors occurred, so the QH might be
updated. */ updated. */
grub_dprintf ("uhci", "transaction fallthrough\n"); grub_dprintf ("uhci", "transaction fallthrough\n");
}
if (grub_get_time_ms () > endtime) if (grub_get_time_ms () > endtime)
{ {
err = GRUB_USB_ERR_STALL; err = GRUB_USB_ERR_STALL;
@ -567,7 +569,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
/* Place the QH back in the free list and deallocate the associated /* Place the QH back in the free list and deallocate the associated
TDs. */ TDs. */
qh->elinkptr = 1; qh->elinkptr = 1;
grub_free_queue (u, td_first, transfer); grub_free_queue (u, td_first, transfer, actual);
return err; return err;
} }

View file

@ -22,6 +22,7 @@
#include <grub/usb.h> #include <grub/usb.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/list.h> #include <grub/list.h>
#include <grub/term.h>
static grub_usb_controller_dev_t grub_usb_list; static grub_usb_controller_dev_t grub_usb_list;
struct grub_usb_attach_desc *attach_hooks; struct grub_usb_attach_desc *attach_hooks;
@ -208,14 +209,23 @@ grub_usb_device_initialize (grub_usb_device_t dev)
goto fail; goto fail;
/* Skip the configuration descriptor. */ /* Skip the configuration descriptor. */
pos = sizeof (struct grub_usb_desc_config); pos = dev->config[i].descconf->length;
/* Read all interfaces. */ /* Read all interfaces. */
for (currif = 0; currif < dev->config[i].descconf->numif; currif++) for (currif = 0; currif < dev->config[i].descconf->numif; currif++)
{ {
while (pos < config.totallen
&& ((struct grub_usb_desc *)&data[pos])->type
!= GRUB_USB_DESCRIPTOR_INTERFACE)
pos += ((struct grub_usb_desc *)&data[pos])->length;
dev->config[i].interf[currif].descif dev->config[i].interf[currif].descif
= (struct grub_usb_desc_if *) &data[pos]; = (struct grub_usb_desc_if *) &data[pos];
pos += sizeof (struct grub_usb_desc_if); pos += dev->config[i].interf[currif].descif->length;
while (pos < config.totallen
&& ((struct grub_usb_desc *)&data[pos])->type
!= GRUB_USB_DESCRIPTOR_ENDPOINT)
pos += ((struct grub_usb_desc *)&data[pos])->length;
/* Point to the first endpoint. */ /* Point to the first endpoint. */
dev->config[i].interf[currif].descendp dev->config[i].interf[currif].descendp
@ -256,6 +266,24 @@ void grub_usb_device_attach (grub_usb_device_t dev)
for (desc = attach_hooks; desc; desc = desc->next) for (desc = attach_hooks; desc; desc = desc->next)
if (interf->class == desc->class && desc->hook (dev, 0, i)) if (interf->class == desc->class && desc->hook (dev, 0, i))
dev->config[0].interf[i].attached = 1; dev->config[0].interf[i].attached = 1;
if (dev->config[0].interf[i].attached)
continue;
switch (interf->class)
{
case GRUB_USB_CLASS_MASS_STORAGE:
grub_dl_load ("usbms");
break;
case GRUB_USB_CLASS_HID:
grub_dl_load ("usb_keyboard");
break;
case 0xff:
/* FIXME: don't load useless modules. */
grub_dl_load ("usbserial_ftdi");
grub_dl_load ("usbserial_pl2303");
break;
}
} }
} }
@ -306,3 +334,14 @@ grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc)
{ {
grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc)); grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc));
} }
GRUB_MOD_INIT(usb)
{
grub_term_poll_usb = grub_usb_poll_devices;
}
GRUB_MOD_FINI(usb)
{
grub_term_poll_usb = NULL;
}

View file

@ -33,7 +33,7 @@ struct grub_usb_hub
struct grub_usb_hub *next; struct grub_usb_hub *next;
grub_usb_controller_t controller; grub_usb_controller_t controller;
int nports; int nports;
grub_usb_speed_t *speed; struct grub_usb_device **devices;
grub_usb_device_t dev; grub_usb_device_t dev;
}; };
@ -104,7 +104,7 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed)
} }
static grub_err_t static grub_usb_err_t
grub_usb_add_hub (grub_usb_device_t dev) grub_usb_add_hub (grub_usb_device_t dev)
{ {
struct grub_usb_usb_hubdesc hubdesc; struct grub_usb_usb_hubdesc hubdesc;
@ -112,6 +112,7 @@ grub_usb_add_hub (grub_usb_device_t dev)
int i; int i;
grub_uint64_t timeout; grub_uint64_t timeout;
grub_usb_device_t next_dev; grub_usb_device_t next_dev;
grub_usb_device_t *attached_devices;
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
| GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_CLASS
@ -130,6 +131,13 @@ grub_usb_add_hub (grub_usb_device_t dev)
grub_dprintf ("usb", "Hub set configuration\n"); grub_dprintf ("usb", "Hub set configuration\n");
grub_usb_set_configuration (dev, 1); grub_usb_set_configuration (dev, 1);
attached_devices = grub_zalloc (hubdesc.portcnt
* sizeof (attached_devices[0]));
if (!attached_devices)
return GRUB_USB_ERR_INTERNAL;
dev->children = attached_devices;
dev->nports = hubdesc.portcnt;
/* Power on all Hub ports. */ /* Power on all Hub ports. */
for (i = 1; i <= hubdesc.portcnt; i++) for (i = 1; i <= hubdesc.portcnt; i++)
{ {
@ -236,6 +244,8 @@ grub_usb_add_hub (grub_usb_device_t dev)
if (! next_dev) if (! next_dev)
continue; continue;
attached_devices[i - 1] = next_dev;
/* If the device is a Hub, scan it for more devices. */ /* If the device is a Hub, scan it for more devices. */
if (next_dev->descdev.class == 0x09) if (next_dev->descdev.class == 0x09)
grub_usb_add_hub (next_dev); grub_usb_add_hub (next_dev);
@ -246,27 +256,29 @@ grub_usb_add_hub (grub_usb_device_t dev)
} }
static void static void
attach_root_port (grub_usb_controller_t controller, int portno, attach_root_port (struct grub_usb_hub *hub, int portno,
grub_usb_speed_t speed) grub_usb_speed_t speed)
{ {
grub_usb_device_t dev; grub_usb_device_t dev;
grub_err_t err; grub_err_t err;
/* Disable the port. XXX: Why? */ /* Disable the port. XXX: Why? */
err = controller->dev->portstatus (controller, portno, 0); err = hub->controller->dev->portstatus (hub->controller, portno, 0);
if (err) if (err)
return; return;
/* Enable the port. */ /* Enable the port. */
err = controller->dev->portstatus (controller, portno, 1); err = hub->controller->dev->portstatus (hub->controller, portno, 1);
if (err) if (err)
return; return;
/* Enable the port and create a device. */ /* Enable the port and create a device. */
dev = grub_usb_hub_add_dev (controller, speed); dev = grub_usb_hub_add_dev (hub->controller, speed);
if (! dev) if (! dev)
return; return;
hub->devices[portno] = dev;
/* If the device is a Hub, scan it for more devices. */ /* If the device is a Hub, scan it for more devices. */
if (dev->descdev.class == 0x09) if (dev->descdev.class == 0x09)
grub_usb_add_hub (dev); grub_usb_add_hub (dev);
@ -297,8 +309,8 @@ grub_usb_root_hub (grub_usb_controller_t controller)
/* Query the number of ports the root Hub has. */ /* Query the number of ports the root Hub has. */
hub->nports = controller->dev->hubports (controller); hub->nports = controller->dev->hubports (controller);
hub->speed = grub_malloc (sizeof (hub->speed[0]) * hub->nports); hub->devices = grub_zalloc (sizeof (hub->devices[0]) * hub->nports);
if (!hub->speed) if (!hub->devices)
{ {
grub_free (hub->controller); grub_free (hub->controller);
grub_free (hub); grub_free (hub);
@ -307,36 +319,54 @@ grub_usb_root_hub (grub_usb_controller_t controller)
for (i = 0; i < hub->nports; i++) for (i = 0; i < hub->nports; i++)
{ {
hub->speed[i] = controller->dev->detect_dev (hub->controller, i, grub_usb_speed_t speed;
speed = controller->dev->detect_dev (hub->controller, i,
&changed); &changed);
if (hub->speed[i] != GRUB_USB_SPEED_NONE) if (speed != GRUB_USB_SPEED_NONE)
attach_root_port (hub->controller, i, hub->speed[i]); attach_root_port (hub, i, speed);
} }
return GRUB_USB_ERR_NONE; return GRUB_USB_ERR_NONE;
} }
static void detach_device (grub_usb_device_t dev);
static void
detach_device (grub_usb_device_t dev)
{
unsigned i;
int k;
if (!dev)
return;
if (dev->descdev.class == GRUB_USB_CLASS_HUB)
{
for (i = 0; i < dev->nports; i++)
detach_device (dev->children[i]);
grub_free (dev->children);
}
for (i = 0; i < ARRAY_SIZE (dev->config); i++)
if (dev->config[i].descconf)
for (k = 0; k < dev->config[i].descconf->numif; k++)
{
struct grub_usb_interface *inter = &dev->config[i].interf[k];
if (inter && inter->detach_hook)
inter->detach_hook (dev, i, k);
}
grub_usb_devs[dev->addr] = 0;
}
static void static void
poll_nonroot_hub (grub_usb_device_t dev) poll_nonroot_hub (grub_usb_device_t dev)
{ {
struct grub_usb_usb_hubdesc hubdesc;
grub_err_t err; grub_err_t err;
int i; unsigned i;
grub_uint64_t timeout; grub_uint64_t timeout;
grub_usb_device_t next_dev; grub_usb_device_t next_dev;
grub_usb_device_t *attached_devices = dev->children;
err = 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);
if (err)
return;
/* Iterate over the Hub ports. */ /* Iterate over the Hub ports. */
for (i = 1; i <= hubdesc.portcnt; i++) for (i = 1; i <= dev->nports; i++)
{ {
grub_uint32_t status; grub_uint32_t status;
@ -351,6 +381,12 @@ poll_nonroot_hub (grub_usb_device_t dev)
if (err) if (err)
continue; continue;
if (status & GRUB_USB_HUB_STATUS_C_CONNECTED)
{
detach_device (attached_devices[i-1]);
attached_devices[i - 1] = NULL;
}
/* Connected and status of connection changed ? */ /* Connected and status of connection changed ? */
if ((status & GRUB_USB_HUB_STATUS_CONNECTED) if ((status & GRUB_USB_HUB_STATUS_CONNECTED)
&& (status & GRUB_USB_HUB_STATUS_C_CONNECTED)) && (status & GRUB_USB_HUB_STATUS_C_CONNECTED))
@ -417,6 +453,8 @@ poll_nonroot_hub (grub_usb_device_t dev)
if (! next_dev) if (! next_dev)
continue; continue;
attached_devices[i - 1] = next_dev;
/* If the device is a Hub, scan it for more devices. */ /* If the device is a Hub, scan it for more devices. */
if (next_dev->descdev.class == 0x09) if (next_dev->descdev.class == 0x09)
grub_usb_add_hub (next_dev); grub_usb_add_hub (next_dev);
@ -434,26 +472,23 @@ grub_usb_poll_devices (void)
for (hub = hubs; hub; hub = hub->next) for (hub = hubs; hub; hub = hub->next)
{ {
int changed=0;
/* Do we have to recheck number of ports? */ /* Do we have to recheck number of ports? */
/* No, it should be never changed, it should be constant. */ /* No, it should be never changed, it should be constant. */
for (i = 0; i < hub->nports; i++) for (i = 0; i < hub->nports; i++)
{ {
grub_usb_speed_t speed; grub_usb_speed_t speed;
int changed = 0;
speed = hub->controller->dev->detect_dev (hub->controller, i, speed = hub->controller->dev->detect_dev (hub->controller, i,
&changed); &changed);
if (speed != GRUB_USB_SPEED_NONE)
{
if (changed) if (changed)
attach_root_port (hub->controller, i, speed); {
detach_device (hub->devices[i]);
hub->devices[i] = NULL;
if (speed != GRUB_USB_SPEED_NONE)
attach_root_port (hub, i, speed);
} }
/* XXX: There should be also handling
* of disconnected devices. */
hub->speed[i] = speed;
} }
} }
@ -463,10 +498,8 @@ grub_usb_poll_devices (void)
grub_usb_device_t dev = grub_usb_devs[i]; grub_usb_device_t dev = grub_usb_devs[i];
if (dev && dev->descdev.class == 0x09) if (dev && dev->descdev.class == 0x09)
{
poll_nonroot_hub (dev); poll_nonroot_hub (dev);
} }
}
} }

View file

@ -43,6 +43,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
volatile char *data; volatile char *data;
grub_uint32_t data_addr; grub_uint32_t data_addr;
grub_size_t size = size0; grub_size_t size = size0;
grub_size_t actual;
/* FIXME: avoid allocation any kind of buffer in a first place. */ /* FIXME: avoid allocation any kind of buffer in a first place. */
data_chunk = grub_memalign_dma32 (128, size ? : 16); data_chunk = grub_memalign_dma32 (128, size ? : 16);
@ -132,6 +133,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
else else
tr->pid = GRUB_USB_TRANSFER_TYPE_OUT; tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
tr->data = data_addr + i * max; tr->data = data_addr + i * max;
tr->preceding = i * max;
size -= max; size -= max;
} }
@ -145,7 +147,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
transfer->transactions[datablocks + 1].toggle = 1; transfer->transactions[datablocks + 1].toggle = 1;
err = dev->controller.dev->transfer (&dev->controller, transfer); err = dev->controller.dev->transfer (&dev->controller, transfer,
1000, &actual);
grub_dprintf ("usb", "control: err=%d\n", err); grub_dprintf ("usb", "control: err=%d\n", err);
grub_free (transfer->transactions); grub_free (transfer->transactions);
@ -162,7 +165,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
static grub_usb_err_t static grub_usb_err_t
grub_usb_bulk_readwrite (grub_usb_device_t dev, grub_usb_bulk_readwrite (grub_usb_device_t dev,
int endpoint, grub_size_t size0, char *data_in, int endpoint, grub_size_t size0, char *data_in,
grub_transfer_type_t type) grub_transfer_type_t type, int timeout,
grub_size_t *actual)
{ {
int i; int i;
grub_usb_transfer_t transfer; grub_usb_transfer_t transfer;
@ -240,10 +244,12 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
toggle = toggle ? 0 : 1; toggle = toggle ? 0 : 1;
tr->pid = type; tr->pid = type;
tr->data = data_addr + i * max; tr->data = data_addr + i * max;
tr->preceding = i * max;
size -= tr->size; size -= tr->size;
} }
err = dev->controller.dev->transfer (&dev->controller, transfer); err = dev->controller.dev->transfer (&dev->controller, transfer, timeout,
actual);
/* We must remember proper toggle value even if some transactions /* We must remember proper toggle value even if some transactions
* were not processed - correct value should be inversion of last * were not processed - correct value should be inversion of last
* processed transaction (TD). */ * processed transaction (TD). */
@ -268,14 +274,34 @@ grub_usb_err_t
grub_usb_bulk_write (grub_usb_device_t dev, grub_usb_bulk_write (grub_usb_device_t dev,
int endpoint, grub_size_t size, char *data) int endpoint, grub_size_t size, char *data)
{ {
return grub_usb_bulk_readwrite (dev, endpoint, size, data, grub_size_t actual;
GRUB_USB_TRANSFER_TYPE_OUT); grub_usb_err_t err;
err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual);
if (!err && actual != size)
err = GRUB_USB_ERR_DATA;
return err;
} }
grub_usb_err_t grub_usb_err_t
grub_usb_bulk_read (grub_usb_device_t dev, grub_usb_bulk_read (grub_usb_device_t dev,
int endpoint, grub_size_t size, char *data) int endpoint, grub_size_t size, char *data)
{ {
return grub_usb_bulk_readwrite (dev, endpoint, size, data, grub_size_t actual;
GRUB_USB_TRANSFER_TYPE_IN); grub_usb_err_t err;
err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual);
if (!err && actual != size)
err = GRUB_USB_ERR_DATA;
return err;
}
grub_usb_err_t
grub_usb_bulk_read_extended (grub_usb_device_t dev,
int endpoint, grub_size_t size, char *data,
int timeout, grub_size_t *actual)
{
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
GRUB_USB_TRANSFER_TYPE_IN, timeout, actual);
} }

View file

@ -0,0 +1,384 @@
/* sendkey.c - fake keystroke. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/extcmd.h>
#include <grub/cpu/io.h>
#include <grub/loader.h>
static char sendkey[0x20];
/* Length of sendkey. */
static int keylen = 0;
static int noled = 0;
static const struct grub_arg_option options[] =
{
{"num", 'n', 0, "set numlock mode", "[on|off]", ARG_TYPE_STRING},
{"caps", 'c', 0, "set capslock mode", "[on|off]", ARG_TYPE_STRING},
{"scroll", 's', 0, "set scrolllock mode", "[on|off]", ARG_TYPE_STRING},
{"insert", 0, 0, "set insert mode", "[on|off]", ARG_TYPE_STRING},
{"pause", 0, 0, "set pause mode", "[on|off]", ARG_TYPE_STRING},
{"left-shift", 0, 0, "press left shift", "[on|off]", ARG_TYPE_STRING},
{"right-shift", 0, 0, "press right shift", "[on|off]", ARG_TYPE_STRING},
{"sysrq", 0, 0, "press SysRq", "[on|off]", ARG_TYPE_STRING},
{"numkey", 0, 0, "press NumLock key", "[on|off]", ARG_TYPE_STRING},
{"capskey", 0, 0, "press CapsLock key", "[on|off]", ARG_TYPE_STRING},
{"scrollkey", 0, 0, "press ScrollLock key", "[on|off]", ARG_TYPE_STRING},
{"insertkey", 0, 0, "press Insert key", "[on|off]", ARG_TYPE_STRING},
{"left-alt", 0, 0, "press left alt", "[on|off]", ARG_TYPE_STRING},
{"right-alt", 0, 0, "press right alt", "[on|off]", ARG_TYPE_STRING},
{"left-ctrl", 0, 0, "press left ctrl", "[on|off]", ARG_TYPE_STRING},
{"right-ctrl", 0, 0, "press right ctrl", "[on|off]", ARG_TYPE_STRING},
{"no-led", 0, 0, "don't update LED state", 0, 0},
{0, 0, 0, 0, 0, 0}
};
static int simple_flag_offsets[]
= {5, 6, 4, 7, 11, 1, 0, 10, 13, 14, 12, 15, 9, 3, 8, 2};
static grub_uint32_t andmask = 0xffffffff, ormask = 0;
struct
keysym
{
char *unshifted_name; /* the name in unshifted state */
char *shifted_name; /* the name in shifted state */
unsigned char unshifted_ascii; /* the ascii code in unshifted state */
unsigned char shifted_ascii; /* the ascii code in shifted state */
unsigned char keycode; /* keyboard scancode */
};
/* The table for key symbols. If the "shifted" member of an entry is
NULL, the entry does not have shifted state. Copied from GRUB Legacy setkey fuction */
static struct keysym keysym_table[] =
{
{"escape", 0, 0x1b, 0, 0x01},
{"1", "exclam", '1', '!', 0x02},
{"2", "at", '2', '@', 0x03},
{"3", "numbersign", '3', '#', 0x04},
{"4", "dollar", '4', '$', 0x05},
{"5", "percent", '5', '%', 0x06},
{"6", "caret", '6', '^', 0x07},
{"7", "ampersand", '7', '&', 0x08},
{"8", "asterisk", '8', '*', 0x09},
{"9", "parenleft", '9', '(', 0x0a},
{"0", "parenright", '0', ')', 0x0b},
{"minus", "underscore", '-', '_', 0x0c},
{"equal", "plus", '=', '+', 0x0d},
{"backspace", 0, '\b', 0, 0x0e},
{"tab", 0, '\t', 0, 0x0f},
{"q", "Q", 'q', 'Q', 0x10},
{"w", "W", 'w', 'W', 0x11},
{"e", "E", 'e', 'E', 0x12},
{"r", "R", 'r', 'R', 0x13},
{"t", "T", 't', 'T', 0x14},
{"y", "Y", 'y', 'Y', 0x15},
{"u", "U", 'u', 'U', 0x16},
{"i", "I", 'i', 'I', 0x17},
{"o", "O", 'o', 'O', 0x18},
{"p", "P", 'p', 'P', 0x19},
{"bracketleft", "braceleft", '[', '{', 0x1a},
{"bracketright", "braceright", ']', '}', 0x1b},
{"enter", 0, '\r', 0, 0x1c},
{"control", 0, 0, 0, 0x1d},
{"a", "A", 'a', 'A', 0x1e},
{"s", "S", 's', 'S', 0x1f},
{"d", "D", 'd', 'D', 0x20},
{"f", "F", 'f', 'F', 0x21},
{"g", "G", 'g', 'G', 0x22},
{"h", "H", 'h', 'H', 0x23},
{"j", "J", 'j', 'J', 0x24},
{"k", "K", 'k', 'K', 0x25},
{"l", "L", 'l', 'L', 0x26},
{"semicolon", "colon", ';', ':', 0x27},
{"quote", "doublequote", '\'', '"', 0x28},
{"backquote", "tilde", '`', '~', 0x29},
{"shift", 0, 0, 0, 0x2a},
{"backslash", "bar", '\\', '|', 0x2b},
{"z", "Z", 'z', 'Z', 0x2c},
{"x", "X", 'x', 'X', 0x2d},
{"c", "C", 'c', 'C', 0x2e},
{"v", "V", 'v', 'V', 0x2f},
{"b", "B", 'b', 'B', 0x30},
{"n", "N", 'n', 'N', 0x31},
{"m", "M", 'm', 'M', 0x32},
{"comma", "less", ',', '<', 0x33},
{"period", "greater", '.', '>', 0x34},
{"slash", "question", '/', '?', 0x35},
{"rshift", 0, 0, 0, 0x36},
{"numasterisk", 0, '*', 0, 0x37},
{"alt", 0, 0, 0, 0x38},
{"space", 0, ' ', 0, 0x39},
{"capslock", 0, 0, 0, 0x3a},
{"F1", 0, 0, 0, 0x3b},
{"F2", 0, 0, 0, 0x3c},
{"F3", 0, 0, 0, 0x3d},
{"F4", 0, 0, 0, 0x3e},
{"F5", 0, 0, 0, 0x3f},
{"F6", 0, 0, 0, 0x40},
{"F7", 0, 0, 0, 0x41},
{"F8", 0, 0, 0, 0x42},
{"F9", 0, 0, 0, 0x43},
{"F10", 0, 0, 0, 0x44},
{"num7", "numhome", '7', 0, 0x47},
{"num8", "numup", '8', 0, 0x48},
{"num9", "numpgup", '9', 0, 0x49},
{"numminus", 0, '-', 0, 0x4a},
{"num4", "numleft", '4', 0, 0x4b},
{"num5", "numcenter", '5', 0, 0x4c},
{"num6", "numright", '6', 0, 0x4d},
{"numplus", 0, '-', 0, 0x4e},
{"num1", "numend", '1', 0, 0x4f},
{"num2", "numdown", '2', 0, 0x50},
{"num3", "numpgdown", '3', 0, 0x51},
{"num0", "numinsert", '0', 0, 0x52},
{"numperiod", "numdelete", 0, 0x7f, 0x53},
{"F11", 0, 0, 0, 0x57},
{"F12", 0, 0, 0, 0x58},
{"numenter", 0, '\r', 0, 0xe0},
{"numslash", 0, '/', 0, 0xe0},
{"delete", 0, 0x7f, 0, 0xe0},
{"insert", 0, 0xe0, 0, 0x52},
{"home", 0, 0xe0, 0, 0x47},
{"end", 0, 0xe0, 0, 0x4f},
{"pgdown", 0, 0xe0, 0, 0x51},
{"pgup", 0, 0xe0, 0, 0x49},
{"down", 0, 0xe0, 0, 0x50},
{"up", 0, 0xe0, 0, 0x48},
{"left", 0, 0xe0, 0, 0x4b},
{"right", 0, 0xe0, 0, 0x4d}
};
/* Set a simple flag in flags variable
OUTOFFSET - offset of flag in FLAGS,
OP - action id
*/
static void
grub_sendkey_set_simple_flag (int outoffset, int op)
{
if (op == 2)
{
andmask |= (1 << outoffset);
ormask &= ~(1 << outoffset);
}
else
{
andmask &= (~(1 << outoffset));
if (op == 1)
ormask |= (1 << outoffset);
else
ormask &= ~(1 << outoffset);
}
}
static int
grub_sendkey_parse_op (struct grub_arg_list state)
{
if (! state.set)
return 2;
if (grub_strcmp (state.arg, "off") == 0 || grub_strcmp (state.arg, "0") == 0
|| grub_strcmp (state.arg, "unpress") == 0)
return 0;
if (grub_strcmp (state.arg, "on") == 0 || grub_strcmp (state.arg, "1") == 0
|| grub_strcmp (state.arg, "press") == 0)
return 1;
return 2;
}
static grub_uint32_t oldflags;
static grub_err_t
grub_sendkey_postboot (void)
{
/* For convention: pointer to flags. */
grub_uint32_t *flags = (grub_uint32_t *) 0x417;
*flags = oldflags;
*((char *) 0x41a) = 0x1e;
*((char *) 0x41c) = 0x1e;
return GRUB_ERR_NONE;
}
/* Set keyboard buffer to our sendkey */
static grub_err_t
grub_sendkey_preboot (int noret __attribute__ ((unused)))
{
/* For convention: pointer to flags. */
grub_uint32_t *flags = (grub_uint32_t *) 0x417;
oldflags = *flags;
/* Set the sendkey. */
*((char *) 0x41a) = 0x1e;
*((char *) 0x41c) = keylen + 0x1e;
grub_memcpy ((char *) 0x41e, sendkey, 0x20);
/* Transform "any ctrl" to "right ctrl" flag. */
if (*flags & (1 << 8))
*flags &= ~(1 << 2);
/* Transform "any alt" to "right alt" flag. */
if (*flags & (1 << 9))
*flags &= ~(1 << 3);
*flags = (*flags & andmask) | ormask;
/* Transform "right ctrl" to "any ctrl" flag. */
if (*flags & (1 << 8))
*flags |= (1 << 2);
/* Transform "right alt" to "any alt" flag. */
if (*flags & (1 << 9))
*flags |= (1 << 3);
/* Write new LED state */
if (!noled)
{
int value = 0;
int failed;
/* Try 5 times */
for (failed = 0; failed < 5; failed++)
{
value = 0;
/* Send command change LEDs */
grub_outb (0xed, 0x60);
/* Wait */
do
value = grub_inb (0x60);
while ((value != 0xfa) && (value != 0xfe));
if (value == 0xfa)
{
/* Set new LEDs*/
grub_outb ((*flags >> 4) & 7, 0x60);
break;
}
}
}
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
auto int find_key_code (char *key);
auto int find_ascii_code (char *key);
int find_key_code (char *key)
{
unsigned i;
for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
{
if (keysym_table[i].unshifted_name
&& grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
return keysym_table[i].keycode;
else if (keysym_table[i].shifted_name
&& grub_strcmp (key, keysym_table[i].shifted_name) == 0)
return keysym_table[i].keycode;
}
return 0;
}
int find_ascii_code (char *key)
{
unsigned i;
for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
{
if (keysym_table[i].unshifted_name
&& grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
return keysym_table[i].unshifted_ascii;
else if (keysym_table[i].shifted_name
&& grub_strcmp (key, keysym_table[i].shifted_name) == 0)
return keysym_table[i].shifted_ascii;
}
return 0;
}
andmask = 0xffffffff;
ormask = 0;
{
int i;
keylen = 0;
for (i = 0; i < argc && keylen < 0x20; i++)
{
int key_code;
key_code = find_key_code (args[i]);
if (key_code)
{
sendkey[keylen++] = find_ascii_code (args[i]);
sendkey[keylen++] = key_code;
}
}
}
{
unsigned i;
for (i = 0; i < sizeof (simple_flag_offsets)
/ sizeof (simple_flag_offsets[0]); i++)
grub_sendkey_set_simple_flag (simple_flag_offsets[i],
grub_sendkey_parse_op(state[i]));
}
/* Set noled. */
noled = (state[sizeof (simple_flag_offsets)
/ sizeof (simple_flag_offsets[0])].set);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd;
static void *preboot_hook;
GRUB_MOD_INIT (sendkey)
{
cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey,
GRUB_COMMAND_FLAG_BOTH,
"sendkey [KEYSTROKE1] [KEYSTROKE2] ...",
"Emulate a keystroke", options);
preboot_hook
= grub_loader_register_preboot_hook (grub_sendkey_preboot,
grub_sendkey_postboot,
GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE);
}
GRUB_MOD_FINI (sendkey)
{
grub_unregister_extcmd (cmd);
grub_loader_unregister_preboot_hook (preboot_hook);
}

View file

@ -59,11 +59,17 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled,
for (aut = autoloads; aut; aut = aut->next) for (aut = autoloads; aut; aut = aut->next)
{ {
for (term = *disabled; term; term = term->next) for (term = *disabled; term; term = term->next)
if (grub_strcmp (term->name, aut->name) == 0) if (grub_strcmp (term->name, aut->name) == 0
|| (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
&& grub_memcmp (term->name, aut->name,
grub_strlen (aut->name) - 1) == 0))
break; break;
if (!term) if (!term)
for (term = *enabled; term; term = term->next) for (term = *enabled; term; term = term->next)
if (grub_strcmp (term->name, aut->name) == 0) if (grub_strcmp (term->name, aut->name) == 0
|| (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
&& grub_memcmp (term->name, aut->name,
grub_strlen (aut->name) - 1) == 0))
break; break;
if (!term) if (!term)
grub_printf ("%s ", aut->name); grub_printf ("%s ", aut->name);
@ -98,7 +104,10 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled,
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
args[i]); args[i]);
for (aut = autoloads; aut; aut = aut->next) for (aut = autoloads; aut; aut = aut->next)
if (grub_strcmp (args[i], aut->name) == 0) if (grub_strcmp (args[i], aut->name) == 0
|| (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
&& grub_memcmp (args[i], aut->name,
grub_strlen (aut->name) - 1) == 0))
{ {
grub_dl_t mod; grub_dl_t mod;
mod = grub_dl_load (aut->modname); mod = grub_dl_load (aut->modname);

View file

@ -29,11 +29,11 @@
static const char *usb_classes[] = static const char *usb_classes[] =
{ {
"", "Unknown",
"Audio", "Audio",
"Communication Interface", "Communication Interface",
"HID", "HID",
"", "Unknown",
"Physical", "Physical",
"Image", "Image",
"Printer", "Printer",
@ -138,9 +138,9 @@ usb_iterate (grub_usb_device_t dev)
usb_print_str ("Vendor", dev, descdev->strvendor); usb_print_str ("Vendor", dev, descdev->strvendor);
usb_print_str ("Serial", dev, descdev->strserial); 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", grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
descdev->class, usb_classes[descdev->class], descdev->class, descdev->class < ARRAY_SIZE (usb_classes)
? usb_classes[descdev->class] : "Unknown",
descdev->subclass, descdev->protocol); descdev->subclass, descdev->protocol);
grub_printf ("USB version %d.%d, VendorID: 0x%02x, ProductID: 0x%02x, #conf: %d\n", grub_printf ("USB version %d.%d, VendorID: 0x%02x, ProductID: 0x%02x, #conf: %d\n",
descdev->usbrel >> 8, (descdev->usbrel >> 4) & 0x0F, descdev->usbrel >> 8, (descdev->usbrel >> 4) & 0x0F,
@ -164,9 +164,9 @@ usb_iterate (grub_usb_device_t dev)
grub_printf ("Interface #%d: #Endpoints: %d ", grub_printf ("Interface #%d: #Endpoints: %d ",
i, interf->endpointcnt); i, interf->endpointcnt);
if (interf->class > 0 && interf->class <= 0x0E)
grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n", grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
interf->class, usb_classes[interf->class], interf->class, interf->class < ARRAY_SIZE (usb_classes)
? usb_classes[interf->class] : "Unknown",
interf->subclass, interf->protocol); interf->subclass, interf->protocol);
usb_print_str ("Interface", dev, interf->strif); usb_print_str ("Interface", dev, interf->strif);

View file

@ -65,6 +65,7 @@ typedef struct grub_usbms_dev *grub_usbms_dev_t;
/* FIXME: remove limit. */ /* FIXME: remove limit. */
#define MAX_USBMS_DEVICES 128 #define MAX_USBMS_DEVICES 128
static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES]; static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES];
static int first_available_slot = 0;
static grub_err_t static grub_err_t
grub_usbms_reset (grub_usb_device_t dev, int interface) grub_usbms_reset (grub_usb_device_t dev, int interface)
@ -96,13 +97,12 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
unsigned curnum; unsigned curnum;
grub_usb_err_t err; grub_usb_err_t err;
for (curnum = 0; curnum < ARRAY_SIZE (grub_usbms_devices); curnum++) if (first_available_slot == ARRAY_SIZE (grub_usbms_devices))
if (!grub_usbms_devices[curnum])
break;
if (curnum == ARRAY_SIZE (grub_usbms_devices))
return 0; return 0;
curnum = first_available_slot;
first_available_slot++;
interf = usbdev->config[configno].interf[interfno].descif; interf = usbdev->config[configno].interf[interfno].descif;
if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK

View file

@ -28,6 +28,8 @@ struct grub_term_input *grub_term_inputs_disabled;
struct grub_term_output *grub_term_outputs; struct grub_term_output *grub_term_outputs;
struct grub_term_input *grub_term_inputs; struct grub_term_input *grub_term_inputs;
void (*grub_term_poll_usb) (void) = NULL;
/* Put a Unicode character. */ /* Put a Unicode character. */
static void static void
grub_putcode_dumb (grub_uint32_t code, grub_putcode_dumb (grub_uint32_t code,
@ -85,6 +87,9 @@ grub_getkey (void)
while (1) while (1)
{ {
if (grub_term_poll_usb)
grub_term_poll_usb ();
FOR_ACTIVE_TERM_INPUTS(term) FOR_ACTIVE_TERM_INPUTS(term)
{ {
int key = term->checkkey (term); int key = term->checkkey (term);
@ -101,6 +106,9 @@ grub_checkkey (void)
{ {
grub_term_input_t term; grub_term_input_t term;
if (grub_term_poll_usb)
grub_term_poll_usb ();
FOR_ACTIVE_TERM_INPUTS(term) FOR_ACTIVE_TERM_INPUTS(term)
{ {
int key = term->checkkey (term); int key = term->checkkey (term);
@ -117,6 +125,9 @@ grub_getkeystatus (void)
int status = 0; int status = 0;
grub_term_input_t term; grub_term_input_t term;
if (grub_term_poll_usb)
grub_term_poll_usb ();
FOR_ACTIVE_TERM_INPUTS(term) FOR_ACTIVE_TERM_INPUTS(term)
{ {
if (term->getkeystatus) if (term->getkeystatus)

View file

@ -295,6 +295,17 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
grub_ssize_t size; grub_ssize_t size;
char *module = 0; char *module = 0;
grub_err_t err; grub_err_t err;
int nounzip = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
if (grub_strcmp (argv[0], "--nounzip") == 0)
{
argv++;
argc--;
nounzip = 1;
}
if (argc == 0) if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
@ -303,6 +314,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
return grub_error (GRUB_ERR_BAD_ARGUMENT, return grub_error (GRUB_ERR_BAD_ARGUMENT,
"you need to load the multiboot kernel first"); "you need to load the multiboot kernel first");
if (nounzip)
file = grub_file_open (argv[0]);
else
file = grub_gzfile_open (argv[0], 1); file = grub_gzfile_open (argv[0], 1);
if (! file) if (! file)
return grub_errno; return grub_errno;

253
grub-core/term/ns8250.c Normal file
View file

@ -0,0 +1,253 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/machine/memory.h>
#include <grub/serial.h>
#include <grub/ns8250.h>
#include <grub/types.h>
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/cpu/io.h>
#include <grub/mm.h>
#ifdef GRUB_MACHINE_PCBIOS
static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
#define GRUB_SERIAL_PORT_NUM 4
#else
#include <grub/machine/serial.h>
static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS;
#define GRUB_SERIAL_PORT_NUM (ARRAY_SIZE(serial_hw_io_addr))
#endif
/* Convert speed to divisor. */
static unsigned short
serial_get_divisor (unsigned int speed)
{
unsigned int i;
/* The structure for speed vs. divisor. */
struct divisor
{
unsigned int speed;
unsigned short div;
};
/* The table which lists common configurations. */
/* 1843200 / (speed * 16) */
static struct divisor divisor_tab[] =
{
{ 2400, 0x0030 },
{ 4800, 0x0018 },
{ 9600, 0x000C },
{ 19200, 0x0006 },
{ 38400, 0x0003 },
{ 57600, 0x0002 },
{ 115200, 0x0001 }
};
/* Set the baud rate. */
for (i = 0; i < ARRAY_SIZE (divisor_tab); i++)
if (divisor_tab[i].speed == speed)
/* UART in Yeeloong runs twice the usual rate. */
#ifdef GRUB_MACHINE_MIPS_YEELOONG
return 2 * divisor_tab[i].div;
#else
return divisor_tab[i].div;
#endif
return 0;
}
static void
do_real_config (struct grub_serial_port *port)
{
int divisor;
unsigned char status = 0;
const unsigned char parities[] = {
[GRUB_SERIAL_PARITY_NONE] = UART_NO_PARITY,
[GRUB_SERIAL_PARITY_ODD] = UART_ODD_PARITY,
[GRUB_SERIAL_PARITY_EVEN] = UART_EVEN_PARITY
};
const unsigned char stop_bits[] = {
[GRUB_SERIAL_STOP_BITS_1] = UART_1_STOP_BIT,
[GRUB_SERIAL_STOP_BITS_2] = UART_2_STOP_BITS,
};
if (port->configured)
return;
divisor = serial_get_divisor (port->config.speed);
/* Turn off the interrupt. */
grub_outb (0, port->port + UART_IER);
/* Set DLAB. */
grub_outb (UART_DLAB, port->port + UART_LCR);
/* Set the baud rate. */
grub_outb (divisor & 0xFF, port->port + UART_DLL);
grub_outb (divisor >> 8, port->port + UART_DLH);
/* Set the line status. */
status |= (parities[port->config.parity]
| (port->config.word_len - 5)
| stop_bits[port->config.stop_bits]);
grub_outb (status, port->port + UART_LCR);
/* In Yeeloong serial port has only 3 wires. */
#ifndef GRUB_MACHINE_MIPS_YEELOONG
/* Enable the FIFO. */
grub_outb (UART_ENABLE_FIFO_TRIGGER1, port->port + UART_FCR);
/* Turn on DTR and RTS. */
grub_outb (UART_ENABLE_DTRRTS, port->port + UART_MCR);
#else
/* Enable the FIFO. */
grub_outb (UART_ENABLE_FIFO_TRIGGER14, port->port + UART_FCR);
/* Turn on DTR, RTS, and OUT2. */
grub_outb (UART_ENABLE_DTRRTS | UART_ENABLE_OUT2, port->port + UART_MCR);
#endif
/* Drain the input buffer. */
while (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
grub_inb (port->port + UART_RX);
port->configured = 1;
}
/* Fetch a key. */
static int
serial_hw_fetch (struct grub_serial_port *port)
{
do_real_config (port);
if (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
return grub_inb (port->port + UART_RX);
return -1;
}
/* Put a character. */
static void
serial_hw_put (struct grub_serial_port *port, const int c)
{
unsigned int timeout = 100000;
do_real_config (port);
/* Wait until the transmitter holding register is empty. */
while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
{
if (--timeout == 0)
/* There is something wrong. But what can I do? */
return;
}
grub_outb (c, port->port + UART_TX);
}
/* Initialize a serial device. PORT is the port number for a serial device.
SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
for the device. Likewise, PARITY is the type of the parity and
STOP_BIT_LEN is the length of the stop bit. The possible values for
WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
macros. */
static grub_err_t
serial_hw_configure (struct grub_serial_port *port,
struct grub_serial_config *config)
{
unsigned short divisor;
divisor = serial_get_divisor (config->speed);
if (divisor == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
if (config->parity != GRUB_SERIAL_PARITY_NONE
&& config->parity != GRUB_SERIAL_PARITY_ODD
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
if (config->word_len < 5 || config->word_len > 8)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
port->config = *config;
port->configured = 0;
/* FIXME: should check if the serial terminal was found. */
return GRUB_ERR_NONE;
}
struct grub_serial_driver grub_ns8250_driver =
{
.configure = serial_hw_configure,
.fetch = serial_hw_fetch,
.put = serial_hw_put
};
static char com_names[GRUB_SERIAL_PORT_NUM][20];
static struct grub_serial_port com_ports[GRUB_SERIAL_PORT_NUM];
void
grub_ns8250_init (void)
{
unsigned i;
for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
if (serial_hw_io_addr[i])
{
grub_err_t err;
grub_snprintf (com_names[i], sizeof (com_names[i]), "com%d", i);
com_ports[i].name = com_names[i];
com_ports[i].driver = &grub_ns8250_driver;
com_ports[i].port = serial_hw_io_addr[i];
err = grub_serial_config_defaults (&com_ports[i]);
if (err)
grub_print_error ();
grub_serial_register (&com_ports[i]);
}
}
char *
grub_serial_ns8250_add_port (grub_port_t port)
{
struct grub_serial_port *p;
unsigned i;
for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
if (com_ports[i].port == port)
return com_names[i];
p = grub_malloc (sizeof (*p));
if (!p)
return NULL;
p->name = grub_xasprintf ("port%lx", (unsigned long) port);
if (!p->name)
{
grub_free (p);
return NULL;
}
p->driver = &grub_ns8250_driver;
grub_serial_config_defaults (p);
p->port = port;
grub_serial_register (p);
return p->name;
}

View file

@ -1,6 +1,6 @@
/* /*
* GRUB -- GRand Unified Bootloader * GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
* *
* GRUB is free software: you can redistribute it and/or modify * GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <grub/machine/memory.h>
#include <grub/serial.h> #include <grub/serial.h>
#include <grub/term.h> #include <grub/term.h>
#include <grub/types.h> #include <grub/types.h>
@ -26,8 +25,9 @@
#include <grub/cpu/io.h> #include <grub/cpu/io.h>
#include <grub/extcmd.h> #include <grub/extcmd.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/list.h>
static unsigned int registered = 0; #define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
/* Argument options. */ /* Argument options. */
static const struct grub_arg_option options[] = static const struct grub_arg_option options[] =
@ -41,154 +41,19 @@ static const struct grub_arg_option options[] =
{0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0}
}; };
/* Serial port settings. */ struct grub_serial_port *grub_serial_ports;
struct serial_port
struct grub_serial_output_state
{ {
grub_port_t port; struct grub_terminfo_output_state tinfo;
unsigned short divisor; struct grub_serial_port *port;
unsigned short word_len;
unsigned int parity;
unsigned short stop_bits;
}; };
/* Serial port settings. */ struct grub_serial_input_state
static struct serial_port serial_settings;
#ifdef GRUB_MACHINE_PCBIOS
static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
#define GRUB_SERIAL_PORT_NUM 4
#else
#include <grub/machine/serial.h>
static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS;
#define GRUB_SERIAL_PORT_NUM (ARRAY_SIZE(serial_hw_io_addr))
#endif
/* Return the port number for the UNITth serial device. */
static inline grub_port_t
serial_hw_get_port (const unsigned int unit)
{ {
if (unit < GRUB_SERIAL_PORT_NUM) struct grub_terminfo_input_state tinfo;
return serial_hw_io_addr[unit]; struct grub_serial_port *port;
else };
return 0;
}
/* Fetch a key. */
static int
serial_hw_fetch (void)
{
if (grub_inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
return grub_inb (serial_settings.port + UART_RX);
return -1;
}
/* Put a character. */
static void
serial_hw_put (const int c)
{
unsigned int timeout = 100000;
/* Wait until the transmitter holding register is empty. */
while ((grub_inb (serial_settings.port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
{
if (--timeout == 0)
/* There is something wrong. But what can I do? */
return;
}
grub_outb (c, serial_settings.port + UART_TX);
}
/* Convert speed to divisor. */
static unsigned short
serial_get_divisor (unsigned int speed)
{
unsigned int i;
/* The structure for speed vs. divisor. */
struct divisor
{
unsigned int speed;
unsigned short div;
};
/* The table which lists common configurations. */
/* 1843200 / (speed * 16) */
static struct divisor divisor_tab[] =
{
{ 2400, 0x0030 },
{ 4800, 0x0018 },
{ 9600, 0x000C },
{ 19200, 0x0006 },
{ 38400, 0x0003 },
{ 57600, 0x0002 },
{ 115200, 0x0001 }
};
/* Set the baud rate. */
for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
if (divisor_tab[i].speed == speed)
/* UART in Yeeloong runs twice the usual rate. */
#ifdef GRUB_MACHINE_MIPS_YEELOONG
return 2 * divisor_tab[i].div;
#else
return divisor_tab[i].div;
#endif
return 0;
}
/* Initialize a serial device. PORT is the port number for a serial device.
SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
for the device. Likewise, PARITY is the type of the parity and
STOP_BIT_LEN is the length of the stop bit. The possible values for
WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
macros. */
static grub_err_t
serial_hw_init (void)
{
unsigned char status = 0;
/* Turn off the interrupt. */
grub_outb (0, serial_settings.port + UART_IER);
/* Set DLAB. */
grub_outb (UART_DLAB, serial_settings.port + UART_LCR);
/* Set the baud rate. */
grub_outb (serial_settings.divisor & 0xFF, serial_settings.port + UART_DLL);
grub_outb (serial_settings.divisor >> 8, serial_settings.port + UART_DLH);
/* Set the line status. */
status |= (serial_settings.parity
| serial_settings.word_len
| serial_settings.stop_bits);
grub_outb (status, serial_settings.port + UART_LCR);
/* In Yeeloong serial port has only 3 wires. */
#ifndef GRUB_MACHINE_MIPS_YEELOONG
/* Enable the FIFO. */
grub_outb (UART_ENABLE_FIFO_TRIGGER1, serial_settings.port + UART_FCR);
/* Turn on DTR and RTS. */
grub_outb (UART_ENABLE_DTRRTS, serial_settings.port + UART_MCR);
#else
/* Enable the FIFO. */
grub_outb (UART_ENABLE_FIFO_TRIGGER14, serial_settings.port + UART_FCR);
/* Turn on DTR, RTS, and OUT2. */
grub_outb (UART_ENABLE_DTRRTS | UART_ENABLE_OUT2,
serial_settings.port + UART_MCR);
#endif
/* Drain the input buffer. */
while (serial_hw_fetch () != -1);
/* FIXME: should check if the serial terminal was found. */
return GRUB_ERR_NONE;
}
static grub_uint16_t static grub_uint16_t
grub_serial_getwh (struct grub_term_output *term __attribute__ ((unused))) grub_serial_getwh (struct grub_term_output *term __attribute__ ((unused)))
@ -198,16 +63,38 @@ grub_serial_getwh (struct grub_term_output *term __attribute__ ((unused)))
return (TEXT_WIDTH << 8) | TEXT_HEIGHT; return (TEXT_WIDTH << 8) | TEXT_HEIGHT;
} }
struct grub_terminfo_input_state grub_serial_terminfo_input = static void
serial_put (grub_term_output_t term, const int c)
{
struct grub_serial_output_state *data = term->data;
data->port->driver->put (data->port, c);
}
static int
serial_fetch (grub_term_input_t term)
{
struct grub_serial_input_state *data = term->data;
return data->port->driver->fetch (data->port);
}
struct grub_serial_input_state grub_serial_terminfo_input =
{ {
.readkey = serial_hw_fetch .tinfo =
{
.readkey = serial_fetch
}
}; };
struct grub_terminfo_output_state grub_serial_terminfo_output = struct grub_serial_output_state grub_serial_terminfo_output =
{ {
.put = serial_hw_put .tinfo =
{
.put = serial_put
}
}; };
int registered = 0;
static struct grub_term_input grub_serial_term_input = static struct grub_term_input grub_serial_term_input =
{ {
.name = "serial", .name = "serial",
@ -235,120 +122,219 @@ static struct grub_term_output grub_serial_term_output =
static struct grub_serial_port *
grub_serial_find (char *name)
{
struct grub_serial_port *port;
FOR_SERIAL_PORTS (port)
if (grub_strcmp (port->name, name) == 0)
break;
#ifndef GRUB_MACHINE_EMU
if (!port && grub_memcmp (name, "port", sizeof ("port") - 1) == 0
&& grub_isdigit (name [sizeof ("port") - 1]))
{
name = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") - 1],
0, 16));
if (!name)
return NULL;
FOR_SERIAL_PORTS (port)
if (grub_strcmp (port->name, name) == 0)
break;
}
#endif
return port;
}
static grub_err_t static grub_err_t
grub_cmd_serial (grub_extcmd_t cmd, grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args)
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = cmd->state;
struct serial_port backup_settings = serial_settings; char pname[40];
grub_err_t hwiniterr; char *name = NULL;
struct grub_serial_port *port;
struct grub_serial_config config;
grub_err_t err;
if (state[0].set) if (state[0].set)
{ {
unsigned int unit; grub_snprintf (pname, sizeof (pname), "com%ld",
grub_strtoul (state[0].arg, 0, 0));
unit = grub_strtoul (state[0].arg, 0, 0); name = pname;
serial_settings.port = serial_hw_get_port (unit);
if (!serial_settings.port)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number");
} }
if (state[1].set) if (state[1].set)
serial_settings.port = (grub_port_t) grub_strtoul (state[1].arg, 0, 0); {
grub_snprintf (pname, sizeof (pname), "port%lx",
grub_strtoul (state[1].arg, 0, 0));
name = pname;
}
if (argc >= 1)
name = args[0];
if (!name)
name = "com0";
port = grub_serial_find (name);
if (!port)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown serial port");
config = port->config;
if (state[2].set) if (state[2].set)
{ config.speed = grub_strtoul (state[2].arg, 0, 0);
unsigned long speed;
speed = grub_strtoul (state[2].arg, 0, 0);
serial_settings.divisor = serial_get_divisor ((unsigned int) speed);
if (serial_settings.divisor == 0)
{
serial_settings = backup_settings;
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
}
}
if (state[3].set) if (state[3].set)
{ config.word_len = grub_strtoul (state[3].arg, 0, 0);
if (! grub_strcmp (state[3].arg, "5"))
serial_settings.word_len = UART_5BITS_WORD;
else if (! grub_strcmp (state[3].arg, "6"))
serial_settings.word_len = UART_6BITS_WORD;
else if (! grub_strcmp (state[3].arg, "7"))
serial_settings.word_len = UART_7BITS_WORD;
else if (! grub_strcmp (state[3].arg, "8"))
serial_settings.word_len = UART_8BITS_WORD;
else
{
serial_settings = backup_settings;
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad word length");
}
}
if (state[4].set) if (state[4].set)
{ {
if (! grub_strcmp (state[4].arg, "no")) if (! grub_strcmp (state[4].arg, "no"))
serial_settings.parity = UART_NO_PARITY; config.parity = GRUB_SERIAL_PARITY_NONE;
else if (! grub_strcmp (state[4].arg, "odd")) else if (! grub_strcmp (state[4].arg, "odd"))
serial_settings.parity = UART_ODD_PARITY; config.parity = GRUB_SERIAL_PARITY_ODD;
else if (! grub_strcmp (state[4].arg, "even")) else if (! grub_strcmp (state[4].arg, "even"))
serial_settings.parity = UART_EVEN_PARITY; config.parity = GRUB_SERIAL_PARITY_EVEN;
else else
{
serial_settings = backup_settings;
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity");
} }
}
if (state[5].set) if (state[5].set)
{ {
if (! grub_strcmp (state[5].arg, "1")) if (! grub_strcmp (state[5].arg, "1"))
serial_settings.stop_bits = UART_1_STOP_BIT; config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
else if (! grub_strcmp (state[5].arg, "2")) else if (! grub_strcmp (state[5].arg, "2"))
serial_settings.stop_bits = UART_2_STOP_BITS; config.stop_bits = GRUB_SERIAL_STOP_BITS_2;
else else
{
serial_settings = backup_settings;
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits");
} }
}
/* Initialize with new settings. */ /* Initialize with new settings. */
hwiniterr = serial_hw_init (); err = port->driver->configure (port, &config);
if (err)
if (hwiniterr == GRUB_ERR_NONE) return err;
#ifndef GRUB_MACHINE_EMU
/* Compatibility kludge. */
if (port->driver == &grub_ns8250_driver)
{ {
/* Register terminal if not yet registered. */ if (!registered)
if (registered == 0)
{ {
grub_term_register_input ("serial", &grub_serial_term_input); grub_term_register_input ("serial", &grub_serial_term_input);
grub_term_register_output ("serial", &grub_serial_term_output); grub_term_register_output ("serial", &grub_serial_term_output);
grub_terminfo_output_register (&grub_serial_term_output, "vt100"); }
grub_serial_terminfo_output.port = port;
grub_serial_terminfo_input.port = port;
registered = 1; registered = 1;
} }
} #endif
else return GRUB_ERR_NONE;
}
grub_err_t
grub_serial_register (struct grub_serial_port *port)
{
struct grub_term_input *in;
struct grub_term_output *out;
struct grub_serial_input_state *indata;
struct grub_serial_output_state *outdata;
in = grub_malloc (sizeof (*in));
if (!in)
return grub_errno;
indata = grub_malloc (sizeof (*indata));
if (!indata)
{ {
/* Initialization with new settings failed. */ grub_free (in);
if (registered == 1) return grub_errno;
{
/* If the terminal is registered, attempt to restore previous
settings. */
serial_settings = backup_settings;
if (serial_hw_init () != GRUB_ERR_NONE)
{
/* If unable to restore settings, unregister terminal. */
grub_term_unregister_input (&grub_serial_term_input);
grub_term_unregister_output (&grub_serial_term_output);
grub_terminfo_output_unregister (&grub_serial_term_output);
registered = 0;
}
}
} }
return hwiniterr; grub_memcpy (in, &grub_serial_term_input, sizeof (*in));
in->data = indata;
in->name = grub_xasprintf ("serial_%s", port->name);
grub_memcpy (indata, &grub_serial_terminfo_input, sizeof (*indata));
if (!in->name)
{
grub_free (in);
grub_free (indata);
return grub_errno;
}
out = grub_malloc (sizeof (*out));
if (!out)
{
grub_free (in);
grub_free (indata);
grub_free ((char *) in->name);
return grub_errno;
}
outdata = grub_malloc (sizeof (*outdata));
if (!outdata)
{
grub_free (in);
grub_free (indata);
grub_free ((char *) in->name);
grub_free (out);
return grub_errno;
}
grub_memcpy (out, &grub_serial_term_output, sizeof (*out));
out->data = outdata;
out->name = in->name;
grub_memcpy (outdata, &grub_serial_terminfo_output, sizeof (*outdata));
grub_list_push (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port));
((struct grub_serial_input_state *) in->data)->port = port;
((struct grub_serial_output_state *) out->data)->port = port;
port->term_in = in;
port->term_out = out;
grub_terminfo_output_register (out, "vt100");
#ifdef GRUB_MACHINE_MIPS_YEELOONG
if (grub_strcmp (port->name, "com0") == 0)
{
grub_term_register_input_active ("serial_*", in);
grub_term_register_output_active ("serial_*", out);
}
else
#endif
{
grub_term_register_input ("serial_*", in);
grub_term_register_output ("serial_*", out);
}
return GRUB_ERR_NONE;
}
void
grub_serial_unregister (struct grub_serial_port *port)
{
if (port->driver->fini)
port->driver->fini (port);
if (port->term_in)
grub_term_unregister_input (port->term_in);
if (port->term_out)
grub_term_unregister_output (port->term_out);
grub_list_remove (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port));
}
void
grub_serial_unregister_driver (struct grub_serial_driver *driver)
{
struct grub_serial_port *port, *next;
for (port = grub_serial_ports; port; port = next)
{
next = port->next;
if (port->driver == driver)
grub_serial_unregister (port);
}
} }
static grub_extcmd_t cmd; static grub_extcmd_t cmd;
@ -359,41 +345,19 @@ GRUB_MOD_INIT(serial)
GRUB_COMMAND_FLAG_BOTH, GRUB_COMMAND_FLAG_BOTH,
N_("[OPTIONS...]"), N_("[OPTIONS...]"),
N_("Configure serial port."), options); N_("Configure serial port."), options);
#ifndef GRUB_MACHINE_EMU
/* Set default settings. */ grub_ns8250_init ();
serial_settings.port = serial_hw_get_port (0);
#ifdef GRUB_MACHINE_MIPS_YEELOONG
serial_settings.divisor = serial_get_divisor (115200);
#else
serial_settings.divisor = serial_get_divisor (9600);
#endif
serial_settings.word_len = UART_8BITS_WORD;
serial_settings.parity = UART_NO_PARITY;
serial_settings.stop_bits = UART_1_STOP_BIT;
#ifdef GRUB_MACHINE_MIPS_YEELOONG
{
grub_err_t hwiniterr;
hwiniterr = serial_hw_init ();
if (hwiniterr == GRUB_ERR_NONE)
{
grub_term_register_input_active ("serial", &grub_serial_term_input);
grub_term_register_output_active ("serial", &grub_serial_term_output);
registered = 1;
}
}
#endif #endif
} }
GRUB_MOD_FINI(serial) GRUB_MOD_FINI(serial)
{ {
grub_unregister_extcmd (cmd); while (grub_serial_ports)
if (registered == 1) /* Unregister terminal only if registered. */ grub_serial_unregister (grub_serial_ports);
if (registered)
{ {
grub_term_unregister_input (&grub_serial_term_input); grub_term_unregister_input (&grub_serial_term_input);
grub_term_unregister_output (&grub_serial_term_output); grub_term_unregister_output (&grub_serial_term_output);
grub_terminfo_output_unregister (&grub_serial_term_output);
} }
grub_unregister_extcmd (cmd);
} }

View file

@ -195,7 +195,7 @@ putstr (struct grub_term_output *term, const char *str)
struct grub_terminfo_output_state *data struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data; = (struct grub_terminfo_output_state *) term->data;
while (*str) while (*str)
data->put (*str++); data->put (term, *str++);
} }
grub_uint16_t grub_uint16_t
@ -225,7 +225,7 @@ grub_terminfo_gotoxy (struct grub_term_output *term,
else else
{ {
if ((y == data->ypos) && (x == data->xpos - 1)) if ((y == data->ypos) && (x == data->xpos - 1))
data->put ('\b'); data->put (term, '\b');
} }
data->xpos = x; data->xpos = x;
@ -348,20 +348,21 @@ grub_terminfo_putchar (struct grub_term_output *term,
data->xpos = 0; data->xpos = 0;
if (data->ypos < grub_term_height (term) - 1) if (data->ypos < grub_term_height (term) - 1)
data->ypos++; data->ypos++;
data->put ('\r'); data->put (term, '\r');
data->put ('\n'); data->put (term, '\n');
} }
data->xpos += c->estimated_width; data->xpos += c->estimated_width;
break; break;
} }
data->put (c->base); data->put (term, c->base);
} }
#define ANSI_C0 0x9b #define ANSI_C0 0x9b
static void static void
grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void)) grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
int (*readkey) (struct grub_term_input *term))
{ {
int c; int c;
@ -371,7 +372,7 @@ grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void))
/* On 9600 we have to wait up to 12 milliseconds. */ \ /* On 9600 we have to wait up to 12 milliseconds. */ \
start = grub_get_time_ms (); \ start = grub_get_time_ms (); \
do \ do \
c = readkey (); \ c = readkey (term); \
while (c == -1 && grub_get_time_ms () - start < 12); \ while (c == -1 && grub_get_time_ms () - start < 12); \
if (c == -1) \ if (c == -1) \
return; \ return; \
@ -380,7 +381,7 @@ grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void))
(*len)++; \ (*len)++; \
} }
c = readkey (); c = readkey (term);
if (c < 0) if (c < 0)
{ {
*len = 0; *len = 0;
@ -475,7 +476,8 @@ grub_terminfo_checkkey (struct grub_term_input *termi)
if (data->npending) if (data->npending)
return data->input_buf[0]; return data->input_buf[0];
grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey); grub_terminfo_readkey (termi, data->input_buf,
&data->npending, data->readkey);
if (data->npending) if (data->npending)
return data->input_buf[0]; return data->input_buf[0];
@ -491,7 +493,8 @@ grub_terminfo_getkey (struct grub_term_input *termi)
= (struct grub_terminfo_input_state *) (termi->data); = (struct grub_terminfo_input_state *) (termi->data);
int ret; int ret;
while (! data->npending) while (! data->npending)
grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey); grub_terminfo_readkey (termi, data->input_buf, &data->npending,
data->readkey);
ret = data->input_buf[0]; ret = data->input_buf[0];
data->npending--; data->npending--;

View file

@ -54,12 +54,6 @@ static char keyboard_map_shift[128] =
'?' '?'
}; };
static grub_usb_device_t usbdev;
/* Valid values for bmRequestType. See HID definition version 1.11 section
7.2. */
#define USB_HID_HOST_TO_DEVICE 0x21
#define USB_HID_DEVICE_TO_HOST 0xA1
/* Valid values for bRequest. See HID definition version 1.11 section 7.2. */ /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
#define USB_HID_GET_REPORT 0x01 #define USB_HID_GET_REPORT 0x01
@ -69,78 +63,176 @@ static grub_usb_device_t usbdev;
#define USB_HID_SET_IDLE 0x0A #define USB_HID_SET_IDLE 0x0A
#define USB_HID_SET_PROTOCOL 0x0B #define USB_HID_SET_PROTOCOL 0x0B
static void #define USB_HID_BOOT_SUBCLASS 0x01
grub_usb_hid (void) #define USB_HID_KBD_PROTOCOL 0x01
{
struct grub_usb_desc_device *descdev;
auto int usb_iterate (grub_usb_device_t dev); static int grub_usb_keyboard_checkkey (struct grub_term_input *term);
int usb_iterate (grub_usb_device_t dev) static int grub_usb_keyboard_getkey (struct grub_term_input *term);
static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term);
static struct grub_term_input grub_usb_keyboard_term =
{ {
descdev = &dev->descdev; .checkkey = grub_usb_keyboard_checkkey,
.getkey = grub_usb_keyboard_getkey,
.getkeystatus = grub_usb_keyboard_getkeystatus,
.next = 0
};
grub_dprintf ("usb_keyboard", "%x %x %x\n", struct grub_usb_keyboard_data
descdev->class, descdev->subclass, descdev->protocol); {
grub_usb_device_t usbdev;
grub_uint8_t status;
int key;
struct grub_usb_desc_endp *endp;
};
#if 0 static struct grub_term_input grub_usb_keyboards[16];
if (descdev->class != 0x09
|| descdev->subclass == 0x01
|| descdev->protocol != 0x02)
return 0;
#endif
if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0) static void
return 0; grub_usb_keyboard_detach (grub_usb_device_t usbdev,
int config __attribute__ ((unused)),
int interface __attribute__ ((unused)))
{
unsigned i;
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
{
struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
grub_printf ("HID found!\n"); if (!data)
continue;
usbdev = dev; if (data->usbdev != usbdev)
continue;
return 1; grub_term_unregister_input (&grub_usb_keyboards[i]);
grub_free ((char *) grub_usb_keyboards[i].name);
grub_usb_keyboards[i].name = NULL;
grub_free (grub_usb_keyboards[i].data);
grub_usb_keyboards[i].data = 0;
} }
grub_usb_iterate (usb_iterate);
/* Place the device in boot mode. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_PROTOCOL,
0, 0, 0, 0);
/* Reports every time an event occurs and not more often than that. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
0<<8, 0, 0, 0);
} }
static grub_err_t static int
grub_usb_keyboard_getreport (grub_usb_device_t dev, grub_uint8_t *report) grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
{ {
return grub_usb_control_msg (dev, USB_HID_DEVICE_TO_HOST, USB_HID_GET_REPORT, unsigned curnum;
0, 0, 8, (char *) report); struct grub_usb_keyboard_data *data;
struct grub_usb_desc_endp *endp = NULL;
int j;
grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
usbdev->descdev.class, usbdev->descdev.subclass,
usbdev->descdev.protocol, configno, interfno);
for (curnum = 0; curnum < ARRAY_SIZE (grub_usb_keyboards); curnum++)
if (!grub_usb_keyboards[curnum].data)
break;
if (curnum == ARRAY_SIZE (grub_usb_keyboards))
return 0;
if (usbdev->descdev.class != 0
|| usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
return 0;
if (usbdev->config[configno].interf[interfno].descif->subclass
!= USB_HID_BOOT_SUBCLASS
|| usbdev->config[configno].interf[interfno].descif->protocol
!= USB_HID_KBD_PROTOCOL)
return 0;
for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt;
j++)
{
endp = &usbdev->config[configno].interf[interfno].descendp[j];
if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
== GRUB_USB_EP_INTERRUPT)
break;
}
if (j == usbdev->config[configno].interf[interfno].descif->endpointcnt)
return 0;
grub_dprintf ("usb_keyboard", "HID found!\n");
data = grub_malloc (sizeof (*data));
if (!data)
{
grub_print_error ();
return 0;
}
data->usbdev = usbdev;
data->endp = endp;
/* Place the device in boot mode. */
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
USB_HID_SET_PROTOCOL, 0, 0, 0, 0);
/* Reports every time an event occurs and not more often than that. */
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
USB_HID_SET_IDLE, 0<<8, 0, 0, 0);
grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
sizeof (grub_usb_keyboards[curnum]));
grub_usb_keyboards[curnum].data = data;
usbdev->config[configno].interf[interfno].detach_hook
= grub_usb_keyboard_detach;
grub_usb_keyboards[curnum].name = grub_xasprintf ("usb_keyboard%d", curnum);
if (!grub_usb_keyboards[curnum].name)
{
grub_print_error ();
return 0;
}
{
grub_uint8_t report[8];
grub_usb_err_t err;
grub_memset (report, 0, sizeof (report));
err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN,
USB_HID_GET_REPORT, 0x0000, interfno,
sizeof (report), (char *) report);
if (err)
{
data->status = 0;
data->key = -1;
}
else
{
data->status = report[0];
data->key = report[2] ? : -1;
}
}
grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
return 1;
} }
static int static int
grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused))) grub_usb_keyboard_checkkey (struct grub_term_input *term)
{ {
grub_uint8_t data[8]; grub_uint8_t data[8];
int key; grub_usb_err_t err;
grub_err_t err; struct grub_usb_keyboard_data *termdata = term->data;
grub_uint64_t currtime; grub_size_t actual;
int timeout = 50;
if (termdata->key != -1)
return termdata->key;
data[2] = 0; data[2] = 0;
currtime = grub_get_time_ms (); /* Poll interrupt pipe. */
do err = grub_usb_bulk_read_extended (termdata->usbdev,
{ termdata->endp->endp_addr, sizeof (data),
/* Get_Report. */ (char *) data, 10, &actual);
err = grub_usb_keyboard_getreport (usbdev, data); if (err || actual < 1)
return -1;
/* Implement a timeout. */ termdata->status = data[0];
if (grub_get_time_ms () > currtime + timeout)
break;
}
while (err || !data[2]);
if (err || !data[2]) if (actual < 3 || !data[2])
return -1; return -1;
grub_dprintf ("usb_keyboard", grub_dprintf ("usb_keyboard",
@ -151,178 +243,74 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused)
/* Check if the Control or Shift key was pressed. */ /* Check if the Control or Shift key was pressed. */
if (data[0] & 0x01 || data[0] & 0x10) if (data[0] & 0x01 || data[0] & 0x10)
key = keyboard_map[data[2]] - 'a' + 1; termdata->key = keyboard_map[data[2]] - 'a' + 1;
else if (data[0] & 0x02 || data[0] & 0x20) else if (data[0] & 0x02 || data[0] & 0x20)
key = keyboard_map_shift[data[2]]; termdata->key = keyboard_map_shift[data[2]];
else else
key = keyboard_map[data[2]]; termdata->key = keyboard_map[data[2]];
if (key == 0) if (termdata->key == 0)
grub_printf ("Unknown key 0x%x detected\n", data[2]); grub_printf ("Unknown key 0x%x detected\n", data[2]);
#if 0
/* Wait until the key is released. */
while (!err && data[2])
{
err = grub_usb_control_msg (usbdev, USB_HID_DEVICE_TO_HOST,
USB_HID_GET_REPORT, 0, 0,
sizeof (data), (char *) data);
grub_dprintf ("usb_keyboard",
"report2: 0x%02x 0x%02x 0x%02x 0x%02x"
" 0x%02x 0x%02x 0x%02x 0x%02x\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7]);
}
#endif
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
return key; return termdata->key;
} }
typedef enum
{
GRUB_HIDBOOT_REPEAT_NONE,
GRUB_HIDBOOT_REPEAT_FIRST,
GRUB_HIDBOOT_REPEAT
} grub_usb_keyboard_repeat_t;
static int static int
grub_usb_keyboard_getkey (struct grub_term_input *term) grub_usb_keyboard_getkey (struct grub_term_input *term)
{ {
int key; int ret;
grub_err_t err; struct grub_usb_keyboard_data *termdata = term->data;
grub_uint8_t data[8];
grub_uint64_t currtime;
int timeout;
static grub_usb_keyboard_repeat_t repeat = GRUB_HIDBOOT_REPEAT_NONE;
again: while (termdata->key == -1)
grub_usb_keyboard_checkkey (term);
do ret = termdata->key;
{
key = grub_usb_keyboard_checkkey (term);
} while (key == -1);
data[2] = !0; /* Or whatever. */ termdata->key = -1;
err = 0;
switch (repeat) return ret;
{
case GRUB_HIDBOOT_REPEAT_FIRST:
timeout = 500;
break;
case GRUB_HIDBOOT_REPEAT:
timeout = 50;
break;
default:
timeout = 100;
break;
}
/* Wait until the key is released. */
currtime = grub_get_time_ms ();
while (!err && data[2])
{
/* Implement a timeout. */
if (grub_get_time_ms () > currtime + timeout)
{
if (repeat == 0)
repeat = 1;
else
repeat = 2;
grub_errno = GRUB_ERR_NONE;
return key;
}
err = grub_usb_keyboard_getreport (usbdev, data);
}
if (repeat)
{
repeat = 0;
goto again;
}
repeat = 0;
grub_errno = GRUB_ERR_NONE;
return key;
} }
static int static int
grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unused))) grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
{ {
grub_uint8_t data[8]; struct grub_usb_keyboard_data *termdata = term->data;
int mods = 0; int mods = 0;
grub_err_t err;
grub_uint64_t currtime;
int timeout = 50;
/* Set idle time to the minimum offered by the spec (4 milliseconds) so
that we can find out the current state. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
0<<8, 0, 0, 0);
currtime = grub_get_time_ms ();
do
{
/* Get_Report. */
err = grub_usb_keyboard_getreport (usbdev, data);
/* Implement a timeout. */
if (grub_get_time_ms () > currtime + timeout)
break;
}
while (err || !data[0]);
/* Go back to reporting every time an event occurs and not more often than
that. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
0<<8, 0, 0, 0);
/* We allowed a while for modifiers to show up in the report, but it is
not an error if they never did. */
if (err)
return -1;
grub_dprintf ("usb_keyboard",
"report: 0x%02x 0x%02x 0x%02x 0x%02x"
" 0x%02x 0x%02x 0x%02x 0x%02x\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7]);
/* Check Shift, Control, and Alt status. */ /* Check Shift, Control, and Alt status. */
if (data[0] & 0x02 || data[0] & 0x20) if (termdata->status & 0x02 || termdata->status & 0x20)
mods |= GRUB_TERM_STATUS_SHIFT; mods |= GRUB_TERM_STATUS_SHIFT;
if (data[0] & 0x01 || data[0] & 0x10) if (termdata->status & 0x01 || termdata->status & 0x10)
mods |= GRUB_TERM_STATUS_CTRL; mods |= GRUB_TERM_STATUS_CTRL;
if (data[0] & 0x04 || data[0] & 0x40) if (termdata->status & 0x04 || termdata->status & 0x40)
mods |= GRUB_TERM_STATUS_ALT; mods |= GRUB_TERM_STATUS_ALT;
grub_errno = GRUB_ERR_NONE;
return mods; return mods;
} }
static struct grub_term_input grub_usb_keyboard_term = struct grub_usb_attach_desc attach_hook =
{ {
.name = "usb_keyboard", .class = GRUB_USB_CLASS_HID,
.checkkey = grub_usb_keyboard_checkkey, .hook = grub_usb_keyboard_attach
.getkey = grub_usb_keyboard_getkey, };
.getkeystatus = grub_usb_keyboard_getkeystatus,
.next = 0
};
GRUB_MOD_INIT(usb_keyboard) GRUB_MOD_INIT(usb_keyboard)
{ {
grub_usb_hid (); grub_usb_register_attach_hook_class (&attach_hook);
grub_term_register_input ("usb_keyboard", &grub_usb_keyboard_term);
} }
GRUB_MOD_FINI(usb_keyboard) GRUB_MOD_FINI(usb_keyboard)
{ {
grub_term_unregister_input (&grub_usb_keyboard_term); unsigned i;
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
if (grub_usb_keyboards[i].data)
{
grub_term_unregister_input (&grub_usb_keyboards[i]);
grub_free ((char *) grub_usb_keyboards[i].name);
grub_usb_keyboards[i].name = NULL;
grub_usb_keyboards[i].data = 0;
}
grub_usb_unregister_attach_hook_class (&attach_hook);
} }

73
include/grub/ns8250.h Normal file
View file

@ -0,0 +1,73 @@
/* serial.h - serial device interface */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2005,2007 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_NS8250_HEADER
#define GRUB_NS8250_HEADER 1
/* Macros. */
/* The offsets of UART registers. */
#define UART_TX 0
#define UART_RX 0
#define UART_DLL 0
#define UART_IER 1
#define UART_DLH 1
#define UART_IIR 2
#define UART_FCR 2
#define UART_LCR 3
#define UART_MCR 4
#define UART_LSR 5
#define UART_MSR 6
#define UART_SR 7
/* For LSR bits. */
#define UART_DATA_READY 0x01
#define UART_EMPTY_TRANSMITTER 0x20
/* The type of parity. */
#define UART_NO_PARITY 0x00
#define UART_ODD_PARITY 0x08
#define UART_EVEN_PARITY 0x18
/* The type of word length. */
#define UART_5BITS_WORD 0x00
#define UART_6BITS_WORD 0x01
#define UART_7BITS_WORD 0x02
#define UART_8BITS_WORD 0x03
/* The type of the length of stop bit. */
#define UART_1_STOP_BIT 0x00
#define UART_2_STOP_BITS 0x04
/* the switch of DLAB. */
#define UART_DLAB 0x80
/* Enable the FIFO. */
#define UART_ENABLE_FIFO_TRIGGER14 0xC7
/* Enable the FIFO. */
#define UART_ENABLE_FIFO_TRIGGER1 0x07
/* Turn on DTR, RTS, and OUT2. */
#define UART_ENABLE_DTRRTS 0x03
/* Turn on DTR, RTS, and OUT2. */
#define UART_ENABLE_OUT2 0x08
#endif /* ! GRUB_SERIAL_MACHINE_HEADER */

View file

@ -1,7 +1,7 @@
/* serial.h - serial device interface */ /* serial.h - serial device interface */
/* /*
* GRUB -- GRand Unified Bootloader * GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2005,2007 Free Software Foundation, Inc. * Copyright (C) 2010 Free Software Foundation, Inc.
* *
* GRUB is free software: you can redistribute it and/or modify * GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,54 +20,100 @@
#ifndef GRUB_SERIAL_HEADER #ifndef GRUB_SERIAL_HEADER
#define GRUB_SERIAL_HEADER 1 #define GRUB_SERIAL_HEADER 1
/* Macros. */ #include <grub/types.h>
#include <grub/cpu/io.h>
#include <grub/usb.h>
#include <grub/list.h>
#include <grub/term.h>
/* The offsets of UART registers. */ struct grub_serial_port;
#define UART_TX 0 struct grub_serial_config;
#define UART_RX 0
#define UART_DLL 0
#define UART_IER 1
#define UART_DLH 1
#define UART_IIR 2
#define UART_FCR 2
#define UART_LCR 3
#define UART_MCR 4
#define UART_LSR 5
#define UART_MSR 6
#define UART_SR 7
/* For LSR bits. */ struct grub_serial_driver
#define UART_DATA_READY 0x01 {
#define UART_EMPTY_TRANSMITTER 0x20 grub_err_t (*configure) (struct grub_serial_port *port,
struct grub_serial_config *config);
int (*fetch) (struct grub_serial_port *port);
void (*put) (struct grub_serial_port *port, const int c);
void (*fini) (struct grub_serial_port *port);
};
/* The type of parity. */ /* The type of parity. */
#define UART_NO_PARITY 0x00 typedef enum
#define UART_ODD_PARITY 0x08 {
#define UART_EVEN_PARITY 0x18 GRUB_SERIAL_PARITY_NONE,
GRUB_SERIAL_PARITY_ODD,
GRUB_SERIAL_PARITY_EVEN,
} grub_serial_parity_t;
/* The type of word length. */ typedef enum
#define UART_5BITS_WORD 0x00 {
#define UART_6BITS_WORD 0x01 GRUB_SERIAL_STOP_BITS_1,
#define UART_7BITS_WORD 0x02 GRUB_SERIAL_STOP_BITS_2,
#define UART_8BITS_WORD 0x03 } grub_serial_stop_bits_t;
/* The type of the length of stop bit. */ struct grub_serial_config
#define UART_1_STOP_BIT 0x00 {
#define UART_2_STOP_BITS 0x04 unsigned speed;
int word_len;
grub_serial_parity_t parity;
grub_serial_stop_bits_t stop_bits;
};
/* the switch of DLAB. */ struct grub_serial_port
#define UART_DLAB 0x80 {
struct grub_serial_port *next;
char *name;
struct grub_serial_driver *driver;
struct grub_serial_config config;
int configured;
/* This should be void *data but since serial is useful as an early console
when malloc isn't available it's a union.
*/
union
{
grub_port_t port;
struct
{
grub_usb_device_t usbdev;
int configno;
int interfno;
char buf[64];
int bufstart, bufend;
struct grub_usb_desc_endp *in_endp;
struct grub_usb_desc_endp *out_endp;
};
};
grub_term_output_t term_out;
grub_term_input_t term_in;
};
/* Enable the FIFO. */ grub_err_t EXPORT_FUNC(grub_serial_register) (struct grub_serial_port *port);
#define UART_ENABLE_FIFO_TRIGGER14 0xC7
/* Enable the FIFO. */ void EXPORT_FUNC(grub_serial_unregister) (struct grub_serial_port *port);
#define UART_ENABLE_FIFO_TRIGGER1 0x07
/* Turn on DTR, RTS, and OUT2. */ /* Set default settings. */
#define UART_ENABLE_DTRRTS 0x03 static inline grub_err_t
grub_serial_config_defaults (struct grub_serial_port *port)
{
struct grub_serial_config config =
{
#ifdef GRUB_MACHINE_MIPS_YEELOONG
.speed = 115200,
#else
.speed = 9600,
#endif
.word_len = 8,
.parity = GRUB_SERIAL_PARITY_NONE,
.stop_bits = GRUB_SERIAL_STOP_BITS_1
};
/* Turn on DTR, RTS, and OUT2. */ return port->driver->configure (port, &config);
#define UART_ENABLE_OUT2 0x08 }
#endif /* ! GRUB_SERIAL_MACHINE_HEADER */ void grub_ns8250_init (void);
char *grub_serial_ns8250_add_port (grub_port_t port);
extern struct grub_serial_driver grub_ns8250_driver;
void EXPORT_FUNC(grub_serial_unregister_driver) (struct grub_serial_driver *driver);
#endif

View file

@ -459,6 +459,7 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces)
grub_putcode (' ', term); grub_putcode (' ', term);
} }
extern void (*EXPORT_VAR (grub_term_poll_usb)) (void);
/* For convenience. */ /* For convenience. */
#define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) #define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff)

View file

@ -32,7 +32,7 @@ struct grub_terminfo_input_state
{ {
int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN]; int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN];
int npending; int npending;
int (*readkey) (void); int (*readkey) (struct grub_term_input *term);
}; };
struct grub_terminfo_output_state struct grub_terminfo_output_state
@ -51,7 +51,7 @@ struct grub_terminfo_output_state
unsigned int xpos, ypos; unsigned int xpos, ypos;
void (*put) (const int c); void (*put) (struct grub_term_output *term, const int c);
}; };
void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_term_output_t term, void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_term_output_t term,

View file

@ -19,6 +19,7 @@
#ifndef GRUB_USB_H #ifndef GRUB_USB_H
#define GRUB_USB_H 1 #define GRUB_USB_H 1
#include <grub/err.h>
#include <grub/usbdesc.h> #include <grub/usbdesc.h>
#include <grub/usbtrans.h> #include <grub/usbtrans.h>
@ -47,6 +48,14 @@ typedef enum
GRUB_USB_SPEED_HIGH GRUB_USB_SPEED_HIGH
} grub_usb_speed_t; } grub_usb_speed_t;
enum
{
GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = 0x21,
GRUB_USB_REQTYPE_VENDOR_OUT = 0x40,
GRUB_USB_REQTYPE_CLASS_INTERFACE_IN = 0xa1,
GRUB_USB_REQTYPE_VENDOR_IN = 0xc0
};
/* Call HOOK with each device, until HOOK returns non-zero. */ /* Call HOOK with each device, until HOOK returns non-zero. */
int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)); int grub_usb_iterate (int (*hook) (grub_usb_device_t dev));
@ -97,7 +106,8 @@ struct grub_usb_controller_dev
int (*iterate) (int (*hook) (grub_usb_controller_t dev)); int (*iterate) (int (*hook) (grub_usb_controller_t dev));
grub_usb_err_t (*transfer) (grub_usb_controller_t dev, grub_usb_err_t (*transfer) (grub_usb_controller_t dev,
grub_usb_transfer_t transfer); grub_usb_transfer_t transfer,
int timeout, grub_size_t *actual);
int (*hubports) (grub_usb_controller_t dev); int (*hubports) (grub_usb_controller_t dev);
@ -132,6 +142,8 @@ struct grub_usb_interface
int attached; int attached;
void (*detach_hook) (struct grub_usb_device *dev, int config, int interface); void (*detach_hook) (struct grub_usb_device *dev, int config, int interface);
void *detach_data;
}; };
struct grub_usb_configuration struct grub_usb_configuration
@ -166,12 +178,32 @@ struct grub_usb_device
/* Data toggle values (used for bulk transfers only). */ /* Data toggle values (used for bulk transfers only). */
int toggle[256]; int toggle[256];
/* Device-specific data. */ /* Used by libusb wrapper. Schedulded for removal. */
void *data; void *data;
/* Array of children for a hub. */
grub_usb_device_t *children;
/* Number of hub ports. */
unsigned nports;
}; };
typedef enum grub_usb_ep_type
{
GRUB_USB_EP_CONTROL,
GRUB_USB_EP_ISOCHRONOUS,
GRUB_USB_EP_BULK,
GRUB_USB_EP_INTERRUPT
} grub_usb_ep_type_t;
static inline enum grub_usb_ep_type
grub_usb_get_ep_type (struct grub_usb_desc_endp *ep)
{
return ep->attrib & 3;
}
typedef enum typedef enum
{ {
GRUB_USB_CLASS_NOTHERE, GRUB_USB_CLASS_NOTHERE,
@ -230,5 +262,9 @@ void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc);
void grub_usb_poll_devices (void); void grub_usb_poll_devices (void);
void grub_usb_device_attach (grub_usb_device_t dev); void grub_usb_device_attach (grub_usb_device_t dev);
grub_usb_err_t
grub_usb_bulk_read_extended (grub_usb_device_t dev,
int endpoint, grub_size_t size, char *data,
int timeout, grub_size_t *actual);
#endif /* GRUB_USB_H */ #endif /* GRUB_USB_H */

View file

@ -31,6 +31,12 @@ typedef enum {
GRUB_USB_DESCRIPTOR_HUB = 0x29 GRUB_USB_DESCRIPTOR_HUB = 0x29
} grub_usb_descriptor_t; } grub_usb_descriptor_t;
struct grub_usb_desc
{
grub_uint8_t length;
grub_uint8_t type;
} __attribute__ ((packed));
struct grub_usb_desc_device struct grub_usb_desc_device
{ {
grub_uint8_t length; grub_uint8_t length;

34
include/grub/usbserial.h Normal file
View file

@ -0,0 +1,34 @@
/* serial.h - serial device interface */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_USBSERIAL_HEADER
#define GRUB_USBSERIAL_HEADER 1
void grub_usbserial_fini (struct grub_serial_port *port);
void grub_usbserial_detach (grub_usb_device_t usbdev, int configno,
int interfno);
int
grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
struct grub_serial_driver *driver);
int
grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size);
#endif

View file

@ -38,6 +38,7 @@ struct grub_usb_transaction
int toggle; int toggle;
grub_transfer_type_t pid; grub_transfer_type_t pid;
grub_uint32_t data; grub_uint32_t data;
grub_size_t preceding;
}; };
typedef struct grub_usb_transaction *grub_usb_transaction_t; typedef struct grub_usb_transaction *grub_usb_transaction_t;

View file

@ -39,6 +39,31 @@ case "${GRUB_DISTRIBUTOR}" in
;; ;;
esac esac
load_kfreebsd_module ()
{
mod="$1"
allow_fail="$2"
if ! test -e "${module_dir}/${mod}.ko" ; then
if [ "${allow_fail}" = "true" ] ; then
# Return silently
return
else
# Print an error and fail.
ls "${module_dir}/${mod}.ko" > /dev/null
fi
fi
if [ -z "${prepare_module_dir_cache}" ]; then
prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")"
fi
printf '%s\n' "${prepare_module_dir_cache}"
cat << EOF
kfreebsd_module_elf ${module_dir_rel}/${mod}.ko
EOF
}
kfreebsd_entry () kfreebsd_entry ()
{ {
os="$1" os="$1"
@ -51,9 +76,6 @@ kfreebsd_entry ()
if [ -z "${prepare_boot_cache}" ]; then if [ -z "${prepare_boot_cache}" ]; then
prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
fi fi
if [ -z "${prepare_module_dir_cache}" ]; then
prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")"
fi
printf '%s\n' "${prepare_boot_cache}" printf '%s\n' "${prepare_boot_cache}"
cat << EOF cat << EOF
@ -67,26 +89,13 @@ EOF
EOF EOF
fi fi
if test -e "${module_dir}/acpi.ko" ; then load_kfreebsd_module acpi true
printf '%s\n' "${prepare_module_dir_cache}"
cat << EOF
kfreebsd_module_elf ${module_dir_rel}/acpi.ko
EOF
fi
case "${kfreebsd_fs}" in case "${kfreebsd_fs}" in
zfs) zfs)
for i in "${module_dir}/opensolaris.ko" "${module_dir}/zfs.ko" \ load_kfreebsd_module opensolaris false
"${dirname}/zfs/zpool.cache" ; do
ls "$i" > /dev/null
done
printf '%s\n' "${prepare_module_dir_cache}"
cat << EOF
kfreebsd_module_elf ${module_dir_rel}/opensolaris.ko
kfreebsd_module_elf ${module_dir_rel}/zfs.ko
EOF
ls "${dirname}/zfs/zpool.cache" > /dev/null
printf '%s\n' "${prepare_boot_cache}" printf '%s\n' "${prepare_boot_cache}"
cat << EOF cat << EOF
kfreebsd_module ${rel_dirname}/zfs/zpool.cache type=/boot/zfs/zpool.cache kfreebsd_module ${rel_dirname}/zfs/zpool.cache type=/boot/zfs/zpool.cache
@ -94,6 +103,8 @@ EOF
;; ;;
esac esac
load_kfreebsd_module ${kfreebsd_fs} false
cat << EOF cat << EOF
set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${kfreebsd_device} set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${kfreebsd_device}
set kFreeBSD.vfs.root.mountfrom.options=rw set kFreeBSD.vfs.root.mountfrom.options=rw
@ -122,6 +133,7 @@ while [ "x$list" != "x" ] ; do
case ${GRUB_FS} in case ${GRUB_FS} in
ufs1 | ufs2) kfreebsd_fs=ufs ;; ufs1 | ufs2) kfreebsd_fs=ufs ;;
ext2) kfreebsd_fs=ext2fs ;;
*) kfreebsd_fs=${GRUB_FS} ;; *) kfreebsd_fs=${GRUB_FS} ;;
esac esac