merge with mainline
This commit is contained in:
commit
d84666e6bb
37 changed files with 2533 additions and 641 deletions
134
ChangeLog
134
ChangeLog
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
174
docs/grub.texi
174
docs/grub.texi
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
125
grub-core/bus/usb/serial/common.c
Normal file
125
grub-core/bus/usb/serial/common.c
Normal 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++];
|
||||||
|
}
|
205
grub-core/bus/usb/serial/ftdi.c
Normal file
205
grub-core/bus/usb/serial/ftdi.c
Normal 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);
|
||||||
|
}
|
218
grub-core/bus/usb/serial/pl2303.c
Normal file
218
grub-core/bus/usb/serial/pl2303.c
Normal 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);
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
384
grub-core/commands/i386/pc/sendkey.c
Normal file
384
grub-core/commands/i386/pc/sendkey.c
Normal 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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
253
grub-core/term/ns8250.c
Normal 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;
|
||||||
|
}
|
|
@ -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,155 +41,20 @@ 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)
|
||||||
{
|
{
|
||||||
.readkey = serial_hw_fetch
|
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 =
|
||||||
|
{
|
||||||
|
.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;
|
||||||
{
|
|
||||||
/* Initialization with new settings failed. */
|
|
||||||
if (registered == 1)
|
|
||||||
{
|
|
||||||
/* 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_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)
|
||||||
|
{
|
||||||
|
grub_free (in);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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--;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
#define USB_HID_BOOT_SUBCLASS 0x01
|
||||||
|
#define USB_HID_KBD_PROTOCOL 0x01
|
||||||
|
|
||||||
|
static int grub_usb_keyboard_checkkey (struct grub_term_input *term);
|
||||||
|
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 =
|
||||||
|
{
|
||||||
|
.checkkey = grub_usb_keyboard_checkkey,
|
||||||
|
.getkey = grub_usb_keyboard_getkey,
|
||||||
|
.getkeystatus = grub_usb_keyboard_getkeystatus,
|
||||||
|
.next = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
struct grub_usb_keyboard_data
|
||||||
|
{
|
||||||
|
grub_usb_device_t usbdev;
|
||||||
|
grub_uint8_t status;
|
||||||
|
int key;
|
||||||
|
struct grub_usb_desc_endp *endp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct grub_term_input grub_usb_keyboards[16];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grub_usb_hid (void)
|
grub_usb_keyboard_detach (grub_usb_device_t usbdev,
|
||||||
|
int config __attribute__ ((unused)),
|
||||||
|
int interface __attribute__ ((unused)))
|
||||||
{
|
{
|
||||||
struct grub_usb_desc_device *descdev;
|
unsigned i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
|
||||||
auto int usb_iterate (grub_usb_device_t dev);
|
|
||||||
int usb_iterate (grub_usb_device_t dev)
|
|
||||||
{
|
{
|
||||||
descdev = &dev->descdev;
|
struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
|
||||||
|
|
||||||
grub_dprintf ("usb_keyboard", "%x %x %x\n",
|
if (!data)
|
||||||
descdev->class, descdev->subclass, descdev->protocol);
|
continue;
|
||||||
|
|
||||||
#if 0
|
if (data->usbdev != usbdev)
|
||||||
if (descdev->class != 0x09
|
continue;
|
||||||
|| descdev->subclass == 0x01
|
|
||||||
|| descdev->protocol != 0x02)
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0)
|
grub_term_unregister_input (&grub_usb_keyboards[i]);
|
||||||
return 0;
|
grub_free ((char *) grub_usb_keyboards[i].name);
|
||||||
|
grub_usb_keyboards[i].name = NULL;
|
||||||
grub_printf ("HID found!\n");
|
grub_free (grub_usb_keyboards[i].data);
|
||||||
|
grub_usb_keyboards[i].data = 0;
|
||||||
usbdev = dev;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
grub_usb_iterate (usb_iterate);
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||||
|
{
|
||||||
|
unsigned curnum;
|
||||||
|
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. */
|
/* Place the device in boot mode. */
|
||||||
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_PROTOCOL,
|
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||||
0, 0, 0, 0);
|
USB_HID_SET_PROTOCOL, 0, 0, 0, 0);
|
||||||
|
|
||||||
/* Reports every time an event occurs and not more often than that. */
|
/* 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,
|
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||||
0<<8, 0, 0, 0);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
|
||||||
grub_usb_keyboard_getreport (grub_usb_device_t dev, grub_uint8_t *report)
|
|
||||||
{
|
{
|
||||||
return grub_usb_control_msg (dev, USB_HID_DEVICE_TO_HOST, USB_HID_GET_REPORT,
|
grub_uint8_t report[8];
|
||||||
0, 0, 8, (char *) report);
|
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
73
include/grub/ns8250.h
Normal 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 */
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
34
include/grub/usbserial.h
Normal 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
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue