[coreboot] r55 - in trunk: . filo filo/Documentation filo/configs filo/drivers filo/drivers/flash filo/drivers/newusb filo/drivers/usb filo/fs filo/i386 filo/i386/include filo/i386/include/arch filo/include filo/include/grub filo/main filo/main/grub filo/util filo/util/kconfig filo/util/kconfig/lxdialog

svn at coreboot.org svn at coreboot.org
Fri Aug 29 15:36:26 CEST 2008


Author: stepan
Date: 2008-08-29 15:36:25 +0200 (Fri, 29 Aug 2008)
New Revision: 55

Added:
   trunk/filo/
   trunk/filo/Config.in
   trunk/filo/Documentation/
   trunk/filo/Documentation/CHANGES
   trunk/filo/Documentation/COPYING
   trunk/filo/Documentation/FAQ
   trunk/filo/Documentation/TODO
   trunk/filo/Makefile
   trunk/filo/README
   trunk/filo/build.sh
   trunk/filo/configs/
   trunk/filo/configs/config.grub
   trunk/filo/configs/config.nogrub
   trunk/filo/configs/defconfig
   trunk/filo/drivers/
   trunk/filo/drivers/Makefile.inc
   trunk/filo/drivers/flash/
   trunk/filo/drivers/flash/Makefile.inc
   trunk/filo/drivers/flash/lxflash.c
   trunk/filo/drivers/flash/lxflash.h
   trunk/filo/drivers/ide.c
   trunk/filo/drivers/newusb/
   trunk/filo/drivers/newusb/Makefile.inc
   trunk/filo/drivers/newusb/usb.c
   trunk/filo/drivers/usb/
   trunk/filo/drivers/usb/Makefile.inc
   trunk/filo/drivers/usb/debug_x.c
   trunk/filo/drivers/usb/debug_x.h
   trunk/filo/drivers/usb/ohci.c
   trunk/filo/drivers/usb/ohci.h
   trunk/filo/drivers/usb/scsi.h
   trunk/filo/drivers/usb/scsi_cmds.c
   trunk/filo/drivers/usb/scsi_cmds.h
   trunk/filo/drivers/usb/uhci.c
   trunk/filo/drivers/usb/uhci.h
   trunk/filo/drivers/usb/usb.c
   trunk/filo/drivers/usb/usb.h
   trunk/filo/drivers/usb/usb_scsi_low.c
   trunk/filo/drivers/usb/usb_scsi_low.h
   trunk/filo/drivers/usb/usb_x.c
   trunk/filo/drivers/via-sound.c
   trunk/filo/fs/
   trunk/filo/fs/Makefile.inc
   trunk/filo/fs/blockdev.c
   trunk/filo/fs/eltorito.c
   trunk/filo/fs/fat.h
   trunk/filo/fs/filesys.h
   trunk/filo/fs/fsys_aboot.c
   trunk/filo/fs/fsys_cramfs.c
   trunk/filo/fs/fsys_ext2fs.c
   trunk/filo/fs/fsys_fat.c
   trunk/filo/fs/fsys_iso9660.c
   trunk/filo/fs/fsys_jfs.c
   trunk/filo/fs/fsys_minix.c
   trunk/filo/fs/fsys_reiserfs.c
   trunk/filo/fs/fsys_squashfs.c
   trunk/filo/fs/fsys_xfs.c
   trunk/filo/fs/iso9660.h
   trunk/filo/fs/jfs.h
   trunk/filo/fs/mini_inflate.c
   trunk/filo/fs/mini_inflate.h
   trunk/filo/fs/shared.h
   trunk/filo/fs/squashfs_fs.h
   trunk/filo/fs/squashfs_zlib.c
   trunk/filo/fs/squashfs_zlib.h
   trunk/filo/fs/vfs.c
   trunk/filo/fs/xfs.h
   trunk/filo/i386/
   trunk/filo/i386/Makefile.inc
   trunk/filo/i386/artecboot.c
   trunk/filo/i386/context.c
   trunk/filo/i386/context.h
   trunk/filo/i386/include/
   trunk/filo/i386/include/arch/
   trunk/filo/i386/include/arch/byteorder.h
   trunk/filo/i386/include/arch/elf.h
   trunk/filo/i386/include/arch/eltorito.h
   trunk/filo/i386/include/arch/timer.h
   trunk/filo/i386/ldscript
   trunk/filo/i386/linux_load.c
   trunk/filo/i386/segment.c
   trunk/filo/i386/segment.h
   trunk/filo/i386/switch.S
   trunk/filo/i386/sys_info.c
   trunk/filo/i386/timer.c
   trunk/filo/i386/wince_load.c
   trunk/filo/include/
   trunk/filo/include/artecboot.h
   trunk/filo/include/debug.h
   trunk/filo/include/elf.h
   trunk/filo/include/elf_boot.h
   trunk/filo/include/fs.h
   trunk/filo/include/grub/
   trunk/filo/include/grub/config.h
   trunk/filo/include/grub/mb_header.h
   trunk/filo/include/grub/mb_info.h
   trunk/filo/include/grub/md5.h
   trunk/filo/include/grub/serial.h
   trunk/filo/include/grub/shared.h
   trunk/filo/include/grub/term.h
   trunk/filo/include/grub/terminfo.h
   trunk/filo/include/grub/tparm.h
   trunk/filo/include/ipchecksum.h
   trunk/filo/include/lib.h
   trunk/filo/include/sound.h
   trunk/filo/include/sys_info.h
   trunk/filo/main/
   trunk/filo/main/Makefile.inc
   trunk/filo/main/elfload.c
   trunk/filo/main/elfnote.c
   trunk/filo/main/filo.c
   trunk/filo/main/grub.c
   trunk/filo/main/grub/
   trunk/filo/main/grub/Makefile.inc
   trunk/filo/main/grub/asmstub.c
   trunk/filo/main/grub/builtins.c
   trunk/filo/main/grub/char_io.c
   trunk/filo/main/grub/cmdline.c
   trunk/filo/main/grub/completions.c
   trunk/filo/main/grub/grubcons.c
   trunk/filo/main/grub/md5.c
   trunk/filo/main/grub/serial.c
   trunk/filo/main/grub/stage2.c
   trunk/filo/main/grub/terminfo.c
   trunk/filo/main/grub/tparm.c
   trunk/filo/main/ipchecksum.c
   trunk/filo/main/sound.c
   trunk/filo/main/strtox.c
   trunk/filo/payload.sh
   trunk/filo/util/
   trunk/filo/util/Makefile.inc
   trunk/filo/util/byteorder.h
   trunk/filo/util/checksum_elf.c
   trunk/filo/util/ebchecksum.c
   trunk/filo/util/ebchecksum.h
   trunk/filo/util/kconfig/
   trunk/filo/util/kconfig/Makefile
   trunk/filo/util/kconfig/POTFILES.in
   trunk/filo/util/kconfig/check.sh
   trunk/filo/util/kconfig/conf.c
   trunk/filo/util/kconfig/confdata.c
   trunk/filo/util/kconfig/expr.c
   trunk/filo/util/kconfig/expr.h
   trunk/filo/util/kconfig/gconf.c
   trunk/filo/util/kconfig/gconf.glade
   trunk/filo/util/kconfig/images.c
   trunk/filo/util/kconfig/kconfig_load.c
   trunk/filo/util/kconfig/kxgettext.c
   trunk/filo/util/kconfig/lex.zconf.c_shipped
   trunk/filo/util/kconfig/lkc.h
   trunk/filo/util/kconfig/lkc_proto.h
   trunk/filo/util/kconfig/lxdialog/
   trunk/filo/util/kconfig/lxdialog/BIG.FAT.WARNING
   trunk/filo/util/kconfig/lxdialog/check-lxdialog.sh
   trunk/filo/util/kconfig/lxdialog/checklist.c
   trunk/filo/util/kconfig/lxdialog/dialog.h
   trunk/filo/util/kconfig/lxdialog/inputbox.c
   trunk/filo/util/kconfig/lxdialog/menubox.c
   trunk/filo/util/kconfig/lxdialog/textbox.c
   trunk/filo/util/kconfig/lxdialog/util.c
   trunk/filo/util/kconfig/lxdialog/yesno.c
   trunk/filo/util/kconfig/mconf.c
   trunk/filo/util/kconfig/menu.c
   trunk/filo/util/kconfig/qconf.cc
   trunk/filo/util/kconfig/qconf.h
   trunk/filo/util/kconfig/symbol.c
   trunk/filo/util/kconfig/util.c
   trunk/filo/util/kconfig/zconf.gperf
   trunk/filo/util/kconfig/zconf.hash.c_shipped
   trunk/filo/util/kconfig/zconf.l
   trunk/filo/util/kconfig/zconf.tab.c_shipped
   trunk/filo/util/kconfig/zconf.y
   trunk/filo/util/vmser.c
Log:
open development branch of filo. filo-0.5 is frozen (and obsolete)


Added: trunk/filo/Config.in
===================================================================
--- trunk/filo/Config.in	                        (rev 0)
+++ trunk/filo/Config.in	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,361 @@
+##
+## Copyright (C) 2008 coresystems GmbH
+##
+
+mainmenu "FILO Configuration"
+
+# When (if) we support multiple architectures, this will become an option.
+config TARGET_I386
+	bool
+	default y
+
+config REVIEW
+	bool
+	default n
+
+menu "Interface Options"
+
+config USE_GRUB
+	bool "Use GRUB like interface"
+	default y
+	help
+	  Use GRUB legacy like interface instead of autoboot?
+
+config PROMPT
+	string "Command line prompt"
+	default "filo"
+	depends on USE_GRUB
+	help
+	  Per default, the FILO shell comes up with the prompt
+	    filo>
+	  If you want better GRUB compatibility (ie to pass through
+	  your automated test system, specify 'grub' here instead of
+	  'filo' to get a prompt of
+	    grub>
+
+config MENULST_FILE
+	string "GRUB menu.lst filename"
+	default "hda3:/boot/filo/menu.lst"
+	depends on USE_GRUB
+	help
+	  For VIA Epia-MII CF use:
+	    hde1:/boot/filo/menu.lst
+	
+config MENULST_TIMEOUT
+	int "Timeout for loading menu.lst"
+	default 0
+	depends on USE_GRUB
+	help
+	  Set to 0 to ignore
+
+config USE_MD5_PASSWORDS
+	bool "Use MD5 passwords in menu.lst?"
+	default y
+	depends on USE_GRUB
+	help
+	  Enable this option if your menu.lst passwords are MD5 encrypted.
+
+config USE_AUTOBOOT
+	bool "Autoboot a command line after timeout?"
+	depends on !USE_GRUB
+	default y
+
+config AUTOBOOT_FILE
+	string "Kernel filename and parameters"
+	default "hda1:/vmlinuz root=/dev/hda1 console=tty0 console=ttyS0,115200"
+	depends on !USE_GRUB
+	depends on USE_AUTOBOOT
+	help
+	  #AUTOBOOT_FILE = "mem at 0xfff80000"
+	  #AUTOBOOT_FILE = "hde1 at 0"
+	  #AUTOBOOT_FILE = "uda1:/vmlinuz.elf"
+	  #AUTOBOOT_FILE = "flashb at 0x00400000,0x154a00 console=tty0 console=ttyS0,115200"
+
+config AUTOBOOT_DELAY
+	int "Time in seconds before booting"
+	default 2
+	depends on !USE_GRUB
+	depends on USE_AUTOBOOT
+	help
+	  Time in second before booting AUTOBOOT_FILE
+
+endmenu
+
+menu "Drivers"
+
+config IDE_DISK
+	bool "IDE DISK support"
+	default y
+	help
+	  Driver for hard disk, CompactFlash, and CD-ROM on IDE bus
+
+config IDE_DISK_POLL_DELAY
+	int "IDE disk poll delay"
+	default 0
+	depends on IDE_DISK
+	help
+	  Add a short delay when polling status registers 
+	  (required on some broken SATA controllers)
+	  NOTE: Slows down access significantly, so disable 
+	  whenever possible. Set to 1 if you require this.
+
+config SLOW_SATA
+	bool "Extra delay for SATA"
+	default n
+	depends on IDE_DISK
+	help
+	  SATA drives seem to have problems reporting their spinup.
+	  This will delay FILO start by 5s so the disks have some time to settle.
+	  (required on some broken SATA controllers)
+	  NOTE: Slows down access significantly, so disable 
+	  whenever possible.
+
+config PCMCIA_CF
+	bool "PCMCIA CF (Epia) support"
+	default n
+	depends on IDE_DISK
+	help
+	  Use PCMCIA compact flash on Via Epia MII10000 and MII6000E
+	  This device is referred to as hde.
+
+config USB_NEW_DISK
+	bool "new USB Stack"
+	default y
+	help
+	  Driver for USB Storage
+
+config USB_DISK
+	bool "USB Stack (obsolete?)"
+	default n
+	help
+	  Driver for USB Storage
+
+config FLASH_DISK
+	bool "NAND Flash support"
+	default n
+	help
+	  Driver for Geode NAND flash storage
+
+config SUPPORT_PCI
+	bool "PCI support"
+	default y
+
+config PCI_BRUTE_SCAN
+	bool "Scan all PCI busses"
+	default n
+	depends on SUPPORT_PCI
+	help
+	  Enable this to scan PCI busses above bus 0
+	  AMD64 based boards do need this.
+
+config SUPPORT_SOUND
+	bool "Sound Support"
+	default n
+	depends on SUPPORT_PCI
+
+config VIA_SOUND
+	bool "VIA sound"
+	default n
+	depends on SUPPORT_SOUND
+
+endmenu
+
+menu "Console"
+
+config VGA_CONSOLE
+	bool "VGA Text Console"
+	default y
+
+config PC_KEYBOARD
+	bool "PC Keyboard Support"
+	default y
+
+config SERIAL_CONSOLE
+	bool "Serial Console"
+	default y
+
+config SERIAL_IOBASE
+	hex "Serial Console IO base"
+	depends on SERIAL_CONSOLE
+	default 0x3f8
+
+config SERIAL_SPEED_DEFAULT
+	bool "Use default serial speed"
+	depends on SERIAL_CONSOLE
+	default y
+
+config SERIAL_SPEED
+	int "Serial Speed"
+	depends on SERIAL_CONSOLE
+	depends on !SERIAL_SPEED_DEFAULT
+	default 115200
+
+endmenu
+
+menu "Filesystems"
+
+config FSYS_EXT2FS
+	bool "EXT2 filesystem"
+	default y
+
+config FSYS_FAT
+	bool "FAT (MSDOS) filesystem"
+	default y
+
+config FSYS_JFS
+	bool "JFS"
+	default n
+
+config FSYS_MINIX
+	bool "Minix filesystem"
+	default n
+
+config FSYS_REISERFS
+	bool "ReiserFS"
+	default y
+
+config FSYS_XFS
+	bool "XFS"
+	default n
+
+config FSYS_ISO9660
+	bool "ISO9660 filesystem"
+	default y
+
+config ELTORITO
+	bool "El Torito bootable CDROMs"
+	default y
+	depends on FSYS_ISO9660
+	help
+	  Support for boot disk image in bootable CD-ROM (El Torito)
+
+config FSYS_CRAMFS
+	bool "Compressed RAM filesystem (CRAMFS)"
+	default n
+
+config FSYS_SQUASHFS
+	bool "Squash filesystem"
+	default n
+
+endmenu
+
+menu "Loaders"
+
+config LINUX_LOADER
+	bool "Standard Linux Loader"
+	default y
+	depends on TARGET_I386
+	help
+	  Loader for standard Linux kernel image, a.k.a. /vmlinuz
+
+config WINCE_LOADER
+	bool "Windows CE Loader"
+	default n
+	depends on TARGET_I386
+	help
+	  Loader for Windows CE image
+
+config ARTEC_BOOT
+	bool "Artec Loader"
+	default n
+	depends on TARGET_I386
+	help
+	  Artecboot Loader Support
+
+endmenu
+
+menu "Debugging & Experimental"
+
+config EXPERIMENTAL
+	bool "Enable experimental features"
+	default n
+	help
+	  Select this option to enable experimental code. This may
+	  cause FILO to stop compiling. Enable if you wish to develop
+	  for FILO.
+
+config DEBUG_ALL
+	bool "DEBUG_ALL"
+	select DEBUG_ELFBOOT
+	select DEBUG_ELFNOTE
+	select DEBUG_SEGMENT
+	select DEBUG_SYS_INFO
+	select DEBUG_BLOCKDEV
+	select DEBUG_FSYS_EXT2FS
+	select DEBUG_PCI
+	select DEBUG_VIA_SOUND
+	select DEBUG_LINUXLOAD
+	select DEBUG_IDE
+	select DEBUG_USB
+	select DEBUG_ELTORITO
+	select DEBUG_FLASH
+	select DEBUG_ARTECBOOT
+	default n
+
+config DEBUG_ELFBOOT
+	bool "DEBUG_ELFBOOT"
+	default n
+
+config DEBUG_ELFNOTE
+	bool "DEBUG_ELFNOTE"
+	default n
+
+config DEBUG_SEGMENT
+	bool "DEBUG_SEGMENT"
+	default n
+
+config DEBUG_SYS_INFO
+	bool "DEBUG_SYS_INFO"
+	default n
+
+config DEBUG_BLOCKDEV
+	bool "DEBUG_BLOCKDEV"
+	default n
+
+config DEBUG_FSYS_EXT2FS
+	bool "DEBUG_FSYS_EXT2FS"
+	depends on FSYS_EXT2FS
+	default n
+
+config DEBUG_PCI
+	bool "DEBUG_PCI"
+	depends on SUPPORT_PCI
+	default n
+
+config DEBUG_VIA_SOUND
+	bool "DEBUG_VIA_SOUND"
+	depends on VIA_SOUND
+	default n
+
+config DEBUG_LINUXLOAD
+	bool "DEBUG_LINUXLOAD"
+	depends on LINUX_LOADER
+	default n
+
+config DEBUG_IDE
+	bool "DEBUG_IDE"
+	depends on IDE_DISK
+	default n
+
+config DEBUG_USB
+	bool "DEBUG_USB"
+	depends on USB_DISK
+	default n
+
+config DEBUG_ELTORITO
+	bool "DEBUG_ELTORITO"
+	depends on ELTORITO
+	default n
+
+config DEBUG_FLASH
+	bool "DEBUG_FLASH"
+	depends on FLASH_DISK
+	default n
+
+config DEBUG_ARTECBOOT
+	bool "DEBUG_ARTECBOOT"
+	depends on ARTEC_BOOT
+	default n
+
+endmenu
+

Added: trunk/filo/Documentation/CHANGES
===================================================================
--- trunk/filo/Documentation/CHANGES	                        (rev 0)
+++ trunk/filo/Documentation/CHANGES	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,99 @@
+Version 0.6.0b1 stepan 2008-08-11
+    * Use Kconfig for configuration
+    * Drop recursive Makefiles
+    * Link against libpayload
+    * Proper cross compilation
+    * Support for cramfs, squashfs
+    * Geode LX flash support
+    * Support for Epia-M CF
+    * Tweaks for S-ATA
+    * IDE fixes
+    * Artec Loader
+
+Version 0.5.0 stepan 2006-09-15
+    * gcc 4.x fix
+    * final release
+
+Version 0.5b5 stepan 2006-06-09
+    * fix initial double keyboard press bug
+    * fix compilation without serial console
+    * allow terminal --dumb serial as well as terminal serial --dumb
+    * add MENULST_TIMEOUT. If nonzero it waits a given number of seconds
+      for the user to interact and change the path to menu.lst
+    * if no menu.lst is given, go straight into console
+    * fix pre-grub vga output.
+    * if vga is disabled, enable serial output no matter what menu.lst says.
+    * fix make process so it compiles out of the box on amd64 machines
+      (32bit binary)
+
+Version 0.5b4 stepan, san 2006-05-05
+    * add S-ATA delay option (san)
+    * add initial find and tab completion code (stepan)
+
+Version 0.5b3 stepan 2006-04-29
+    * add S-ATA support for serial driver.
+    * enable USB stack
+    * Documentation updates
+
+Version 0.5b2 stepan 2006-04-28
+    * make grub user interface more Redhatish
+    * add menu.lst password support
+    * drop serial initialization if no speed specified
+    * add USB stack (not used yet but compiling)
+
+Version 0.5b1 stepan 2005-10-01
+    * Integrate grub user interface
+    
+Version 0.4.2 ts1 2003-10-31
+    * Added brute force method of PCI scan (turned off by default.)
+    * Workaround for CD drives that report unusual sector size.
+
+Version 0.4.1 ts1 2003-10-30
+    * Fixed IDE driver for older hard disks (such as WD Caviar 1.2G)
+    * Fixed wrong sector number in the disk read error message
+    * Fixed inaccurate display of hard disk capacity
+    * Fixed behavior of word erase (^W) for one character
+    * Updated README and FAQ
+
+Version 0.4 ts1 2003-10-15
+    * Support for ATAPI CD-ROM.
+    * ISO-9660 filesystem is taken from a GRUB patch by
+      Leonid Lisovskiy <lly at pisem.net>. The filesystem code was originally
+      written by Kousuke Takai <tak at kmc.gr.jp> for GRUB/98 project.
+    * Support for mounting boot disk image of El Torito bootable CD-ROM.
+      ("hdc1" means the boot disk image of the CD-ROM at hdc.)
+    * Support for memory as device, raw device as image, and
+      user-specifiable device offset and length.
+      (eg. boot: mem at 0xfffd0000,0x10000)
+    * PCI support in IDE driver. Now it by default uses PCI enumeration
+      to find the PCI IDE controller, and can use native PCI mode
+      if the controller is configured to this mode by BIOS.
+      To disable this, turn off SUPPORT_PCI.
+    * Fixed Linux loader to boot RedHat 9 kernel properly.
+
+Version 0.3 ts1 2003-10-07
+    * Added loader for Linux bzImage/zImage/Image (a.k.a. /vmlinuz).
+      Many thanks to Steve Gehlbach <steve at nexpath.com> for early
+      work on this.
+    * New "context switch" routine to unify the assembly starters
+      for ELF and Linux, and even the C startup.
+      This reduced the amount of assembly code.
+    * Debug prints are now automatically prefixed with function names.
+    * Lots of internal tweaks.
+
+Version 0.2 ts1 2003-09-19
+    * Added code to pass kernel command line parameter from console.
+    * Changed not to disable automatic boot by ANY key. Now you have to
+      press <Esc> to cancel autoboot. This fixes the problem that FILO
+      gets stuck at boot prompt when a phantom byte is read from
+      a fickle serial or keyboard hardware.
+      Additionaly, now <Enter> key does autoboot immediately.
+    * Fixed build problem with new coreutils.
+      Thanks to Stefan Reinauer <stepan at suse.de>.
+    * Updated fsys_fat.c and fsys_reiserfs.c from GRUB CVS.
+    * Lots of minor tweaks.
+    * Beginning of PCI layer and a sound driver (what??). Don't worry,
+      it doesn't even get compiled with default configuration.
+
+Version 0.1 ts1 2003-08
+    * First public release.

Added: trunk/filo/Documentation/COPYING
===================================================================
--- trunk/filo/Documentation/COPYING	                        (rev 0)
+++ trunk/filo/Documentation/COPYING	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: trunk/filo/Documentation/FAQ
===================================================================
--- trunk/filo/Documentation/FAQ	                        (rev 0)
+++ trunk/filo/Documentation/FAQ	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,11 @@
+Q. My GRUB menu.lst does not work. 
+A. The disks are numbered differently in FILO, following the linux scheme.
+   hd2,0 is hdc1, not necessarily the third disk (there might be no hdb)
+
+Q. FILO loads my ELF kernel fine, but complains "Verify FAILED".
+A. Try the newer version of mkelfImage instead of the one from the
+   freebios tree. It's available at ftp://ftp.lnxi.com/pub/mkelfImage/ .
+
+Q. LinuxBIOS (v1 tree) crashes or fails to verify checksum when booting FILO.
+A. Make sure you are using the latest source of LinuxBIOS. It had a bug
+   that interferes with checksum calculation, until recently.

Added: trunk/filo/Documentation/TODO
===================================================================
--- trunk/filo/Documentation/TODO	                        (rev 0)
+++ trunk/filo/Documentation/TODO	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,42 @@
+Please report suggestions for this file to stepan at coresystems.de
+
+Features
+    - finish "find" implementation in main/grub/builtins.c
+    - finish print_completions implementation in main/grub/completions.c
+    - enter grub command line interface if no menu.lst is found, instead
+      of hanging forever.
+
+Cleanup
+    - Cleanup addresses specified in include/grub/shared.h. That looks
+      dangerous to plain wrong.
+
+Devices/Drivers
+    - create a list of all available devices (and search this on for menu.lst 
+      or "find" or tab completion)
+    - USB keyboard/Serial support
+    - Full & tested USB support
+    
+CD/DVD Boot support
+    - gather syslinux config files from CDs/DVDs and add their entries
+      to the menu. (Create a menu if syslinux config files are found 
+      but no menu.lst)
+
+SCSI
+    - yeah, scsi support, good point. This is an open issue in LinuxBIOS
+      for now. Int13 support somehow?
+      http://cvs.sourceforge.net/viewcvs.py/u-boot/u-boot/board/MAI/bios_emulator/
+     
+Config File Support
+
+    - search for a menu.lst rather than hardcoding it?!?
+
+      Maybe store this information (device type, drive number, partition number)
+      to the CMOS, so finally we won't have to have it hardcoded in the flash?
+
+    - we're parsing a grub menu.lst right now, but we should also be able to
+      read syslinux.cfg
+
+    - We can have an entry in hard disk's filo.cfg to boot from CD-ROM.
+      If this entry is selected, filo.cfg from CD-ROM is read.
+ 
+      

Added: trunk/filo/Makefile
===================================================================
--- trunk/filo/Makefile	                        (rev 0)
+++ trunk/filo/Makefile	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,149 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+export PROGRAM_NAME := FILO
+export PROGRAM_VERSION := 0.6.0b1
+
+export src := $(shell pwd)
+export srctree := $(src)
+export srck := $(src)/util/kconfig
+export obj := $(src)/build
+export objk := $(src)/build/util/kconfig
+
+export KERNELVERSION      := $(PROGRAM_VERSION)
+export KCONFIG_AUTOHEADER := $(obj)/config.h
+export KCONFIG_AUTOCONFIG := $(obj)/auto.conf
+
+CONFIG_SHELL := sh
+KBUILD_DEFCONFIG := configs/defconfig
+UNAME_RELEASE := $(shell uname -r)
+HAVE_DOTCONFIG := $(wildcard .config)
+
+BUILD_INFO = ($(shell whoami)@$(shell hostname)) $(shell LANG=C date)
+
+# Make is silent per default, but 'make V=1' will show all compiler calls.
+ifneq ($(V),1)
+Q := @
+endif
+
+HOSTCC = gcc
+HOSTCXX = g++
+HOSTCFLAGS := -I$(srck) -I$(objk)
+HOSTCXXFLAGS := -I$(srck) -I$(objk)
+
+STRIP ?= strip
+NM ?= nm
+
+ifeq ($(strip $(HAVE_DOTCONFIG)),)
+
+all: config
+include util/kconfig/Makefile
+
+else
+
+include $(src)/.config
+
+ARCHDIR-$(CONFIG_TARGET_I386) := i386
+
+PLATFORM-y += $(ARCHDIR-y)/Makefile.inc
+TARGETS-y :=
+
+BUILD-y := main/Makefile.inc main/grub/Makefile.inc fs/Makefile.inc 
+BUILD-y += drivers/Makefile.inc
+BUILD-y += drivers/usb/Makefile.inc drivers/newusb/Makefile.inc drivers/flash/Makefile.inc
+
+include $(PLATFORM-y) $(BUILD-y)
+
+LIBPAYLOAD = libpayload/lib/libpayload.a
+INCPAYLOAD = libpayload/include
+INCPAYLOADDRIVERS = libpayload/drivers
+LIBGCC = $(shell $(CC) -print-libgcc-file-name)
+
+OBJS     := $(patsubst %,$(obj)/%,$(TARGETS-y))
+INCLUDES := -I$(INCPAYLOAD) -I$(INCPAYLOADDRIVERS) -Iinclude -I$(ARCHDIR-y)/include -Ibuild
+INCLUDES += -I$(shell $(CC) -print-search-dirs | head -n 1 | cut -d' ' -f2)include
+
+try-run= $(shell set -e; \
+TMP=".$$$$.tmp"; \
+if ($(1)) > /dev/null 2>&1; \
+then echo "$(2)"; \
+else echo "$(3)"; \
+fi; rm -rf "$$TMP")
+
+cc-option= $(call try-run,\
+$(CC) $(1) -S -xc /dev/null -o "$$TMP", $(1), $(2))
+
+STACKPROTECT += $(call cc-option, -fno-stack-protector,)
+
+GCCINCDIR = $(shell $(CC) -print-search-dirs | head -n 1 | cut -d' ' -f2)include
+CPPFLAGS = -nostdinc -imacros $(obj)/config.h -Iinclude -I$(GCCINCDIR) -MD
+CFLAGS := -Wall $(STACKPROTECT) $(INCLUDES) -Os -fomit-frame-pointer -fno-common -ffreestanding -fno-strict-aliasing
+
+TARGET  = $(obj)/filo.elf
+
+include $(src)/.config
+
+all: prepare $(obj)/version.h $(TARGET)
+
+$(obj)/filo: $(src)/.config $(OBJS)
+	$(Q)printf "  LD      $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(LD) -N -T $(ARCHDIR-y)/ldscript -o $@ $(OBJS) $(LIBPAYLOAD) $(LIBGCC)
+
+$(TARGET): $(obj)/filo $(obj)/util/ebchecksum
+	$(Q)cp $(obj)/filo $@
+	$(Q)$(NM) $(obj)/filo > $(obj)/filo.map
+	$(Q)printf "  STRIP   $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(STRIP) -s $@
+	$(Q)printf "  EBCHECK $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(obj)/util/ebchecksum -w $@
+
+include util/kconfig/Makefile
+include util/Makefile.inc
+
+$(obj)/%.o: $(src)/%.c
+	$(Q)printf "  CC      $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(CC) -m32 $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+$(obj)/%.S.o: $(src)/%.S
+	$(Q)printf "  AS      $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(AS) --32 -o $@ $<
+
+endif
+
+$(obj)/version.h: FORCE
+	$(Q)echo '#define PROGRAM_NAME "$(PROGRAM_NAME)"' > $@
+	$(Q)echo '#define PROGRAM_VERSION "$(PROGRAM_VERSION)"' >> $@
+	$(Q)echo '#define PROGRAM_VERSION_FULL "$(PROGRAM_VERSION) $(BUILD_INFO)"' >> $@
+	$(Q)echo '#define BUILD_INFO "$(BUILD_INFO)"' >> $@
+
+prepare:
+	$(Q)mkdir -p $(obj)/util/kconfig/lxdialog
+	$(Q)mkdir -p $(obj)/i386 $(obj)/fs $(obj)/drivers/flash $(obj)/drivers/usb $(obj)/drivers/newusb
+	$(Q)mkdir -p $(obj)/main/grub
+
+clean:
+	$(Q)rm -rf $(obj)/i386 $(obj)/fs $(obj)/drivers $(obj)/main $(obj)/util
+
+distclean: clean
+	$(Q)rm -rf build
+	$(Q)rm -f .config .config.old ..config.tmp .kconfig.d .tmpconfig*
+
+FORCE:
+
+.PHONY: $(PHONY) prepare clean distclean FORCE
+

Added: trunk/filo/README
===================================================================
--- trunk/filo/README	                        (rev 0)
+++ trunk/filo/README	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,165 @@
+This is FILO, a bootloader which loads boot images from local filesystem,
+without help from legacy BIOS services.
+
+Expected usage is to flash it into the BIOS ROM together with coreboot.
+
+Find the latest version and more information on FILO
+at http://www.coreboot.org/FILO
+
+FEATURES
+
+    - Supported boot devices: IDE hard disk and CD-ROM, and system memory (ROM)
+      S-ATA and USB memory devices
+    - Supported filesystems: ext2, fat, jfs, minix, reiserfs, xfs, and iso9660
+    - Supported image formats: ELF and [b]zImage (a.k.a. /vmlinuz)
+    - Supports boot disk image of El Torito bootable CD-ROM
+    - Supports loading image from raw device with user-specified offset
+    - Console on VGA + keyboard, serial port, or both
+    - Line editing with ^H, ^W and ^U keys to type arbitrary filename to boot
+    - GRUB like user interface
+    - Full support for the ELF Boot Proposal (where is it btw, Eric?)
+    - Auxiliary tool to compute checksum of ELF boot images
+    - Full 32-bit code, no BIOS calls
+
+REQUIREMENTS
+
+    Only i386 PC architecture is currently supported.
+
+    x86-64 (AMD 64) machines in 32-bit mode do also work.
+    (coreboot uses 32-bit mode and the Linux kernel does the 
+    transition to 64-bit mode)
+
+    I'm using an AMD64 based mainboard with IDE hard disk
+    and a DVD drive for testing, and QEmu, Bochs or VMware 
+    for development.
+
+    Recent version of GNU toolchain is required to build.
+    I have tested with the toolchains from SUSE 10.0 and SUSE 10.1, 
+    but slightly older versions might also work.
+
+INSTALL
+
+    First invocation of make creates the default Config file.
+	$ make
+    Edit this file as you like. It's fairly straightforward (I hope).
+	$ vi Config
+
+    If you are using the GRUB like frontend:
+
+    - make sure you adapt your menu.lst path 
+    - if you want to use FILO over a serial connection, make sure you have 
+      something like this in your menu.lst file:
+
+        serial --unit=0 --speed=115200
+        terminal serial console
+	
+    Then running make again will build filo.elf, the ELF boot image of FILO.
+	$ make
+
+    Use filo.elf as your payload of coreboot, or a boot image for
+    Etherboot.
+
+USING
+
+    When FILO starts, it displays "boot:" prompt or the GRUB menu interface.
+    
+    At "boot:" prompt, type the name of your boot image, and optionally
+    the kernel parameter, in the form:
+	DEVICE:FILENAME[ PARAM]
+    for example:
+	boot: hda1:/vmlinuz root=/dev/hda1
+
+    Notation of DEVICE for IDE disk and CD-ROM is same as in Linux
+    (eg. hda1 means the first partition of master device on primary 
+    IDE channel). Support for El Torito bootable CD-ROM, "hdc1" means
+    the boot disk image of the CD-ROM at hdc.
+
+    FILENAME can be standard bzImage/zImage (vmlinuz) Linux kernels,
+    Linux-compatible images such as memtest.bin of Memtest86,
+    and any bootable ELF images, which include Linux kernel converted
+    by mkelfImage, Etherboot .elf and .zelf, Memtest86, FILO itself, etc.
+
+    If USE_GRUB is disabled:
+
+      If AUTOBOOT_FILE is set in Config, FILO tries to boot this file
+      first, and falls back to boot: prompt if it fails.
+
+      If AUTOBOOT_DELAY is also set, FILO waits for specified time in
+      seconds before booting AUTOBOOT_FILE. If <Esc> key is pressed
+      during this time period, automatic boot is canceled.
+      Pressing <Enter> key also cancels the delay, but in this case
+      AUTOBOOT_FILE is booted immediately.
+
+      Even if AUTOBOOT_DELAY is not set, automatic boot can be disabled
+      by pressing <Esc> key beforehand.
+
+    FILO can also load separate initrd images along with vmlinuz
+    kernels. (For ELF kernel, initrd images are embedded into the
+    ELF file and cannot be altered).
+    To do so, add "initrd=NAME" parameter to the kernel command line.
+    NAME uses the same notation as kernel image name.
+    (eg. boot: hda1:/vmlinuz initrd=hda1:/root.gz root=/dev/ram)
+
+    To boot an image in the BIOS flash (or whatever is mapped in the system
+    memory space), use the notation "mem at OFFSET[,LENGTH]", like:
+	boot: mem at 0xfffe0000
+    In this example, it loads the boot image from the last 128KB of BIOS
+    flash.
+
+    The same notation can be used with IDE devices, eg:
+	boot: hda at 512,697344 initrd=hda at 1M,4M
+    In this case the 697344 bytes starting from second sector of IDE drive
+    is loaded as kernel, and 4M bytes of offset 1M bytes of the same disk
+    is loaded as initrd.
+    Note that when you load vmlinuz kernel or initrd this way,
+    you must specify the LENGTH parameter. You can omit it for ELF
+    images since they have segment length internally.
+    OFFSET and LENGTH parameters must be multiple of 512.
+
+USB
+
+    USB support is originally taken from Steven James's baremetal in
+    coreboot-v1 util.
+    
+    Yinghai Lu seperated common functions from uhci.c to usb.c and 
+    created ohci.c to support ohci.
+    ohci.c is heavily inspired by Linux Kernel 2.4.22 drivers/usb/host/usb-ohci.c.
+    
+    Stefan Reinauer integrated USB back into the main filo version.
+    
+    USB support includes several parts
+     1. UHCI+OHCI--->USB: provides usb init, usb_control_msg and usb_bulk_msg interface
+     2. USB_SCSI: bulk only device 
+     3. USB_X interface to FILO
+    
+    todo:
+     - EHCI support
+
+BUG REPORTING
+
+    If you have problem with FILO, set DEBUG_ALL in Config and send its 
+    console output to the coreboot mailinglist at <coreboot at coreboot.org>.
+
+ACKNOWLEDGEMENTS
+
+    Filesystem and menu code taken from GNU GRUB and patches for it.
+    IDE driver is originally taken from Etherboot.
+    Steve Gehlbach wrote the original bzImage loader for FILO.
+
+    Besides, I have taken pieces of code and/or learned concepts
+    from various standalone programs, including GNU GRUB, Etherboot,
+    polled IDE patch by Adam Agnew, Memtest86, LinuxBIOS, and Linux.
+    I must say thanks to all the developers of these wonderful software,
+    especially to Eric Biederman for his great development work in this area.
+
+    Stefan Reinauer is now maintaining FILO officially and added new features
+    such as the grub menu interface and merged S-ATA and USB support from
+    etherboot.
+
+LICENSE
+
+    Copyright (C) 2003 by SONE Takeshi <ts1 at tsn.or.jp> and others.
+    Copyright (C) 2005-2008 by coresystems GmbH <info at coresystems.de>.
+
+    This program is licensed under the terms of GNU General Public License.
+    See the COPYING file for details.

Added: trunk/filo/build.sh
===================================================================
--- trunk/filo/build.sh	                        (rev 0)
+++ trunk/filo/build.sh	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+#ALLCLEAN=1
+
+OS=`uname -s`
+if [ "$OS" == "Darwin" -o "${OS:0:6}" == "CYGWIN" ]; then
+    MAKEFLAGS="			\
+	AS=i386-elf-as		\
+	CC=i386-elf-gcc		\
+	AR=i386-elf-ar		\
+	LD=i386-elf-ld		\
+	STRIP=i386-elf-strip	\
+	NM=i386-elf-nm		\
+	HOSTCC=gcc		\
+	-j
+	"
+fi
+if [ "$OS" == "Linux" ]; then
+MAKEFLAGS='CC="gcc -m32" LD="ld -b elf32-i386" HOSTCC="gcc"'
+fi
+
+if [ "$ALLCLEAN" != "" -o ! -r libpayload/build/lib/libpayload.a ]; then
+  cd libpayload
+  make clean
+  make defconfig
+  make $MAKEFLAGS
+  cd ..
+fi
+
+make distclean
+make defconfig
+make $MAKEFLAGS
+

Added: trunk/filo/configs/config.grub
===================================================================
--- trunk/filo/configs/config.grub	                        (rev 0)
+++ trunk/filo/configs/config.grub	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,76 @@
+#
+# Automatically generated make config: don't edit
+# FILO version: 0.6.0b1
+# Tue Aug 19 18:33:40 2008
+#
+CONFIG_TARGET_I386=y
+# CONFIG_REVIEW is not set
+
+#
+# Interface Options
+#
+CONFIG_USE_GRUB=y
+CONFIG_PROMPT="filo"
+CONFIG_MENULST_FILE="hda3:/boot/filo/menu.lst"
+CONFIG_MENULST_TIMEOUT=0
+CONFIG_USE_MD5_PASSWORDS=y
+
+#
+# Drivers
+#
+CONFIG_IDE_DISK=y
+CONFIG_IDE_DISK_POLL_DELAY=0
+# CONFIG_SLOW_SATA is not set
+# CONFIG_PCMCIA_CF is not set
+CONFIG_USB_NEW_DISK=y
+# CONFIG_USB_DISK is not set
+# CONFIG_FLASH_DISK is not set
+CONFIG_SUPPORT_PCI=y
+# CONFIG_PCI_BRUTE_SCAN is not set
+# CONFIG_SUPPORT_SOUND is not set
+
+#
+# Console
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_PC_KEYBOARD=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_IOBASE=0x3f8
+CONFIG_SERIAL_SPEED_DEFAULT=y
+
+#
+# Filesystems
+#
+CONFIG_FSYS_EXT2FS=y
+CONFIG_FSYS_FAT=y
+# CONFIG_FSYS_JFS is not set
+# CONFIG_FSYS_MINIX is not set
+CONFIG_FSYS_REISERFS=y
+# CONFIG_FSYS_XFS is not set
+CONFIG_FSYS_ISO9660=y
+CONFIG_ELTORITO=y
+# CONFIG_FSYS_CRAMFS is not set
+# CONFIG_FSYS_SQUASHFS is not set
+
+#
+# Loaders
+#
+CONFIG_LINUX_LOADER=y
+# CONFIG_WINCE_LOADER is not set
+# CONFIG_ARTEC_BOOT is not set
+
+#
+# Debugging & Experimental
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEBUG_ALL is not set
+# CONFIG_DEBUG_ELFBOOT is not set
+# CONFIG_DEBUG_ELFNOTE is not set
+# CONFIG_DEBUG_SEGMENT is not set
+# CONFIG_DEBUG_SYS_INFO is not set
+# CONFIG_DEBUG_BLOCKDEV is not set
+# CONFIG_DEBUG_FSYS_EXT2FS is not set
+# CONFIG_DEBUG_PCI is not set
+# CONFIG_DEBUG_LINUXLOAD is not set
+# CONFIG_DEBUG_IDE is not set
+# CONFIG_DEBUG_ELTORITO is not set

Added: trunk/filo/configs/config.nogrub
===================================================================
--- trunk/filo/configs/config.nogrub	                        (rev 0)
+++ trunk/filo/configs/config.nogrub	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,73 @@
+#
+# Automatically generated make config: don't edit
+# FILO version: 0.6.0b1
+# Tue Aug 26 18:40:56 2008
+#
+CONFIG_TARGET_I386=y
+# CONFIG_REVIEW is not set
+
+#
+# Interface Options
+#
+# CONFIG_USE_GRUB is not set
+# CONFIG_USE_AUTOBOOT is not set
+
+#
+# Drivers
+#
+CONFIG_IDE_DISK=y
+CONFIG_IDE_DISK_POLL_DELAY=0
+# CONFIG_SLOW_SATA is not set
+# CONFIG_PCMCIA_CF is not set
+CONFIG_USB_NEW_DISK=y
+# CONFIG_USB_DISK is not set
+# CONFIG_FLASH_DISK is not set
+CONFIG_SUPPORT_PCI=y
+# CONFIG_PCI_BRUTE_SCAN is not set
+# CONFIG_SUPPORT_SOUND is not set
+
+#
+# Console
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_PC_KEYBOARD=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_IOBASE=0x3f8
+CONFIG_SERIAL_SPEED_DEFAULT=y
+
+#
+# Filesystems
+#
+CONFIG_FSYS_EXT2FS=y
+CONFIG_FSYS_FAT=y
+# CONFIG_FSYS_JFS is not set
+# CONFIG_FSYS_MINIX is not set
+CONFIG_FSYS_REISERFS=y
+# CONFIG_FSYS_XFS is not set
+CONFIG_FSYS_ISO9660=y
+CONFIG_ELTORITO=y
+# CONFIG_FSYS_CRAMFS is not set
+# CONFIG_FSYS_SQUASHFS is not set
+
+#
+# Loaders
+#
+CONFIG_LINUX_LOADER=y
+# CONFIG_WINCE_LOADER is not set
+# CONFIG_ARTEC_BOOT is not set
+
+#
+# Debugging & Experimental
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEBUG_ALL is not set
+# CONFIG_DEBUG_ELFBOOT is not set
+# CONFIG_DEBUG_ELFNOTE is not set
+# CONFIG_DEBUG_SEGMENT is not set
+# CONFIG_DEBUG_SYS_INFO is not set
+# CONFIG_DEBUG_BLOCKDEV is not set
+# CONFIG_DEBUG_FSYS_EXT2FS is not set
+# CONFIG_DEBUG_PCI is not set
+# CONFIG_DEBUG_LINUXLOAD is not set
+# CONFIG_DEBUG_IDE is not set
+# CONFIG_DEBUG_ELTORITO is not set

Added: trunk/filo/configs/defconfig
===================================================================
--- trunk/filo/configs/defconfig	                        (rev 0)
+++ trunk/filo/configs/defconfig	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,76 @@
+#
+# Automatically generated make config: don't edit
+# FILO version: 0.6.0b1
+# Tue Aug 19 18:33:40 2008
+#
+CONFIG_TARGET_I386=y
+# CONFIG_REVIEW is not set
+
+#
+# Interface Options
+#
+CONFIG_USE_GRUB=y
+CONFIG_PROMPT="filo"
+CONFIG_MENULST_FILE="hda3:/boot/filo/menu.lst"
+CONFIG_MENULST_TIMEOUT=0
+CONFIG_USE_MD5_PASSWORDS=y
+
+#
+# Drivers
+#
+CONFIG_IDE_DISK=y
+CONFIG_IDE_DISK_POLL_DELAY=0
+# CONFIG_SLOW_SATA is not set
+# CONFIG_PCMCIA_CF is not set
+CONFIG_USB_NEW_DISK=y
+# CONFIG_USB_DISK is not set
+# CONFIG_FLASH_DISK is not set
+CONFIG_SUPPORT_PCI=y
+# CONFIG_PCI_BRUTE_SCAN is not set
+# CONFIG_SUPPORT_SOUND is not set
+
+#
+# Console
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_PC_KEYBOARD=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_IOBASE=0x3f8
+CONFIG_SERIAL_SPEED_DEFAULT=y
+
+#
+# Filesystems
+#
+CONFIG_FSYS_EXT2FS=y
+CONFIG_FSYS_FAT=y
+# CONFIG_FSYS_JFS is not set
+# CONFIG_FSYS_MINIX is not set
+CONFIG_FSYS_REISERFS=y
+# CONFIG_FSYS_XFS is not set
+CONFIG_FSYS_ISO9660=y
+CONFIG_ELTORITO=y
+# CONFIG_FSYS_CRAMFS is not set
+# CONFIG_FSYS_SQUASHFS is not set
+
+#
+# Loaders
+#
+CONFIG_LINUX_LOADER=y
+# CONFIG_WINCE_LOADER is not set
+# CONFIG_ARTEC_BOOT is not set
+
+#
+# Debugging & Experimental
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEBUG_ALL is not set
+# CONFIG_DEBUG_ELFBOOT is not set
+# CONFIG_DEBUG_ELFNOTE is not set
+# CONFIG_DEBUG_SEGMENT is not set
+# CONFIG_DEBUG_SYS_INFO is not set
+# CONFIG_DEBUG_BLOCKDEV is not set
+# CONFIG_DEBUG_FSYS_EXT2FS is not set
+# CONFIG_DEBUG_PCI is not set
+# CONFIG_DEBUG_LINUXLOAD is not set
+# CONFIG_DEBUG_IDE is not set
+# CONFIG_DEBUG_ELTORITO is not set

Added: trunk/filo/drivers/Makefile.inc
===================================================================
--- trunk/filo/drivers/Makefile.inc	                        (rev 0)
+++ trunk/filo/drivers/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-$(CONFIG_IDE_DISK) += drivers/ide.o
+TARGETS-$(CONFIG_VIA_SOUND) += drivers/via-sound.o
+

Added: trunk/filo/drivers/flash/Makefile.inc
===================================================================
--- trunk/filo/drivers/flash/Makefile.inc	                        (rev 0)
+++ trunk/filo/drivers/flash/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-$(CONFIG_FLASH_DISK) += drivers/flash/lxflash.o
+

Added: trunk/filo/drivers/flash/lxflash.c
===================================================================
--- trunk/filo/drivers/flash/lxflash.c	                        (rev 0)
+++ trunk/filo/drivers/flash/lxflash.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,836 @@
+/*******************************************************************************
+ *
+ *	Geode LX CS5536 flash driver
+ *
+ *	Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ *	Artec Design LLC http://www.artecdesign.ee
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#include <arch/io.h>
+#include "lxflash.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_FLASH
+#include <debug.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// driver globals
+
+static FLASH_INFO g_flashInfo;		// flash info structure
+static u32	g_deviceID = 0;		// flash memory ID
+static int32_t	g_chipID = -1;		// chip ID
+static u16	g_baseAddr = 0;		// port mapped controller IO base address
+
+static u8 g_eccTest[MAX_ECC_SIZE];	// used to retrieve/store ECC
+static u8 g_eccCalc[MAX_ECC_SIZE];
+
+static u32 g_currentPage = (u32)-1;
+static u8 g_pageBuf[MAX_PAGE_SIZE];
+static u8 *g_pBBT=NULL;
+
+static msr_t g_orig_flsh;
+
+////////////////////////////////////////////////////////////////////////////////
+// ECC structs and routines
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const u8 nand_ecc_precalc_table[] = {
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/**
+ * nand_trans_result - [GENERIC] create non-inverted ECC
+ * @reg2:	line parity reg 2
+ * @reg3:	line parity reg 3
+ * @ecc_code:	ecc
+ *
+ * Creates non-inverted ECC code from line parity
+ */
+static void NAND_transResult(u8 reg2, u8 reg3,
+	u8 *ecc_code)
+{
+	u8 a, b, i, tmp1, tmp2;
+
+	/* Initialize variables */
+	a = b = 0x80;
+	tmp1 = tmp2 = 0;
+
+	/* Calculate first ECC byte */
+	for (i = 0; i < 4; i++) {
+		if (reg3 & a)		/* LP15,13,11,9 --> ecc_code[0] */
+			tmp1 |= b;
+		b >>= 1;
+		if (reg2 & a)		/* LP14,12,10,8 --> ecc_code[0] */
+			tmp1 |= b;
+		b >>= 1;
+		a >>= 1;
+	}
+
+	/* Calculate second ECC byte */
+	b = 0x80;
+	for (i = 0; i < 4; i++) {
+		if (reg3 & a)		/* LP7,5,3,1 --> ecc_code[1] */
+			tmp2 |= b;
+		b >>= 1;
+		if (reg2 & a)		/* LP6,4,2,0 --> ecc_code[1] */
+			tmp2 |= b;
+		b >>= 1;
+		a >>= 1;
+	}
+
+	/* Store two of the ECC bytes */
+	ecc_code[0] = tmp1;
+	ecc_code[1] = tmp2;
+}
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
+ * @dat:	raw data
+ * @ecc_code:	buffer for ECC
+ */
+int NAND_calculateECC(const u8 *dat, u8 *ecc_code)
+{
+	u8 idx, reg1, reg2, reg3;
+	int j;
+
+	/* Initialize variables */
+	reg1 = reg2 = reg3 = 0;
+	ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+	/* Build up column parity */
+	for(j = 0; j < 256; j++) {
+
+		/* Get CP0 - CP5 from table */
+		idx = nand_ecc_precalc_table[dat[j]];
+		reg1 ^= (idx & 0x3f);
+
+		/* All bit XOR = 1 ? */
+		if (idx & 0x40) {
+			reg3 ^= (u8) j;
+			reg2 ^= ~((u8) j);
+		}
+	}
+
+	/* Create non-inverted ECC code from line parity */
+	NAND_transResult(reg2, reg3, ecc_code);
+
+	/* Calculate final ECC code */
+	ecc_code[0] = ~ecc_code[0];
+	ecc_code[1] = ~ecc_code[1];
+	ecc_code[2] = ((~reg1) << 2) | 0x03;
+	return 0;
+}
+
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @dat:	raw data read from the chip
+ * @read_ecc:	ECC from the chip
+ * @calc_ecc:	the ECC calculated from raw data
+ *
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int NAND_correctData(u8 *dat, u8 *read_ecc, u8 *calc_ecc)
+{
+	u8 a, b, c, d1, d2, d3, add, bit, i;
+
+	/* Do error detection */
+	d1 = calc_ecc[0] ^ read_ecc[0];
+	d2 = calc_ecc[1] ^ read_ecc[1];
+	d3 = calc_ecc[2] ^ read_ecc[2];
+
+	if ((d1 | d2 | d3) == 0) {
+		/* No errors */
+		return 0;
+	}
+	else {
+		a = (d1 ^ (d1 >> 1)) & 0x55;
+		b = (d2 ^ (d2 >> 1)) & 0x55;
+		c = (d3 ^ (d3 >> 1)) & 0x54;
+
+		/* Found and will correct single bit error in the data */
+		if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+			c = 0x80;
+			add = 0;
+			a = 0x80;
+			for (i=0; i<4; i++) {
+				if (d1 & c)
+					add |= a;
+				c >>= 2;
+				a >>= 1;
+			}
+			c = 0x80;
+			for (i=0; i<4; i++) {
+				if (d2 & c)
+					add |= a;
+				c >>= 2;
+				a >>= 1;
+			}
+			bit = 0;
+			b = 0x04;
+			c = 0x80;
+			for (i=0; i<3; i++) {
+				if (d3 & c)
+					bit |= b;
+				c >>= 2;
+				b >>= 1;
+			}
+			b = 0x01;
+			a = dat[add];
+			a ^= (b << bit);
+			dat[add] = a;
+			return 1;
+		}
+		else {
+			i = 0;
+			while (d1) {
+				if (d1 & 0x01)
+					++i;
+				d1 >>= 1;
+			}
+			while (d2) {
+				if (d2 & 0x01)
+					++i;
+				d2 >>= 1;
+			}
+			while (d3) {
+				if (d3 & 0x01)
+					++i;
+				d3 >>= 1;
+			}
+			if (i == 1) {
+				/* ECC Code Error Correction */
+				read_ecc[0] = calc_ecc[0];
+				read_ecc[1] = calc_ecc[1];
+				read_ecc[2] = calc_ecc[2];
+				return 2;
+			}
+			else {
+				/* Uncorrectable Error */
+				return -1;
+			}
+		}
+	}
+
+	/* Should never happen */
+	return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NAND flash helper functions go here, ported from Windows CE FMD
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_checkStatus()
+//
+// Retrieve the status of the Chip. This function accept a loop number, which
+// is used to do the loop if chip is not ready.
+//
+// dwLoops:
+//
+// 0: no loop
+// 0xffffffff: loop forever
+
+u8 NAND_checkStatus(u32 dwLoops)
+{
+	int	bStop = (dwLoops != (u32) -1);
+	u8	ucStatus;
+	int i;
+
+	// There is a 200ns delay (Twb) between the time that the !write-enable line
+	// (!WE) is asserted and the time the ready (R/!B) line is de-asserted. Generate a
+	// delay before querrying the status.
+	for (i=0; i<10; i++)
+		inb(g_baseAddr + IO_NAND_STS);
+
+	while(TRUE)
+	{
+		ucStatus = inb(g_baseAddr + IO_NAND_STS);
+
+		if(((ucStatus & CS_NAND_STS_FLASH_RDY) &&	// status ready
+				!(ucStatus & CS_NAND_CTLR_BUSY)) ||		// controller not busy
+				(bStop && !dwLoops))					// non-infinite loop and
+
+			break;									// we already pay our due
+
+		dwLoops --;
+	}
+
+	return ucStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NAND command helpers
+
+static __inline void NAND_enableHwECC(int enable)
+{
+	if(enable) outb(0x07, g_baseAddr + IO_NAND_ECC_CTL);
+	else outb(0x02, g_baseAddr + IO_NAND_ECC_CTL);
+}
+
+static void NAND_readHwECC(u8 *pData)
+{
+	// read ECC data from status register
+	pData[0] = inb(g_baseAddr + IO_NAND_ECC_MSB);
+	pData[1] = inb(g_baseAddr + IO_NAND_ECC_LSB);
+	pData[2] = inb(g_baseAddr + IO_NAND_ECC_COL);
+}
+
+static __inline void NAND_writeIO(u8 b)
+{
+	outb(b, g_baseAddr + IO_NAND_IO);
+}
+
+static __inline void NAND_writeCTL(u8 b)
+{
+	outb(b, g_baseAddr + IO_NAND_CTL);
+}
+
+static __inline u8 NAND_readDataByte()
+{
+	return inb(g_baseAddr + IO_NAND_DATA);
+}
+
+static void NAND_readData(u8 *pData, int nSize)
+{
+	int i, nDwords = nSize/4;	// number of double words
+	int nBytes = nSize % 4;		// leftover stuff
+
+	if(nSize > 528) return;		// oversized buffer?
+
+	// read from port mapped registers, 
+	for(i=0; i<nDwords; i++)
+		((u32*)pData)[i] = inl(g_baseAddr + IO_NAND_DATA);
+
+	for(i=0; i<nBytes; i++)
+		pData[i] = inb(g_baseAddr + IO_NAND_DATA);
+}
+
+static __inline void NAND_writeByte(u8 b)
+{
+	outb(b, g_baseAddr + IO_NAND_DATA);
+}
+
+static void NAND_writeData(u8 *pData, int nSize)
+{
+	int i;
+	if(nSize > 528) return;	// oversized buffer?
+
+	// write byte by byte, pedestrian way
+	for(i=0; i<nSize; i++)
+		NAND_writeByte(pData[i]);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_getStatus()
+//
+// Retrieve the status of the Chip. This function accept a loop number, which
+// is used to do the loop if chip is not ready.
+//
+// dwLoops:
+//
+// 0: no loop
+// 0xffffffff: loop forever
+
+u8 NAND_getStatus(u32 dwLoops)
+{
+	int	bStop = (dwLoops != (u32) -1);
+	u8	ucStatus;
+
+	NAND_checkStatus(dwLoops);		// wait until ready
+
+	NAND_writeCTL(CS_NAND_CTL_CLE);	// latch command
+	NAND_writeIO(CMD_STATUS);		// issue read status command
+	NAND_writeCTL(0x00);			// enable chip
+
+	while(1)
+	{
+		ucStatus = inb(g_baseAddr + IO_NAND_DATA);
+
+		if((ucStatus & STATUS_READY) ||		// status ready
+				(bStop && !dwLoops))			// non-infinite loop and
+
+			break;							// we already pay our due
+
+		dwLoops--;
+	}
+
+	return ucStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_readFlashID
+//
+// Retrieve the flash chip manufacturer and ID
+
+
+u32 NAND_readFlashID()
+{
+	u32 dwID=0;
+
+	NAND_writeCTL(0x00);			// enable chip
+
+	NAND_checkStatus((u32) -1);	// check ready
+
+	NAND_writeCTL(CS_NAND_CTL_CLE);	// latch command
+	NAND_writeIO(CMD_READID);		// send command
+	NAND_writeCTL(CS_NAND_CTL_ALE);	// latch address
+	NAND_writeIO(0x00);				// send address
+	NAND_writeCTL(0x00);			// enable chip
+
+	NAND_checkStatus((u32) -1);
+
+	dwID = inl(g_baseAddr + IO_NAND_DATA);
+
+	NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+
+	return dwID;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_isBlockBad
+//
+// Check to see if the given block is bad. A block is bad if the 517th u8 on
+// the first or second page is not 0xff.
+//
+// blockID: The block address. We need to convert this to page address
+//
+
+int NAND_isBlockBad(u32 blockID)
+{
+	u8 pa1, pa2, pa3, ca1, ca2, bData;
+
+	// Get the first page of the block
+	u32 dwPageID = blockID * g_flashInfo.pagesPerBlock;
+	
+	// for 512-byte page size, use the original addressing scheme
+	if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_512)
+	{
+		// three page address bytes
+		pa1 = (u8) (dwPageID & 0xff);
+		pa2 = (u8) ((dwPageID >> 8) & 0xff);
+		pa3 = (u8) ((dwPageID >> 16) & 0xff);
+		// just one column address byte
+		ca1 = VALIDADDR;
+	}
+	// for 2048-byte page size, we need to add some stuff
+	else if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+	{
+		// three page address bytes
+		pa1 = (u8) (dwPageID & 0xff);
+		pa2 = (u8) ((dwPageID >> 8) & 0xff);
+		pa3 = (u8) ((dwPageID >> 16) & 0xff);
+		// two column address bytes
+		ca1 = 0x0000;
+		ca2 = 0x0008;	// point to the 2048-th byte
+	}
+	// unsupported page size
+	else return TRUE;
+
+	// For our NAND flash, we don't have to issue two read command. We just need
+	// to issue one read command and do contiquous read
+
+	NAND_writeCTL(0x00);				// enable chip
+	NAND_checkStatus((u32) -1);	// check ready
+
+	// Check the first page.
+	NAND_writeCTL(CS_NAND_CTL_CLE);		// latch command
+	
+	if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+		NAND_writeIO(CMD_READ);			// send read command
+	else NAND_writeIO(CMD_READ2);		// send read command 2
+	NAND_writeCTL(CS_NAND_CTL_ALE);		// latch address
+	NAND_writeIO(ca1);					// send Column Address 1
+
+	if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+		NAND_writeIO(ca2);				// send Column Address 2
+
+	NAND_writeIO(pa1);					// send Page Address 1
+	NAND_writeIO(pa2);					// send Page Address 2
+	NAND_writeIO(pa3);					// send Page Address 3
+	NAND_writeCTL(0x00);				// select chip
+	
+	if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+	{
+		NAND_writeCTL(CS_NAND_CTL_CLE);	// latch command
+		NAND_writeIO(CMD_READ_2K);		// send read command
+		NAND_writeCTL(0x00);			// select chip
+	}
+
+	NAND_checkStatus((u32) -1);	// check ready
+
+	bData = NAND_readDataByte();		// read out the bad block marker
+	if(bData != 0xff)					// no bits may be zeroed
+	{
+		debug("bad block found at address 0x%x\n", blockID);
+		NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+		return TRUE;
+	}
+
+	NAND_writeCTL(CS_NAND_CTL_CE);		// disable chip
+	return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+
+__inline int IsECCWritten(u8 *pECC)
+{
+	// FIXME: check only 6 first bytes
+	static u8 abNoECC[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+	return (memcmp(pECC, abNoECC, sizeof(abNoECC)) != 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 
+
+int NAND_close(void)
+{
+	if (g_chipID >= 0)
+		wrmsr(MSR_DIVIL_LBAR_FLSH0 + g_chipID, g_orig_flsh);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 
+
+int NAND_initChip(int chipNum)
+{
+	msr_t msr;
+
+	if (g_chipID == chipNum) return 0;
+	if (g_chipID != -1) NAND_close();
+	
+	memset(&g_flashInfo, 0, sizeof(g_flashInfo));
+
+	g_chipID = -1;
+
+	///////////////////////////////////////////////////////////////////////////////////
+	// init the MSR_DIVIL_BALL_OPTS register, enable flash mode
+	
+	msr = rdmsr(MSR_DIVIL_BALL_OPTS);
+	
+	if (msr.lo & PIN_OPT_IDE) {
+		printf("NAND controller not enabled!\n");
+		return -1;
+	}
+	
+	///////////////////////////////////////////////////////////////////////////////////
+	// init the MSR_DIVIL_LBAR_FLSHx register, I/O mapped mode, set a hardcoded base address
+	// Later we restore initial state
+	
+	g_orig_flsh = rdmsr(MSR_DIVIL_LBAR_FLSH0 + chipNum);
+	if (!(g_orig_flsh.hi & NOR_NAND)) {
+		printf("CS%d set up for NOR, aborting!\n", chipNum);
+		return -1;
+	}
+	
+	msr.hi = SET_FLSH_HIGH;
+	msr.lo = SET_FLSH_LOW;
+	wrmsr(MSR_DIVIL_LBAR_FLSH0 + chipNum, msr);
+	g_baseAddr = SET_FLSH_LOW;	// set the IO base address
+
+	// read the register back
+	msr = rdmsr(MSR_DIVIL_LBAR_FLSH0 + chipNum);
+	debug("MSR_DIVIL_LBAR_FLSH%d = 0x%08x 0x%08x\n", (int)chipNum, msr.hi, msr.lo);
+
+	// read out flash chip ID
+	g_deviceID = NAND_readFlashID();
+	
+	switch(g_deviceID)	// allow only known flash chips
+	{
+	case SAMSUNG_NAND_64MB:
+	case ST_NAND_64MB:
+		
+		g_flashInfo.numBlocks = 4096;
+		g_flashInfo.pagesPerBlock = 32;
+		g_flashInfo.dataBytesPerPage = 512;
+		g_flashInfo.flashType = FLASH_NAND;
+
+		break;
+
+	case ST_NAND_128MB:
+
+		g_flashInfo.numBlocks = 1024;
+		g_flashInfo.pagesPerBlock = 64;
+		g_flashInfo.dataBytesPerPage = 2048;
+		g_flashInfo.flashType = FLASH_NAND;
+		
+	case ST_NAND_512MB:
+
+		g_flashInfo.numBlocks = 4096;
+		g_flashInfo.pagesPerBlock = 64;
+		g_flashInfo.dataBytesPerPage = 2048;
+		g_flashInfo.flashType = FLASH_NAND;
+		
+		break;
+
+	default:
+		printf("Unsupported flash chip ID: %x\n", g_deviceID);
+		return -1;
+	}
+
+	g_flashInfo.bytesPerBlock = g_flashInfo.dataBytesPerPage * g_flashInfo.pagesPerBlock;
+
+	if(!g_pBBT) g_pBBT = malloc(g_flashInfo.numBlocks);
+	if(!g_pBBT)
+	{
+		printf("Could not allocate bad block table\n");
+		return -1;
+	}
+
+	debug("bad block table allocated, size %d\n", g_flashInfo.numBlocks);
+	memset(g_pBBT, BLOCK_UNKNOWN, g_flashInfo.numBlocks);
+
+	g_chipID = chipNum;
+	
+	printf("Geode LX flash driver initialized, device ID 0x%x\n", g_deviceID);
+	debug("FlashChip = 0x%x\n", g_chipID);
+	debug("NumBlocks = 0x%x\n", g_flashInfo.numBlocks);
+	debug("PagesPerBlock = 0x%x\n", g_flashInfo.pagesPerBlock);
+	debug("BytesPerPage = 0x%x\n", g_flashInfo.dataBytesPerPage);
+	debug("FlashType = %s\n", g_flashInfo.flashType == FLASH_NAND ? "NAND" : "NOR");
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NAND_readPage
+//
+// Read the content of the sector.
+//
+// startSectorAddr: Starting page address
+// pSectorBuff : Buffer for the data portion
+
+int NAND_readPage(u32 pageAddr, u8 *pPageBuff)
+{
+	if (!pPageBuff)
+	{
+		debug("Invalid parameters!\n");
+		return ERROR_BAD_PARAMS;
+	}
+
+	// sanity check
+	if (pageAddr < (g_flashInfo.numBlocks * g_flashInfo.pagesPerBlock))
+	{
+		u8 bData = 0, bBadBlock = 0, bReserved = 0;
+
+		u8 addr1 = (u8)(pageAddr & 0xff);
+		u8 addr2 = (u8)((pageAddr >> 8) & 0xff);
+		u8 addr3 = (u8)((pageAddr >> 16) & 0xff);
+		
+		u16 eccSize = 0;				// total ECC size
+		u32 pageSize = 0;
+		
+		NAND_writeCTL(0x00);				// enable chip
+		NAND_checkStatus((u32)-1);		// check ready
+
+		NAND_writeCTL(CS_NAND_CTL_CLE);		// latch command
+		NAND_writeIO(CMD_READ);				// send read command
+		NAND_writeCTL(CS_NAND_CTL_ALE);		// latch address
+		NAND_writeIO(0x00);					// send Column Address 1
+		
+		if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+			NAND_writeIO(0x00);				// send Column Address 2
+		
+		NAND_writeIO(addr1);				// send Page Address 1
+		NAND_writeIO(addr2);				// send Page Address 2
+		NAND_writeIO(addr3);				// send Page Address 3
+		NAND_writeCTL(0x00);				// select chip
+		
+		if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+		{
+			NAND_writeCTL(CS_NAND_CTL_CLE);	// latch command
+			NAND_writeIO(CMD_READ_2K);		// send read command
+			NAND_writeCTL(0x00);			// select chip
+		}
+
+		NAND_checkStatus((u32) -1);	// check ready
+
+		while(pageSize < g_flashInfo.dataBytesPerPage)
+		{
+			// read out the first half of page data
+			NAND_enableHwECC(1);			// enable HW ECC calculation
+			NAND_readData(&pPageBuff[pageSize], READ_BLOCK_SIZE);
+			NAND_readHwECC(&g_eccCalc[pageSize / READ_BLOCK_SIZE * 3]);
+			// update counters too
+			pageSize += READ_BLOCK_SIZE;
+			eccSize += 3;
+		}
+
+		debug("read %d bytes from page address %x\n", pageSize, pageAddr);
+		NAND_enableHwECC(0);				// disable HW ECC
+
+		// Now read the spare area data
+
+		if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_512)
+		{
+			// Read the ECC info according to Linux MTD format, first part
+			NAND_readData(g_eccTest, 4);
+	
+			bBadBlock = NAND_readDataByte();	// bad block byte
+			bReserved = NAND_readDataByte();	// reserved byte
+			// Read the ECC info according to Linux MTD format, second part
+			NAND_readData(&g_eccTest[4], 2);
+
+			// calculate the first part of ECC, use software method
+			//NAND_calculateECC(&pPageBuff[0], &g_eccCalc[0]);
+			// calculate the second part of ECC, use software method
+			//NAND_calculateECC(&pPageBuff[256], &g_eccCalc[3]);
+		}
+		else if(g_flashInfo.dataBytesPerPage == PAGE_SIZE_2048)
+		{
+			int i;
+			for(i=0; i<40; i++) NAND_readDataByte();	// skip stuff 
+			// Read the ECC info according to Linux MTD format (2048 byte page)
+			NAND_readData(g_eccTest, eccSize); 
+		}
+		
+		// test the data integrity; if the data is invalid, attempt to fix it using ECC
+		if(memcmp(g_eccCalc, g_eccTest, eccSize))
+		{
+			int nRet = 0;
+
+			// If the ECC is all 0xff, then it probably hasn't been written out yet
+			// because the data hasn't been written, so ignore the invalid ECC.
+			if(!IsECCWritten(g_eccTest))
+			{
+				debug("No ECC detected at page 0x%x\n", pageAddr);
+				NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+				return ERROR_NO_ECC;
+			}
+			
+			debug("Page data (page 0x%x) is invalid. Attempting ECC to fix it.\n", pageAddr);
+			nRet = NAND_correctData(&pPageBuff[0], &g_eccTest[0], &g_eccCalc[0]);
+			if(nRet == -1)
+			{
+				debug("ERROR - page data (page 0x%x, first part) Unable to correct invalid data!\n", pageAddr);
+				NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+				return ERROR_ECC_ERROR1;
+			}
+			else if(nRet == 0) debug("No errors detected (page 0x%x, first part)\n", pageAddr);
+			else debug("Invalid data (page 0x%x, first part) was corrected using ECC!\n", pageAddr);
+
+			// now do the second part
+			nRet = NAND_correctData(&pPageBuff[256], &g_eccTest[3], &g_eccCalc[3]);
+			if(nRet == -1)
+			{
+				debug("ERROR - page data (page 0x%x, second part) Unable to correct invalid data!\n", pageAddr);
+				NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+				return ERROR_ECC_ERROR2;
+			}
+			else if(nRet == 0) debug("No errors detected (page 0x%x, second part)\n", pageAddr);
+			else debug("Invalid data (page 0x%x, second part) was corrected using ECC!\n", pageAddr);
+		}
+	} 
+	else 
+	{
+		debug("Page address [%d] is too large\n", pageAddr);
+		return ERROR_BAD_ADDRESS;
+	}
+
+	NAND_writeCTL(CS_NAND_CTL_CE);	// disable chip
+	return ERROR_SUCCESS;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FILO interface functions
+
+int flash_probe(int drive)
+{
+	debug("drive %d\n", drive);
+	return NAND_initChip(drive);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+int flash_read(int drive, sector_t sector, void *buffer)
+{
+	int block, nRet;
+	u32 pageAddress = sector * DEV_SECTOR_SIZE / g_flashInfo.dataBytesPerPage;
+	u32 pageOffset = sector * DEV_SECTOR_SIZE % g_flashInfo.dataBytesPerPage;
+	
+	// sanity check
+	if(!g_pBBT || !g_flashInfo.pagesPerBlock)
+	{
+		debug("error: NAND not initialized\n");
+		return -1;
+	}
+	
+	// check that the page ID is valid
+	if(pageAddress >= (g_flashInfo.numBlocks * g_flashInfo.pagesPerBlock))
+	{
+		debug("error: sector offset %x out of range\n", sector);
+		return -2;
+	}
+
+	// get block address
+	block = pageAddress / g_flashInfo.pagesPerBlock;
+
+	debug("drive %d, sector %d -> page %d + %d, buffer 0x%08x\n", 
+		drive, (unsigned int)sector, pageAddress, pageOffset, (unsigned int)buffer);
+
+	// get the block status first
+	if(g_pBBT[block] == BLOCK_UNKNOWN)
+	{
+		debug("checking block 0x%x status for BBT\n", block);
+		g_pBBT[block] = NAND_isBlockBad(block) ? BLOCK_BAD : BLOCK_GOOD;
+	}
+
+	// return failure immediately if the block is bad
+	if(g_pBBT[block] == BLOCK_BAD) 
+	{
+		debug("error: block %x is bad\n", block);
+		return -3;
+	}
+	
+	// check if we have just read that page
+	if(g_currentPage == pageAddress)
+	{
+		// should use cache instead
+		memcpy(buffer, g_pageBuf + pageOffset, DEV_SECTOR_SIZE);
+		return ERROR_SUCCESS;
+	}
+	
+	// otherwise proceed with normal reading
+	nRet = NAND_readPage(pageAddress, g_pageBuf);
+	memcpy(buffer, g_pageBuf + pageOffset, DEV_SECTOR_SIZE);
+	
+	return nRet;
+}

Added: trunk/filo/drivers/flash/lxflash.h
===================================================================
--- trunk/filo/drivers/flash/lxflash.h	                        (rev 0)
+++ trunk/filo/drivers/flash/lxflash.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,155 @@
+#ifndef LXFLASH_H
+#define LXFLASH_H
+
+#define TRUE	1	// hmm that's quite obvious :)
+#define FALSE	0
+
+typedef struct msr_struct 
+{
+	unsigned lo;
+	unsigned hi;
+} msr_t;
+
+static inline msr_t rdmsr(unsigned index)
+{
+	msr_t result;
+	__asm__ __volatile__ (
+		"rdmsr"
+		: "=a" (result.lo), "=d" (result.hi)
+		: "c" (index)
+		);
+	return result;
+}
+
+static inline void wrmsr(unsigned index, msr_t msr)
+{
+	__asm__ __volatile__ (
+		"wrmsr"
+		: /* No outputs */
+		: "c" (index), "a" (msr.lo), "d" (msr.hi)
+		);
+}
+
+typedef struct _FLASH_INFO
+{
+	unsigned long	numBlocks;
+	unsigned long	bytesPerBlock;
+	unsigned short	pagesPerBlock;
+	unsigned short	dataBytesPerPage;
+	unsigned short	flashType;
+} FLASH_INFO;
+
+// NAND flash controller MSR registers
+
+#define MSR_DIVIL_LBAR_FLSH0	0x51400010	// Flash Chip Select 0
+#define MSR_DIVIL_LBAR_FLSH1	0x51400011	// Flash Chip Select 1
+#define MSR_DIVIL_LBAR_FLSH2	0x51400012	// Flash Chip Select 2
+#define MSR_DIVIL_LBAR_FLSH3	0x51400013	// Flash Chip Select 3
+#define NOR_NAND				(1UL<<1)	// 1 for NAND, 0 for NOR
+
+#define MSR_DIVIL_BALL_OPTS		0x51400015
+#define PIN_OPT_IDE				(1UL<<0)	// 0 for flash, 1 for IDE
+
+#define MSR_NANDF_DATA			0x5140001B
+#define MSR_NANDF_CTL			0x5140001C
+
+// Intended value for LBAR_FLSHx: enabled, PIO, NAND, @0xC000
+
+#define SET_FLSH_HIGH			0x0000FFF3
+#define SET_FLSH_LOW			0x0000C000
+
+// ThinCan defaults
+
+#define PAGE_SIZE_512			512
+#define PAGE_SIZE_2048			2048
+#define MAX_PAGE_SIZE			2048
+#define MAX_ECC_SIZE			24
+#define READ_BLOCK_SIZE			256
+
+//  VALIDADDR is 5 << 8
+//
+//  Explain:    5 means the 6th byte in spare area (517 byte in the page)
+//              Shift 8 bit to the left to form the correct address for 16bit port
+//
+#define VALIDADDR				0x05
+#define OEMADDR					0x04		// 5th byte in spare area 
+
+//  NAND Flash Command. This appears to be generic across all NAND flash chips
+
+#define CMD_READ                0x00        //  Read
+#define CMD_READ1               0x01        //  Read1
+#define CMD_READ2               0x50        //  Read2
+#define CMD_READID              0x90        //  ReadID
+#define CMD_READID2             0x91        //  Read extended ID
+#define CMD_WRITE               0x80        //  Write phase 1
+#define CMD_WRITE2              0x10        //  Write phase 2
+#define CMD_ERASE               0x60        //  Erase phase 1
+#define CMD_ERASE2              0xd0        //  Erase phase 2
+#define CMD_STATUS              0x70        //  Status read
+#define CMD_RESET               0xff        //  Reset
+#define CMD_READ_2K             0x30        //  Second cycle read cmd for 2KB flash 
+
+// Registers within the NAND flash controller BAR -- memory mapped
+
+#define MM_NAND_DATA			0x00		// 0 to 0x7ff, in fact
+#define MM_NAND_CTL				0x800		// Any even address 0x800-0x80e
+#define MM_NAND_IO				0x801		// Any odd address 0x801-0x80f
+#define MM_NAND_STS				0x810
+#define MM_NAND_ECC_LSB			0x811
+#define MM_NAND_ECC_MSB			0x812
+#define MM_NAND_ECC_COL			0x813
+#define MM_NAND_LAC				0x814
+#define MM_NAND_ECC_CTL			0x815
+
+// Registers within the NAND flash controller BAR -- I/O mapped 
+
+#define IO_NAND_DATA			0x00		// 0 to 3, in fact
+#define IO_NAND_CTL				0x04
+#define IO_NAND_IO				0x05
+#define IO_NAND_STS				0x06
+#define IO_NAND_ECC_CTL			0x08
+#define IO_NAND_ECC_LSB			0x09
+#define IO_NAND_ECC_MSB			0x0a
+#define IO_NAND_ECC_COL			0x0b
+#define IO_NAND_LAC				0x0c
+
+#define CS_NAND_CTL_DIST_EN			(1<<4)	// Enable NAND Distract interrupt
+#define CS_NAND_CTL_RDY_INT_MASK	(1<<3)	// Enable RDY/BUSY# interrupt
+#define CS_NAND_CTL_ALE				(1<<2)
+#define CS_NAND_CTL_CLE				(1<<1)
+#define CS_NAND_CTL_CE				(1<<0)	// Keep low; 1 to reset
+
+#define CS_NAND_STS_FLASH_RDY		(1<<3)
+#define CS_NAND_CTLR_BUSY			(1<<2)
+#define CS_NAND_CMD_COMP			(1<<1)
+#define CS_NAND_DIST_ST				(1<<0)
+
+#define CS_NAND_ECC_PARITY			(1<<2)
+#define CS_NAND_ECC_CLRECC			(1<<1)
+#define CS_NAND_ECC_ENECC			(1<<0)
+
+//  Status bit pattern, read from chip register
+
+#define STATUS_READY				0x40	//  Ready
+#define STATUS_ERROR				0x01	//  Error
+
+#define FLASH_NOR					0
+#define FLASH_NAND					1
+
+#define SAMSUNG_NAND_64MB			0xc0a576ec
+#define ST_NAND_64MB				0x76207620
+#define ST_NAND_512MB				0x9580dc20
+#define ST_NAND_128MB				0x1d80f120
+
+#define ERROR_SUCCESS				0
+#define ERROR_BAD_PARAMS			-1
+#define ERROR_ECC_ERROR1			1
+#define ERROR_ECC_ERROR2			2
+#define ERROR_BAD_ADDRESS			3
+#define ERROR_NO_ECC				4
+
+#define BLOCK_UNKNOWN				0
+#define BLOCK_BAD					2
+#define BLOCK_GOOD					1
+
+#endif

Added: trunk/filo/drivers/ide.c
===================================================================
--- trunk/filo/drivers/ide.c	                        (rev 0)
+++ trunk/filo/drivers/ide.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1311 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Derived from Etherboot 5.1 */
+
+#include <libpayload.h>
+#include <config.h>
+#include <lib.h>
+#include <fs.h>
+#include <arch/timer.h>
+#ifdef CONFIG_SUPPORT_PCI
+#include <pci.h>
+#endif
+
+#define DEBUG_THIS CONFIG_DEBUG_IDE
+#include <debug.h>
+
+#define IDE_MAX_CONTROLLERS 4
+#define IDE_MAX_DRIVES (IDE_MAX_CONTROLLERS * 2)
+
+#define BSY_SET_DURING_SPINUP 1
+/*
+ *   UBL, The Universal Talkware Boot Loader 
+ *    Copyright (C) 2000 Universal Talkware Inc.
+ *    Copyright (C) 2002 Eric Biederman
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ *
+ */
+struct controller {
+	uint16_t cmd_base;
+	uint16_t ctrl_base;
+};
+
+struct harddisk_info {
+	struct controller *ctrl;
+	uint16_t heads;
+	uint16_t cylinders;
+	uint16_t sectors_per_track;
+	uint8_t  model_number[41];
+	uint8_t  slave;
+	sector_t sectors;
+	int  address_mode;
+#define ADDRESS_MODE_CHS    0
+#define ADDRESS_MODE_LBA    1
+#define ADDRESS_MODE_LBA48  2
+#define ADDRESS_MODE_PACKET 3
+	uint32_t hw_sector_size;
+	unsigned drive_exists : 1;
+	unsigned slave_absent : 1;
+	unsigned removable : 1;
+};
+
+#define IDE_SECTOR_SIZE 0x200
+#define CDROM_SECTOR_SIZE 0x800
+
+#define IDE_BASE0             (0x1F0u) /* primary controller */
+#define IDE_BASE1             (0x170u) /* secondary */
+#define IDE_BASE2             (0x1E8u) /* third */
+#define IDE_BASE3             (0x168u) /* fourth */
+#define IDE_BASE4             (0x1E0u) /* fifth */
+#define IDE_BASE5             (0x160u) /* sixth */
+
+#define IDE_REG_EXTENDED_OFFSET   (0x204u)
+
+#define IDE_REG_DATA(ctrl)           ((ctrl)->cmd_base + 0u) /* word register */
+#define IDE_REG_ERROR(ctrl)          ((ctrl)->cmd_base + 1u)
+#define IDE_REG_PRECOMP(ctrl)        ((ctrl)->cmd_base + 1u)
+#define IDE_REG_FEATURE(ctrl)        ((ctrl)->cmd_base + 1u)
+#define IDE_REG_SECTOR_COUNT(ctrl)   ((ctrl)->cmd_base + 2u)
+#define IDE_REG_SECTOR_NUMBER(ctrl)  ((ctrl)->cmd_base + 3u)
+#define IDE_REG_LBA_LOW(ctrl)        ((ctrl)->cmd_base + 3u)
+#define IDE_REG_CYLINDER_LSB(ctrl)   ((ctrl)->cmd_base + 4u)
+#define IDE_REG_LBA_MID(ctrl)	     ((ctrl)->cmd_base + 4u)
+#define IDE_REG_CYLINDER_MSB(ctrl)   ((ctrl)->cmd_base + 5u)
+#define IDE_REG_LBA_HIGH(ctrl)	     ((ctrl)->cmd_base + 5u)
+#define IDE_REG_DRIVEHEAD(ctrl)      ((ctrl)->cmd_base + 6u)
+#define IDE_REG_DEVICE(ctrl)	     ((ctrl)->cmd_base + 6u)
+#define IDE_REG_STATUS(ctrl)         ((ctrl)->cmd_base + 7u)
+#define IDE_REG_COMMAND(ctrl)        ((ctrl)->cmd_base + 7u)
+#define IDE_REG_ALTSTATUS(ctrl)      ((ctrl)->ctrl_base + 2u)
+#define IDE_REG_DEVICE_CONTROL(ctrl) ((ctrl)->ctrl_base + 2u)
+
+struct ide_pio_command
+{
+	uint8_t feature;
+	uint8_t sector_count;
+	uint8_t lba_low;
+	uint8_t lba_mid;
+	uint8_t lba_high;
+	uint8_t device;
+#       define IDE_DH_DEFAULT (0xA0)
+#       define IDE_DH_HEAD(x) ((x) & 0x0F)
+#       define IDE_DH_MASTER  (0x00)
+#       define IDE_DH_SLAVE   (0x10)
+#       define IDE_DH_LBA     (0x40)
+#       define IDE_DH_CHS     (0x00)
+	uint8_t command;
+	uint8_t sector_count2;
+	uint8_t lba_low2;
+	uint8_t lba_mid2;
+	uint8_t lba_high2;
+};
+
+#define IDE_DEFAULT_COMMAND { 0xFFu, 0x01, 0x00, 0x0000, IDE_DH_DEFAULT }
+
+#define IDE_ERR_ICRC	0x80	/* ATA Ultra DMA bad CRC */
+#define IDE_ERR_BBK	0x80	/* ATA bad block */
+#define IDE_ERR_UNC	0x40	/* ATA uncorrected error */
+#define IDE_ERR_MC	0x20	/* ATA media change */
+#define IDE_ERR_IDNF	0x10	/* ATA id not found */
+#define IDE_ERR_MCR	0x08	/* ATA media change request */
+#define IDE_ERR_ABRT	0x04	/* ATA command aborted */
+#define IDE_ERR_NTK0	0x02	/* ATA track 0 not found */
+#define IDE_ERR_NDAM	0x01	/* ATA address mark not found */
+
+#define IDE_STATUS_BSY	0x80	/* busy */
+#define IDE_STATUS_RDY	0x40	/* ready */
+#define IDE_STATUS_DF	0x20	/* device fault */
+#define IDE_STATUS_WFT	0x20	/* write fault (old name) */
+#define IDE_STATUS_SKC	0x10	/* seek complete */
+#define IDE_STATUS_DRQ	0x08	/* data request */
+#define IDE_STATUS_CORR	0x04	/* corrected */
+#define IDE_STATUS_IDX	0x02	/* index */
+#define IDE_STATUS_ERR	0x01	/* error (ATA) */
+#define IDE_STATUS_CHK	0x01	/* check (ATAPI) */
+
+#define IDE_CTRL_HD15	0x08	/* bit should always be set to one */
+#define IDE_CTRL_SRST	0x04	/* soft reset */
+#define IDE_CTRL_NIEN	0x02	/* disable interrupts */
+
+
+/* Most mandtory and optional ATA commands (from ATA-3), */
+
+#define IDE_CMD_CFA_ERASE_SECTORS            0xC0
+#define IDE_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
+#define IDE_CMD_CFA_TRANSLATE_SECTOR         0x87
+#define IDE_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
+#define IDE_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
+#define IDE_CMD_CHECK_POWER_MODE1            0xE5
+#define IDE_CMD_CHECK_POWER_MODE2            0x98
+#define IDE_CMD_DEVICE_RESET                 0x08
+#define IDE_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
+#define IDE_CMD_FLUSH_CACHE                  0xE7
+#define IDE_CMD_FORMAT_TRACK                 0x50
+#define IDE_CMD_IDENTIFY_DEVICE              0xEC
+#define IDE_CMD_IDENTIFY_DEVICE_PACKET       0xA1
+#define IDE_CMD_IDENTIFY_PACKET_DEVICE       0xA1
+#define IDE_CMD_IDLE1                        0xE3
+#define IDE_CMD_IDLE2                        0x97
+#define IDE_CMD_IDLE_IMMEDIATE1              0xE1
+#define IDE_CMD_IDLE_IMMEDIATE2              0x95
+#define IDE_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
+#define IDE_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define IDE_CMD_NOP                          0x00
+#define IDE_CMD_PACKET                       0xA0
+#define IDE_CMD_READ_BUFFER                  0xE4
+#define IDE_CMD_READ_DMA                     0xC8
+#define IDE_CMD_READ_DMA_QUEUED              0xC7
+#define IDE_CMD_READ_MULTIPLE                0xC4
+#define IDE_CMD_READ_SECTORS                 0x20
+#define IDE_CMD_READ_SECTORS_EXT             0x24
+#define IDE_CMD_READ_VERIFY_SECTORS          0x40
+#define IDE_CMD_RECALIBRATE                  0x10
+#define IDE_CMD_SEEK                         0x70
+#define IDE_CMD_SET_FEATURES                 0xEF
+#define IDE_CMD_SET_MAX_ADDR_EXT             0x24
+#define IDE_CMD_SET_MULTIPLE_MODE            0xC6
+#define IDE_CMD_SLEEP1                       0xE6
+#define IDE_CMD_SLEEP2                       0x99
+#define IDE_CMD_STANDBY1                     0xE2
+#define IDE_CMD_STANDBY2                     0x96
+#define IDE_CMD_STANDBY_IMMEDIATE1           0xE0
+#define IDE_CMD_STANDBY_IMMEDIATE2           0x94
+#define IDE_CMD_WRITE_BUFFER                 0xE8
+#define IDE_CMD_WRITE_DMA                    0xCA
+#define IDE_CMD_WRITE_DMA_QUEUED             0xCC
+#define IDE_CMD_WRITE_MULTIPLE               0xC5
+#define IDE_CMD_WRITE_SECTORS                0x30
+#define IDE_CMD_WRITE_VERIFY                 0x3C
+
+/* IDE_CMD_SET_FEATURE sub commands */
+#define IDE_FEATURE_CFA_ENABLE_8BIT_PIO                     0x01
+#define IDE_FEATURE_ENABLE_WRITE_CACHE                      0x02
+#define IDE_FEATURE_SET_TRANSFER_MODE                       0x03
+#define IDE_FEATURE_ENABLE_POWER_MANAGEMENT                 0x05
+#define IDE_FEATURE_ENABLE_POWERUP_IN_STANDBY               0x06
+#define IDE_FEATURE_STANDBY_SPINUP_DRIVE                    0x07
+#define IDE_FEATURE_CFA_ENABLE_POWER_MODE1                  0x0A
+#define IDE_FEATURE_DISABLE_MEDIA_STATUS_NOTIFICATION       0x31
+#define IDE_FEATURE_ENABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT    0x42
+#define IDE_FEATURE_SET_MAXIMUM_HOST_INTERFACE_SECTOR_TIMES 0x43
+#define IDE_FEATURE_DISABLE_READ_LOOKAHEAD                  0x55
+#define IDE_FEATURE_ENABLE_RELEASE_INTERRUPT                0x5D
+#define IDE_FEATURE_ENABLE_SERVICE_INTERRUPT                0x5E
+#define IDE_FEATURE_DISABLE_REVERTING_TO_POWERON_DEFAULTS   0x66
+#define IDE_FEATURE_CFA_DISABLE_8BIT_PIO                    0x81
+#define IDE_FEATURE_DISABLE_WRITE_CACHE                     0x82
+#define IDE_FEATURE_DISABLE_POWER_MANAGEMENT                0x85
+#define IDE_FEATURE_DISABLE_POWERUP_IN_STANDBY              0x86
+#define IDE_FEATURE_CFA_DISABLE_POWER_MODE1                 0x8A
+#define IDE_FEATURE_ENABLE_MEDIA_STATUS_NOTIFICATION        0x95
+#define IDE_FEATURE_ENABLE_READ_LOOKAHEAD                   0xAA
+#define IDE_FEATURE_DISABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT   0xC2
+#define IDE_FEATURE_ENABLE_REVERTING_TO_POWERON_DEFAULTS    0xCC
+#define IDE_FEATURE_DISABLE_SERVICE_INTERRUPT               0xDE
+
+static unsigned short ide_base[] = {
+	IDE_BASE0,
+	IDE_BASE1, 
+	IDE_BASE2, 
+	IDE_BASE3, 
+	0
+};
+
+static struct controller controllers[IDE_MAX_CONTROLLERS];
+static struct harddisk_info harddisk_info[IDE_MAX_DRIVES];
+
+static unsigned char ide_buffer[IDE_SECTOR_SIZE];
+
+static int await_ide(int (*done)(struct controller *ctrl), 
+	struct controller *ctrl, unsigned long timeout)
+{
+	int result;
+	for(;;) {
+		result = done(ctrl);
+#if CONFIG_IDE_DISK_POLL_DELAY
+		mdelay(1);
+#endif
+		if (result) {
+			return 0;
+		}
+		//poll_interruptions();
+		if ((timeout == 0) || (currticks() > timeout)) {
+			break;
+		}
+	}
+	printf("IDE time out\n");
+	return -1;
+}
+
+/* The maximum time any IDE command can last 31 seconds,
+ * So if any IDE commands takes this long we know we have problems.
+ */
+#define IDE_TIMEOUT (32*TICKS_PER_SEC)
+
+static int not_bsy(struct controller *ctrl)
+{
+	return !(inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY);
+}
+
+/* IDE drives assert BSY bit within 400 nsec when SRST is set.
+ * Use 2 msec since our tick is 1 msec */
+#define IDE_RESET_PULSE (2*TICKS_PER_SEC / 1000)
+
+static int bsy(struct controller *ctrl)
+{
+	return inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY;
+}
+
+#if  !BSY_SET_DURING_SPINUP
+static int timeout(struct controller *ctrl)
+{
+	return 0;
+}
+#endif
+
+static void print_status(struct controller *ctrl)
+{
+	debug("IDE: status=%#x, err=%#x\n",
+			inb(IDE_REG_STATUS(ctrl)), inb(IDE_REG_ERROR(ctrl)));
+}
+
+int select_drive(struct controller *ctrl, int drive)
+{
+	int device, status;
+
+	outb(0xa0 | (drive << 4), IDE_REG_DEVICE(ctrl));
+	status = inb(IDE_REG_STATUS(ctrl));
+
+	mdelay(10);
+	
+	device = inb(IDE_REG_DEVICE(ctrl));
+	status = inb(IDE_REG_STATUS(ctrl));
+	
+	if (device == (0xa0 | (drive<<4)))
+		return 1;
+	else
+		return 0;
+}
+
+static int ide_software_reset(struct controller *ctrl)
+{
+	int master_exist = select_drive(ctrl, 0);
+	int slave_exist = select_drive(ctrl, 1);
+
+	/* Wait a little bit in case this is immediately after
+	 * hardware reset.
+	 */
+	mdelay(2);
+	/* A software reset should not be delivered while the bsy bit
+	 * is set.  If the bsy bit does not clear in a reasonable
+	 * amount of time give up.
+	 */
+	debug("Waiting for ide%d to become ready for reset... ",
+			ctrl - controllers);
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		debug("failed\n");
+		return -1;
+	}
+	debug("ok\n");
+
+	debug("Resetting ide%d... ",
+			ctrl - controllers);
+	/* Disable Interrupts and reset the ide bus */
+	outb(IDE_CTRL_HD15 | IDE_CTRL_SRST | IDE_CTRL_NIEN, 
+		IDE_REG_DEVICE_CONTROL(ctrl));
+	/* If BSY bit is not asserted within 400ns, no device there */
+	if (await_ide(bsy, ctrl, currticks() + IDE_RESET_PULSE) < 0) {
+		if (master_exist) {
+			debug("master found.");
+		}
+		if (slave_exist)
+			printf ("reset failed, but slave may exist\n");
+		else {
+			// return -1;
+			printf("reset failed, but we may be on SATA\n");
+		}
+	}
+	debug("ok\n");
+
+	outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl));
+	mdelay(2);
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+	return 0;
+}
+
+static void pio_set_registers(
+	struct controller *ctrl, const struct ide_pio_command *cmd)
+{
+	uint8_t device;
+	/* Disable Interrupts */
+	outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl));
+
+	/* Possibly switch selected device */
+	device = inb(IDE_REG_DEVICE(ctrl));
+	outb(cmd->device,          IDE_REG_DEVICE(ctrl));
+	if ((device & (1UL << 4)) != (cmd->device & (1UL << 4))) {
+		/* Allow time for the selected drive to switch,
+		 * The linux ide code suggests 50ms is the right
+		 * amount of time to use here.
+		 */
+		mdelay(50); 
+	}
+	outb(cmd->feature,         IDE_REG_FEATURE(ctrl));
+	if (cmd->command == IDE_CMD_READ_SECTORS_EXT) {
+		outb(cmd->sector_count2,   IDE_REG_SECTOR_COUNT(ctrl));
+		outb(cmd->lba_low2,        IDE_REG_LBA_LOW(ctrl));
+		outb(cmd->lba_mid2,        IDE_REG_LBA_MID(ctrl));
+		outb(cmd->lba_high2,       IDE_REG_LBA_HIGH(ctrl));
+	}
+	outb(cmd->sector_count,    IDE_REG_SECTOR_COUNT(ctrl));
+	outb(cmd->lba_low,         IDE_REG_LBA_LOW(ctrl));
+	outb(cmd->lba_mid,         IDE_REG_LBA_MID(ctrl));
+	outb(cmd->lba_high,        IDE_REG_LBA_HIGH(ctrl));
+	outb(cmd->command,         IDE_REG_COMMAND(ctrl));
+}
+
+
+static int pio_non_data(struct controller *ctrl, const struct ide_pio_command *cmd)
+{
+	/* Wait until the busy bit is clear */
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+
+	pio_set_registers(ctrl, cmd);
+	ndelay(400);
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+	/* FIXME is there more error checking I could do here? */
+	return 0;
+}
+
+static int pio_data_in(struct controller *ctrl, const struct ide_pio_command *cmd,
+	void *buffer, size_t bytes)
+{
+	unsigned int status;
+
+	/* FIXME handle commands with multiple blocks */
+	/* Wait until the busy bit is clear */
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+
+	/* How do I tell if INTRQ is asserted? */
+	pio_set_registers(ctrl, cmd);
+	ndelay(400);
+	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+	status = inb(IDE_REG_STATUS(ctrl));
+	if (!(status & IDE_STATUS_DRQ)) {
+		print_status(ctrl);
+		return -1;
+	}
+	insw(IDE_REG_DATA(ctrl), buffer, bytes/2);
+	status = inb(IDE_REG_STATUS(ctrl));
+	if (status & IDE_STATUS_DRQ) {
+		print_status(ctrl);
+		return -1;
+	}
+	return 0;
+}
+
+static int pio_packet(struct harddisk_info *info, int in,
+	const void *packet, int packet_len,
+	void *buffer, int buffer_len)
+{
+	unsigned int status;
+	struct ide_pio_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	/* Wait until the busy bit is clear */
+	if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+
+	/* Issue a PACKET command */
+	cmd.lba_mid = (uint8_t) buffer_len;
+	cmd.lba_high = (uint8_t) (buffer_len >> 8);
+	cmd.device = IDE_DH_DEFAULT | info->slave;
+	cmd.command = IDE_CMD_PACKET;
+	pio_set_registers(info->ctrl, &cmd);
+	ndelay(400);
+	if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+	status = inb(IDE_REG_STATUS(info->ctrl));
+	if (!(status & IDE_STATUS_DRQ)) {
+		debug("no drq after PACKET\n");
+		print_status(info->ctrl);
+		return -1;
+	}
+
+	/* Send the packet */
+	outsw(IDE_REG_DATA(info->ctrl), packet, packet_len/2);
+
+	if (await_ide(not_bsy, info->ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+	status = inb(IDE_REG_STATUS(info->ctrl));
+	if (buffer_len == 0) {
+		if (status & IDE_STATUS_DRQ) {
+			debug("drq after non-data command\n");
+			print_status(info->ctrl);
+			return -1;
+		}
+		return 0;
+	}
+
+	if (!(status & IDE_STATUS_DRQ)) {
+		debug("no drq after sending packet\n");
+		print_status(info->ctrl);
+		return -1;
+	}
+
+	insw(IDE_REG_DATA(info->ctrl), buffer, buffer_len/2);
+
+	status = inb(IDE_REG_STATUS(info->ctrl));
+	if (status & IDE_STATUS_DRQ) {
+		debug("drq after insw\n");
+		print_status(info->ctrl);
+		return -1;
+	}
+	return 0;
+}
+
+static inline int ide_read_sector_chs(
+	struct harddisk_info *info, void *buffer, unsigned long sector)
+{
+	struct ide_pio_command cmd;
+	unsigned int track;
+	unsigned int offset;
+	unsigned int cylinder;
+		
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.sector_count = 1;
+
+	//debug("ide_read_sector_chs: sector= %ld.\n",sector);
+
+	track = sector / info->sectors_per_track;
+	/* Sector number */
+	offset = 1 + (sector % info->sectors_per_track);
+	cylinder = track / info->heads;
+	cmd.lba_low = offset;
+	cmd.lba_mid = cylinder & 0xff;
+	cmd.lba_high = (cylinder >> 8) & 0xff;
+	cmd.device = IDE_DH_DEFAULT |
+		IDE_DH_HEAD(track % info->heads) |
+		info->slave |
+		IDE_DH_CHS;
+	cmd.command = IDE_CMD_READ_SECTORS;
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+}
+
+static inline int ide_read_sector_lba(
+	struct harddisk_info *info, void *buffer, unsigned long sector)
+{
+	struct ide_pio_command cmd;
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.sector_count = 1;
+	cmd.lba_low = sector & 0xff;
+	cmd.lba_mid = (sector >> 8) & 0xff;
+	cmd.lba_high = (sector >> 16) & 0xff;
+	cmd.device = IDE_DH_DEFAULT |
+		((sector >> 24) & 0x0f) |
+		info->slave | 
+		IDE_DH_LBA;
+	cmd.command = IDE_CMD_READ_SECTORS;
+	//debug("%s: sector= %ld, device command= 0x%x.\n",__FUNCTION__,(unsigned long) sector, cmd.device);
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+}
+
+static inline int ide_read_sector_lba48(
+	struct harddisk_info *info, void *buffer, sector_t sector)
+{
+	struct ide_pio_command cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	//debug("ide_read_sector_lba48: sector= %ld.\n",(unsigned long) sector);
+
+	cmd.sector_count = 1;
+	cmd.lba_low = sector & 0xff;
+	cmd.lba_mid = (sector >> 8) & 0xff;
+	cmd.lba_high = (sector >> 16) & 0xff;
+	cmd.lba_low2 = (sector >> 24) & 0xff;
+	cmd.lba_mid2 = (sector >> 32) & 0xff;
+	cmd.lba_high2 = (sector >> 40) & 0xff;
+	cmd.device =  info->slave | IDE_DH_LBA;
+	cmd.command = IDE_CMD_READ_SECTORS_EXT;
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+}
+
+static inline int ide_read_sector_packet(
+	struct harddisk_info *info, void *buffer, sector_t sector)
+{
+	char packet[12];
+	static uint8_t cdbuffer[CDROM_SECTOR_SIZE];
+	static struct harddisk_info *last_disk = 0;
+	static sector_t last_sector = (sector_t) -1;
+	uint8_t *buf;
+	uint32_t hw_sector;
+
+	//debug("sector=%ld\n", sector);
+
+	if (info->hw_sector_size == CDROM_SECTOR_SIZE) {
+		buf = cdbuffer;
+		hw_sector = sector >> 2;
+	} else {
+		buf = buffer;
+		hw_sector = sector;
+	}
+
+	if (buf==buffer || info != last_disk || hw_sector != last_sector) {
+		//debug("hw_sector=%u\n", hw_sector);
+		memset(packet, 0, sizeof packet);
+		packet[0] = 0x28; /* READ */
+		packet[2] = hw_sector >> 24;
+		packet[3] = hw_sector >> 16;
+		packet[4] = hw_sector >> 8;
+		packet[5] = hw_sector >> 0;
+		packet[7] = 0;
+		packet[8] = 1; /* length */
+
+		if (pio_packet(info, 1, packet, sizeof packet,
+					buf, info->hw_sector_size) != 0) {
+			debug("read error\n");
+			return -1;
+		}
+		last_disk = info;
+		last_sector = hw_sector;
+	}
+
+	if (buf != buffer)
+		memcpy(buffer, &cdbuffer[(sector & 3) << 9], IDE_SECTOR_SIZE);
+	return 0;
+}
+
+int ide_read(int drive, sector_t sector, void *buffer)
+{
+	struct harddisk_info *info = &harddisk_info[drive];
+	int result;
+
+	//debug("drive=%d, sector=%ld\n",drive,(unsigned long) sector);
+	/* Report the buffer is empty */
+	if (sector > info->sectors) {
+		return -1;
+	}
+	if (info->address_mode == ADDRESS_MODE_CHS) {
+		result = ide_read_sector_chs(info, buffer, sector);
+	}
+	else if (info->address_mode == ADDRESS_MODE_LBA) {
+		result = ide_read_sector_lba(info, buffer, sector);
+	}
+	else if (info->address_mode == ADDRESS_MODE_LBA48) {
+		result = ide_read_sector_lba48(info, buffer, sector);
+	}
+	else if (info->address_mode == ADDRESS_MODE_PACKET) {
+		result = ide_read_sector_packet(info, buffer, sector);
+	}
+	else {
+		result = -1;
+	}
+	return result;
+}
+
+static int init_drive(struct harddisk_info *info, struct controller *ctrl,
+		int slave, int drive, unsigned char *buffer, int ident_command)
+{
+	uint16_t* drive_info;
+	struct ide_pio_command cmd;
+	int i;
+
+	info->ctrl = ctrl;
+	info->heads = 0u;
+	info->cylinders = 0u;
+	info->sectors_per_track = 0u;
+	info->address_mode = IDE_DH_CHS;
+	info->sectors = 0ul;
+	info->drive_exists = 0;
+	info->slave_absent = 0;
+	info->removable = 0;
+	info->hw_sector_size = IDE_SECTOR_SIZE;
+	info->slave = slave?IDE_DH_SLAVE: IDE_DH_MASTER;
+
+	debug("Testing for hd%c\n", 'a'+drive);
+
+	/* Select the drive that we are testing */
+	outb(IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave, 
+		IDE_REG_DEVICE(ctrl));
+	mdelay(50);
+
+	/* Test to see if the drive registers exist,
+	 * In many cases this quickly rules out a missing drive.
+	 */
+	for(i = 0; i < 4; i++) {
+		outb(0xaa + i, (ctrl->cmd_base) + 2 + i);
+	}
+	for(i = 0; i < 4; i++) {
+		if (inb((ctrl->cmd_base) + 2 + i) != 0xaa + i) {
+			return 1;
+		}
+	}
+	for(i = 0; i < 4; i++) {
+		outb(0x55 + i, (ctrl->cmd_base) + 2 + i);
+	}
+	for(i = 0; i < 4; i++) {
+		if (inb((ctrl->cmd_base) + 2 + i) != 0x55 + i) {
+			return 1;
+		}
+	}
+	debug("Probing for hd%c\n", 'a'+drive);
+	
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave;
+	cmd.command = ident_command;
+
+	
+	if (pio_data_in(ctrl, &cmd, buffer, IDE_SECTOR_SIZE) < 0) {
+		/* Well, if that command didn't work, we probably don't have drive. */
+		return 1;
+	}
+	
+
+	/* Now suck the data out */
+	drive_info = (uint16_t *)buffer;
+	if (drive_info[2] == 0x37C8) {
+		/* If the response is incomplete spin up the drive... */
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS |
+			info->slave;
+		cmd.feature = IDE_FEATURE_STANDBY_SPINUP_DRIVE;
+		if (pio_non_data(ctrl, &cmd) < 0) {
+			/* If the command doesn't work give up on the drive */
+			return 1;
+		}
+		
+	}
+	if ((drive_info[2] == 0x37C8) || (drive_info[2] == 0x8C73)) {
+		/* The response is incomplete retry the drive info command */
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS |
+			info->slave;
+		cmd.command = ident_command;
+		if(pio_data_in(ctrl, &cmd, buffer, IDE_SECTOR_SIZE) < 0) {
+			/* If the command didn't work give up on the drive. */
+			return 1;
+		}
+	}
+	if ((drive_info[2] != 0x37C8) &&
+		(drive_info[2] != 0x738C) &&
+		(drive_info[2] != 0x8C73) &&
+		(drive_info[2] != 0xC837) &&
+		(drive_info[2] != 0x0000)) {
+		printf("Invalid IDE Configuration: %hx\n", drive_info[2]);
+		return 1;
+	}
+	for(i = 27; i < 47; i++) {
+		info->model_number[((i-27)<< 1)] = (drive_info[i] >> 8) & 0xff;
+		info->model_number[((i-27)<< 1)+1] = drive_info[i] & 0xff;
+	}
+	info->model_number[40] = '\0';
+	info->drive_exists = 1;
+
+	/* See if LBA is supported */
+	if (ident_command == IDE_CMD_IDENTIFY_PACKET_DEVICE) {
+		info->address_mode = ADDRESS_MODE_PACKET;
+		info->removable = 1; /* XXX */
+	} else if (drive_info[49] & (1 << 9)) {
+		info->address_mode = ADDRESS_MODE_LBA;
+		info->sectors = (drive_info[61] << 16) | (drive_info[60]);
+		debug("LBA mode, sectors=%ld\n", info->sectors);
+		/* Enable LBA48 mode if it is present */
+		if (drive_info[83] & (1 <<10)) {
+			/* Should LBA48 depend on LBA? */
+			info->address_mode = ADDRESS_MODE_LBA48;
+			info->sectors = 
+				(((sector_t)drive_info[103]) << 48) |
+				(((sector_t)drive_info[102]) << 32) |
+				(((sector_t)drive_info[101]) << 16) |
+				(((sector_t)drive_info[100]) <<  0);
+			debug("LBA48 mode, sectors=%ld\n", info->sectors);
+		}
+	} else {
+		info->address_mode = ADDRESS_MODE_CHS;
+		info->heads = drive_info[3];
+		info->cylinders = drive_info[1];
+		info->sectors_per_track = drive_info[6];
+		info->sectors = 
+			info->sectors_per_track *
+			info->heads *
+			info->cylinders;
+		debug("CHS mode, sectors_per_track=[%d], heads=[%d], cylinders=[%d]\n",
+			info->sectors_per_track,
+			info->heads,
+			info->cylinders);
+		debug("sectors=%ld\n", info->sectors);
+	}
+	/* See if we have a slave */
+	if (!info->slave && (((drive_info[93] >> 14) & 3) == 1)) {
+		info->slave_absent = !(drive_info[93] & (1 << 5));
+	}
+
+	/* See if we need to put the device in CFA power mode 1 */
+	if ((drive_info[160] & ((1 << 15) | (1 << 13)| (1 << 12))) ==
+		((1 << 15) | (1 << 13)| (1 << 12))) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave;
+		cmd.feature = IDE_FEATURE_CFA_ENABLE_POWER_MODE1;
+		if (pio_non_data(ctrl, &cmd) < 0) {
+			/* If I need to power up the drive, and I can't
+			 * give up.
+			 */
+			printf("Cannot power up CFA device\n");
+			return 1;
+		}
+	}
+
+	/* Some extra steps for older drives.. */
+	if (info->address_mode != ADDRESS_MODE_PACKET) {
+		/* Initialize drive parameters
+		 * This is an obsolete command (disappeared as of ATA-6)
+		 * but old drives need it before accessing media. */
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(drive_info[3] - 1)
+		    | info->slave;
+		cmd.sector_count = drive_info[6];
+		cmd.command = IDE_CMD_INITIALIZE_DRIVE_PARAMETERS;
+		debug("Init device params... ");
+		if (pio_non_data(ctrl, &cmd) < 0)
+			debug("failed (ok for newer drives)\n");
+		else
+			debug("ok\n");
+	}
+
+	printf("hd%c: %s",
+		'a'+drive,
+		(info->address_mode==ADDRESS_MODE_CHS) ? "CHS" :
+		(info->address_mode==ADDRESS_MODE_LBA) ? "LBA" :
+		(info->address_mode==ADDRESS_MODE_LBA48) ? "LBA48" :
+		(info->address_mode==ADDRESS_MODE_PACKET) ? "ATAPI" : "???");
+
+	if (info->sectors > (10LL*1000*1000*1000/512))
+		printf(" %uGB", (unsigned) (info->sectors / (1000*1000*1000/512)));
+	else if (info->sectors > (10*1000*1000/512))
+		printf(" %uMB", (unsigned) (info->sectors / (1000*1000/512)));
+	else if (info->sectors > 0)
+		printf(" %uKB", (unsigned) (info->sectors / 2));
+	printf(": %s\n", info->model_number);
+
+	return 0;
+}
+
+/* Experimental floating bus detection
+ * As Eric mentions, we get stuck when the bus has no drive
+ * and floating high. To avoid this, try some heuristics.
+ * This is based on a paper on Phoenix website. --ts1 */
+static int ide_bus_floating(struct controller *ctrl)
+{
+	unsigned long timeout;
+	unsigned char status;
+
+	/* Test 1: if status reads 0xff, probably no device is present
+	 * on the bus. Repeat this for 20msec. */
+	timeout = currticks() + 20 * TICKS_PER_SEC / 1000;
+	status = 0;
+	do {
+		/* Take logical OR to avoid chattering */
+		status |= inb(IDE_REG_STATUS(ctrl));
+		/* If it makes 0xff, it's possible to be floating, 
+		 * do test2 to ensure. */
+		if (status == 0xff)
+			goto test2;
+		/* If BSY bit is not set, it's harmless to continue probing. */
+		if ((status & IDE_STATUS_BSY) == 0)
+			return 0;
+	} while (currticks() < timeout);
+	/* Timed out. Logical ORed status didn't make 0xFF.
+	 * We have something there. */
+	return 0;
+
+test2:
+	/* Test 2: write something to registers, then read back and 
+	 * compare. Note that ATA spec inhibits this while BSY is set,
+	 * but for many drives this works. This is a confirmation step anyway.
+	 */
+	outb(0xaa, ctrl->cmd_base + 2);
+	outb(0x55, ctrl->cmd_base + 3);
+	outb(0xff, ctrl->cmd_base + 4);
+	if (inb(ctrl->cmd_base+2) == 0xaa
+			&& inb(ctrl->cmd_base+3) == 0x55
+			&& inb(ctrl->cmd_base+4) == 0xff) {
+		/* We have some registers there. 
+		 * Though this does not mean it is not a NIC or something... */
+		return 0;
+	}
+
+	/* Status port is 0xFF, and other registers are not there.
+	 * Most certainly this bus is floating. */
+	printf("Detected floating bus\n");
+	return 1;
+}
+
+static int init_controller(struct controller *ctrl, int drive, unsigned char *buffer) 
+{
+	struct harddisk_info *info;
+
+	/* Put the drives ide channel in a know state and wait
+	 * for the drives to spinup.  
+	 *
+	 * In practice IDE disks tend not to respond to commands until
+	 * they have spun up.  This makes IDE hard to deal with
+	 * immediately after power up, as the delays can be quite
+	 * long, so we must be very careful here.
+	 *
+	 * There are two pathological cases that must be dealt with:
+	 *
+	 * - The BSY bit not being set while the IDE drives spin up.
+	 *   In this cases only a hard coded delay will work.  As
+	 *   I have not reproduced it, and this is out of spec for
+	 *   IDE drives the work around can be enabled by setting
+	 *   BSY_SET_DURING_SPINUP to 0.
+	 *
+	 * - The BSY bit floats high when no drives are plugged in.
+	 *   This case will not be detected except by timing out but
+	 *   we avoid the problems by only probing devices we are
+	 *   supposed to boot from.  If we don't do the probe we
+	 *   will not experience the problem.
+	 *
+	 * So speed wise I am only slow if the BSY bit is not set
+	 * or not reported by the IDE controller during spinup, which
+	 * is quite rare.
+	 * 
+	 */
+	debug("init_controller: drive %d\n", drive);
+#if !BSY_SET_DURING_SPINUP
+	if (await_ide(timeout, ctrl, currticks() + IDE_TIMEOUT) < 0) {
+		return -1;
+	}
+#endif
+	/* ts1: Try some heuristics to avoid waiting for floating bus */
+	if (ide_bus_floating(ctrl))
+		return -1;
+
+	if (ide_software_reset(ctrl) < 0) {
+		return -1;
+	}
+
+	/* Note: I have just done a software reset.  It may be
+	 * reasonable to just read the boot time signatures 
+	 * off of the drives to see if they are present.
+	 *
+	 * For now I will go with just sending commands to the drives
+	 * and assuming filtering out missing drives by detecting registers
+	 * that won't set and commands that fail to execute properly.
+	 */
+
+	/* Now initialize the individual drives */
+	int master_drive = drive & ~1;
+	info = &harddisk_info[master_drive];
+
+	/* master */
+	init_drive(info, ctrl, 0, master_drive, buffer, IDE_CMD_IDENTIFY_DEVICE);
+
+	if (!info->drive_exists)
+		init_drive(info, ctrl, 0, master_drive, buffer,
+				IDE_CMD_IDENTIFY_PACKET_DEVICE);
+
+	debug("MASTER CHECK: master %s\n", 
+			info->drive_exists ? "yes" : "no");
+	/* slave and master */
+	if (info->drive_exists && !info->slave_absent) {
+		master_drive++;
+		info++;
+		init_drive(info, ctrl, 1, master_drive, buffer,
+				IDE_CMD_IDENTIFY_DEVICE);
+		if (!info->drive_exists)
+			init_drive(info, ctrl, 1, master_drive, buffer,
+					IDE_CMD_IDENTIFY_PACKET_DEVICE);
+	}
+
+	/* slave */
+	debug("/* slave */ -- drive is %d\n", drive);
+	info = &harddisk_info[drive];
+	if (!info->drive_exists) {
+		debug("NO MASTER -- check slave!\n");
+		init_drive(info, ctrl, 1, drive, buffer, IDE_CMD_IDENTIFY_DEVICE);
+		
+		if (!info->drive_exists)
+			init_drive(info, ctrl, 1, drive, buffer,
+				IDE_CMD_IDENTIFY_PACKET_DEVICE);
+		debug("SLAVE ONLY CHECK: slave %s\n", 
+				info->drive_exists ? "yes" : "no");
+	}
+
+	return 0;
+}
+
+static int
+atapi_request_sense(struct harddisk_info *info, uint8_t *asc, uint8_t *ascq)
+{
+	uint8_t packet[12];
+	uint8_t buf[18];
+	int i;
+
+	memset(packet, 0, sizeof packet);
+	packet[0] = 0x03; /* REQUEST SENSE */
+	packet[4] = sizeof buf;
+	if (pio_packet(info, 1, packet, sizeof packet, buf, sizeof buf) != 0)
+		return -1;
+
+	for (i = 0; i < sizeof buf; i++)
+		debug("%02x ", buf[i]);
+	debug("\n");
+
+	if (asc)
+		*asc = buf[12];
+	if (ascq)
+		*ascq = buf[13];
+	return 0;
+}
+
+static int atapi_detect_medium(struct harddisk_info *info)
+{
+	uint8_t packet[12];
+	uint8_t buf[8];
+	uint32_t block_len, sectors;
+	unsigned long timeout;
+	uint8_t asc, ascq;
+	int in_progress;
+
+	memset(packet, 0, sizeof packet);
+	packet[0] = 0x25; /* READ CAPACITY */
+
+	/* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT
+	 * is reported by the drive. If the drive reports "IN PROGRESS",
+	 * 30 seconds is added. */
+	timeout = currticks() + 5*TICKS_PER_SEC;
+	in_progress = 0;
+	while (currticks() < timeout) {
+		if (pio_packet(info, 1, packet, sizeof packet, buf, sizeof buf)
+				== 0)
+			goto ok;
+
+		if (atapi_request_sense(info, &asc, &ascq) == 0) {
+			if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
+				debug("Device reports MEDIUM NOT PRESENT\n");
+				return -1;
+			}
+
+			if (asc == 0x04 && ascq == 0x01 && !in_progress) {
+					/* IN PROGRESS OF BECOMING READY */
+				printf("Waiting for drive to detect "
+						"the medium... ");
+				/* Allow 30 seconds more */
+				timeout = currticks() + 30*TICKS_PER_SEC;
+				in_progress = 1;
+			}
+		}
+
+		mdelay(100);
+	}
+	debug("read capacity failed\n");
+	return -1;
+ok:
+
+	block_len = (uint32_t) buf[4] << 24
+		| (uint32_t) buf[5] << 16
+		| (uint32_t) buf[6] << 8
+		| (uint32_t) buf[7] << 0;
+	debug("block_len=%u\n", block_len);
+
+	switch (block_len) {
+	case CDROM_SECTOR_SIZE:
+	case IDE_SECTOR_SIZE:
+		/* ok */
+		break;
+	case 0:
+	case 2340:
+	case 2352:
+		/* Some CD drives report weird sector sizes.
+		 * These values are taken from linux/drivers/scsi/sr.c */
+		block_len = CDROM_SECTOR_SIZE;
+		break;
+	default:
+		printf("Unsupported sector size %u\n", block_len);
+		return -1;
+	}
+	info->hw_sector_size = block_len;
+
+	sectors = (uint32_t) buf[0] << 24
+		| (uint32_t) buf[1] << 16
+		| (uint32_t) buf[2] << 8
+		| (uint32_t) buf[3] << 0;
+
+	debug("sectors=%u\n", sectors);
+	if (info->hw_sector_size == CDROM_SECTOR_SIZE)
+		sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
+	if (sectors != info->sectors)
+		printf("%uMB medium detected\n", sectors>>(20-9));
+	info->sectors = sectors;
+	return 0;
+}
+
+static int detect_medium(struct harddisk_info *info)
+{
+	if (info->address_mode == ADDRESS_MODE_PACKET) {
+		if (atapi_detect_medium(info) != 0)
+			return -1;
+	} else {
+		debug("not implemented for non-ATAPI device\n");
+		return -1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SUPPORT_PCI
+static int pci_find_ata_device_on_bus(int bus, pcidev_t * dev, int *index, int sata, int pata)
+{
+	int slot, func;
+	u32 val;
+	unsigned char hdr;
+	u32 class;
+
+        for (slot = 0; slot < 0x20; slot++) {
+		for (func = 0; func < 8; func++) {
+			pcidev_t currdev = PCI_DEV(bus, slot, func);
+
+			val = pci_read_config32(currdev, REG_VENDOR_ID);
+
+			if (val == 0xffffffff || val == 0x00000000 ||
+			    val == 0x0000ffff || val == 0xffff0000)
+				continue;
+
+			class = pci_read_config16(currdev, 0x0a);
+			debug("%02x:%02x.%02x [%04x:%04x] class %04x\n",
+				bus, slot, func, val & 0xffff, val >> 16, class);
+
+			if ((sata && class == 0x180) || (pata && class == 0x101)) {
+				if (*index == 0) {
+					*dev = currdev;
+					return 1;
+				}
+				(*index)--;
+			}
+
+			hdr = pci_read_config8(currdev, REG_HEADER_TYPE) & 0x7f;
+
+			if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
+				unsigned int new_bus;
+				new_bus = (pci_read_config32(currdev, REG_PRIMARY_BUS) >> 8) & 0xff;
+				if (pci_find_ata_device_on_bus(new_bus, dev, index, sata, pata))
+					return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int pci_find_ata_device(pcidev_t *dev, int *index, int sata, int pata)
+{
+	debug(" Scanning for:%s%s\n", sata?" SATA":"", pata?" PATA":"");
+	return pci_find_ata_device_on_bus(0, dev, index, sata, pata);
+}
+#endif
+
+
+static int find_ide_controller_compat(struct controller *ctrl, int index)
+{
+#ifdef CONFIG_SUPPORT_PCI
+	int skip, i, pci_index = index / 2;
+	pcidev_t dev;
+#else
+	if (index >= IDE_MAX_CONTROLLERS)
+		return -1;
+#endif
+#ifdef CONFIG_PCMCIA_CF
+	if (index == 2) {
+		ctrl->cmd_base = 0x1e0;
+		ctrl->ctrl_base = 0x1ec;
+		return 0;
+	}
+#endif
+#ifdef CONFIG_SUPPORT_PCI
+	/* skip any SATA and PATA PCI controllers in native mode */
+	for (skip = i = 0; i < pci_index && index; i++) {
+		int devidx = i;
+		/* look for i:th ata (IDE/other storage really) device */
+		if(!pci_find_ata_device(&dev, &devidx, 1, 1))
+			break;
+		/* only IDE can be in compat mode so skip all others */
+		if (pci_read_config16(dev, 0xa) != 0x0101) {
+			/* other storage (SATA) always has two channels */
+			skip += 2;
+			continue;
+		}
+		/* primary in native mode? then skip it. */
+		if (1 == (pci_read_config8(dev, 0x09) & 1))
+			skip++;
+		/* secondary in native mode? then skip it. */
+		if (index && 4 == (pci_read_config8(dev, 0x09)  & 4))
+			skip++;
+	}
+	index = skip <= index ? index - skip : 0;
+	debug("skipping %d native PCI controllers, new index=%d\n", skip, index);
+	if (index >= IDE_MAX_CONTROLLERS)
+		return -1;
+#endif
+	ctrl->cmd_base  = ide_base[index];
+	ctrl->ctrl_base = ide_base[index] + IDE_REG_EXTENDED_OFFSET;
+	return 0;
+}
+
+#ifdef CONFIG_SUPPORT_PCI
+static int find_ide_controller(struct controller *ctrl, int ctrl_index)
+{
+	int pci_index;
+	pcidev_t dev;
+	unsigned int mask;
+	u8 prog_if;
+	u16 vendor, device, devclass;
+
+	/* A PCI IDE controller has two channels (pri, sec) */
+	pci_index = ctrl_index >> 1;
+
+	/* Find a IDE storage class device */
+
+	if (!pci_find_ata_device(&dev, &pci_index, 1, 0)) { // S-ATA first
+		pci_index = ctrl_index >> 1;
+		if (!pci_find_ata_device(&dev, &pci_index, 0, 1)) { // P-ATA second
+			debug("PCI IDE #%d not found\n", ctrl_index >> 1);
+			return -1;
+		}
+	}
+	
+	vendor = pci_read_config16(dev, 0);
+	device = pci_read_config16(dev, 2);
+	prog_if = pci_read_config8(dev, 9);
+	devclass = pci_read_config16(dev, 0x0a);
+
+	debug("found PCI IDE controller %04x:%04x prog_if=%#x\n",
+			vendor, device, prog_if);
+
+	/* See how this controller is configured */
+	mask = (ctrl_index & 1) ? 4 : 1;
+	debug("%s channel: ", (ctrl_index & 1) ? "secondary" : "primary");
+	if ((prog_if & mask) || (devclass != 0x0101)) {
+		debug("native PCI mode\n");
+		if ((ctrl_index & 1) == 0) {
+			/* Primary channel */
+			ctrl->cmd_base = pci_read_resource(dev, 0);
+			ctrl->ctrl_base = pci_read_resource(dev, 1);
+		} else {
+			/* Secondary channel */
+			ctrl->cmd_base = pci_read_resource(dev, 2);
+			ctrl->ctrl_base = pci_read_resource(dev, 3);
+		}
+		ctrl->cmd_base &= ~3;
+		ctrl->ctrl_base &= ~3;
+	} else {
+		debug("compatibility mode\n");
+		if (find_ide_controller_compat(ctrl, ctrl_index) != 0)
+			return -1;
+	}
+	debug("cmd_base=%#x ctrl_base=%#x\n", ctrl->cmd_base, ctrl->ctrl_base);
+#if 0
+	debug("cmd+0=%0#x\n", inb(ctrl->cmd_base+0));
+	debug("cmd+1=%0#x\n", inb(ctrl->cmd_base+1));
+	debug("cmd+2=%0#x\n", inb(ctrl->cmd_base+2));
+	debug("cmd+3=%0#x\n", inb(ctrl->cmd_base+3));
+	debug("cmd+4=%0#x\n", inb(ctrl->cmd_base+4));
+	debug("cmd+5=%0#x\n", inb(ctrl->cmd_base+5));
+	debug("cmd+6=%0#x\n", inb(ctrl->cmd_base+6));
+	debug("cmd+7=%0#x\n", inb(ctrl->cmd_base+7));
+	debug("ctrl+0=%0#x\n", inb(ctrl->ctrl_base+0));
+	debug("ctrl+1=%0#x\n", inb(ctrl->ctrl_base+1));
+	debug("ctrl+2=%0#x\n", inb(ctrl->ctrl_base+2));
+	debug("ctrl+3=%0#x\n", inb(ctrl->ctrl_base+3));
+#endif
+	return 0;
+}
+#else /* !CONFIG_SUPPORT_PCI */
+# define find_ide_controller find_ide_controller_compat
+#endif
+
+int ide_probe(int drive)
+{
+	struct controller *ctrl;
+	int ctrl_index;
+	struct harddisk_info *info;
+
+	if (drive >= IDE_MAX_DRIVES) {
+		printf("Unsupported drive number\n");
+		return -1;
+	}
+
+	/* A controller has two drives (master, slave) */
+	ctrl_index = drive >> 1;
+
+	ctrl = &controllers[ctrl_index];
+	if (ctrl->cmd_base == 0) {
+		if (find_ide_controller(ctrl, ctrl_index) != 0) {
+			printf("IDE channel %d not found\n", ctrl_index);
+			return -1;
+		}
+		if (init_controller(ctrl, drive, ide_buffer) != 0) {
+			printf("No drive detected on IDE channel %d\n",
+					ctrl_index);
+			return -1;
+		}
+	}
+	info = &harddisk_info[drive];
+	if (!info->drive_exists) {
+		printf("Drive %d does not exist\n", drive);
+		return -1;
+	}
+
+	if (info->removable) {
+		if (detect_medium(info) != 0) {
+			printf("Media detection failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* vim:set sts=8 sw=8: */

Added: trunk/filo/drivers/newusb/Makefile.inc
===================================================================
--- trunk/filo/drivers/newusb/Makefile.inc	                        (rev 0)
+++ trunk/filo/drivers/newusb/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-$(CONFIG_USB_NEW_DISK) += drivers/newusb/usb.o

Added: trunk/filo/drivers/newusb/usb.c
===================================================================
--- trunk/filo/drivers/newusb/usb.c	                        (rev 0)
+++ trunk/filo/drivers/newusb/usb.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,59 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <fs.h>
+#include "usb/usb.h"
+#include "usb/usbmsc.h"
+
+
+static usbdev_t* devs[4]; // FIXME: only 4 devices
+static int count = -1;
+
+void usbdisk_create (usbdev_t* dev)
+{
+	if (count == 3) return;
+	devs[++count] = dev;
+}
+
+void usbdisk_remove (usbdev_t* dev)
+{
+	/* FIXME: actually remove the right device */
+	if (count == -1) return;
+	count--;
+}
+
+int usb_new_probe(int drive)
+{
+	/* FIXME: need a place to periodically poll usb_poll().
+	   or at least at sensible times.
+	   this would be a nice place, but the usb disk handling
+	   must be more clever for that.
+	*/
+	if (count >= drive) return drive;
+	return -1;
+}
+
+int usb_new_read(int drive, sector_t sector, void *buffer)
+{
+	if (count < drive) return -1;
+	/* FIXME: only one sector at a time :-(
+	   This must happen some layers further up
+	*/
+	const int size = 1;
+	int result = -readwrite_blocks(devs[drive], sector, size, cbw_direction_data_in, buffer);
+	return result;
+}

Added: trunk/filo/drivers/usb/Makefile.inc
===================================================================
--- trunk/filo/drivers/usb/Makefile.inc	                        (rev 0)
+++ trunk/filo/drivers/usb/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/debug_x.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/ohci.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/scsi_cmds.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/uhci.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/usb.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/usb_scsi_low.o
+TARGETS-$(CONFIG_USB_DISK) += drivers/usb/usb_x.o

Added: trunk/filo/drivers/usb/debug_x.c
===================================================================
--- trunk/filo/drivers/usb/debug_x.c	                        (rev 0)
+++ trunk/filo/drivers/usb/debug_x.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+
+#define DPRINTF debug
+
+#include "usb.h"
+#include "uhci.h"
+#include "debug_x.h"
+
+void dump_link( link_pointer_t *link, char *prefix)
+{
+	DPRINTF("%saddr: %08x\n", prefix, MEM_ADDR(link->link) );
+	DPRINTF("%s raw addr: %04x\n", prefix, (link->link) <<4 );
+	DPRINTF("%sterminate: %x\n", prefix, link->terminate);
+	DPRINTF("%squeue: %x\n", prefix, link->queue);
+	DPRINTF("%sdepth: %x\n", prefix, link->depth);
+}
+
+void dump_frame_list( link_pointer_t *addr, char *prefix)
+{
+	int i;
+
+	DPRINTF("%sFRAMELIST:\n",prefix);
+
+	for(i=0;i<10; i++) {
+		dump_link(addr+i, prefix);
+		if(addr[i].queue)
+			dump_queue_head( MEM_ADDR(addr[i].link), "");
+		else
+			dump_td( MEM_ADDR(addr[i].link), "");
+	}
+}
+
+void dump_hex(uchar *data, int len, char *prefix)
+{
+	int i=0;
+
+	while(i<len) {
+		if(!i%16) {
+			DPRINTF("\n%s %04x: ", prefix, i);
+		}
+		else {
+			DPRINTF(": ");
+		}
+
+		DPRINTF("%02x", data[i++]);
+	}
+
+	DPRINTF("\n");
+}
+
+void dump_uhci(uint32_t port)
+{
+#if 0
+	unsigned long value;
+#endif
+
+	DPRINTF("HCI at %08x\n", port);
+#if 0
+	value = inw(port);
+	DPRINTF("Command: %04x\n", value);
+
+	value = inw(port+2);
+	DPRINTF("USBSTS: %04x\n", value);
+
+	value = inw(port+4);
+	DPRINTF("USBINTR: %04x\n", value);
+
+	value = inw(port+6);
+	DPRINTF("FRNUM: %04x\n", value);
+
+	value = inl(port+8);
+	DPRINTF("FLBASEADD: %08x\n", value);
+
+	value = inb(port+0x0c);
+	DPRINTF("SOFMOD: %02x\n", value);
+
+	value = inw(port+0x10);
+	DPRINTF("PORTSTS1: %04x\n", value);
+
+	value = inw(port+0x12);
+	DPRINTF("PORTSTS2: %04x\n", value);
+	
+#endif
+
+}
+
+void dump_td( td_t *td, char *prefix)
+{
+	char newpre[64];
+
+	newpre[0]='\t';
+	strcpy(newpre+1, prefix);
+
+	DPRINTF("%sTD(%08x):\n", prefix, td);
+
+	switch(td->packet_type) {
+		case SETUP_TOKEN:
+			DPRINTF("%stype: SETUP\n", prefix);
+			break;
+		case OUT_TOKEN:
+			DPRINTF("%stype: OUT\n", prefix);
+			break;
+		case IN_TOKEN:
+			DPRINTF("%stype: IN\n", prefix);
+			break;
+		default:
+			DPRINTF("%stype: INVALID (%02x)\n", prefix, td->packet_type);
+			break;
+	}
+
+	DPRINTF("%sretries: %x\n", prefix, td->retrys);
+
+	if(td->isochronous) {
+		DPRINTF("%sisochronous\n", prefix);
+	}
+
+	if(td->interrupt) {
+		DPRINTF("%sIOC\n", prefix);
+	}
+
+	if(td->lowspeed) {
+		DPRINTF("%slowspeed\n", prefix);
+	}
+
+	if(td->detect_short) {
+		DPRINTF("%sDETECT_SHORT\n", prefix);
+	}
+
+	DPRINTF("%sactive: %04x\n", prefix, td->active);
+	DPRINTF("%sdevice_addr: %02x\n", prefix, td->device_addr);
+	DPRINTF("%sendpoint: %1x\n", prefix, td->endpoint);
+	DPRINTF("%sdata_toggle: %1x\n", prefix, td->data_toggle);
+	DPRINTF("%smax_transfer: %x\n", prefix, td->max_transfer);
+	DPRINTF("%sactual: %x\n", prefix, td->actual);
+	DPRINTF("%slink:\n", prefix);
+
+	if(td->stall) {
+		DPRINTF("%sSTALL\n", prefix);
+	}
+
+	if(td->bitstuff) {
+		DPRINTF("%sBITSTUFF ERROR\n", prefix);
+	}
+
+	if(td->crc) {
+		DPRINTF("%sCRC ERROR\n", prefix);
+	}
+
+	if(td->nak) {
+		DPRINTF("%sNAK ERROR\n", prefix);
+	}
+
+	if(td->babble) {
+		DPRINTF("%sBABBLE ERROR\n", prefix);
+	}
+
+	if(td->buffer_error) {
+		DPRINTF("%sBUFFER ERROR\n", prefix);
+	}
+
+	if(MEM_ADDR(td->link.link) == td) {
+		DPRINTF("link loops back to me!\n");
+		return;
+	}
+
+	dump_link(&(td->link), newpre);
+	if(!td->link.terminate) {
+		if(td->link.queue)
+			dump_queue_head(MEM_ADDR(td->link.link), prefix );
+		else
+			dump_td(MEM_ADDR(td->link.link), prefix);
+	}
+}
+
+void dump_queue_head( queue_head_t *qh, char *prefix)
+{
+	char newpre[64];
+
+	newpre[0] = '\t';
+	strcpy(newpre+1, prefix);
+
+	DPRINTF("%sQUEUE HEAD(%x):\n", prefix, qh);
+	DPRINTF("%sdepth:\n", prefix);
+	dump_link( &(qh->depth), newpre);
+
+	if(!qh->depth.terminate) {
+		if(qh->depth.queue) {
+			dump_queue_head(MEM_ADDR(qh->depth.link), newpre);
+		}
+		else {
+			dump_td( MEM_ADDR(qh->depth.link), newpre);
+		}
+	}
+		
+
+	DPRINTF("%sbredth:\n", prefix);
+	dump_link( &(qh->bredth), newpre);
+	if(!qh->bredth.terminate) {
+		if(qh->bredth.queue) {
+			dump_queue_head(MEM_ADDR(qh->bredth.link), newpre);
+		}
+		else {
+			dump_td( MEM_ADDR(qh->bredth.link), newpre);
+		}
+	}
+}
+
+void dump_transaction( transaction_t *trans, char *prefix)
+{
+	char newpre[64];
+
+	newpre[0] = '\t';
+	strcpy(newpre+1, prefix);
+
+
+	DPRINTF("%s TRANSACTION(%x):\n", prefix, trans);
+	dump_queue_head( trans->qh, newpre);
+
+	DPRINTF("%s TDs:\n", prefix);
+	dump_td( trans->td_list, newpre);
+
+	DPRINTF("\n");
+	if(trans->next)
+		dump_transaction(trans->next, prefix);
+}
+
+void dump_usbdev( usbdev_t *dev, char *prefix)
+{
+	char newpre[64];
+	int i;
+
+	newpre[0] = '\t';
+	strcpy(newpre+1, prefix);
+
+	DPRINTF("%saddress: %x\n", prefix, dev->address);
+	DPRINTF("%sclass: %x\n", prefix, dev->class);
+	DPRINTF("%ssubclass: %x\n", prefix, dev->subclass);
+	DPRINTF("%sbulk_in: %x\n", prefix, dev->bulk_in);
+	DPRINTF("%sbulk_out: %x\n", prefix, dev->bulk_out);
+	DPRINTF("%sinterrupt: %x\n", prefix, dev->interrupt);
+
+	DPRINTF("%sep toggle:\n", prefix);
+		for(i=0;i<MAX_EP;i++) {
+			DPRINTF("%s%x\n", newpre, dev->toggle[i]);
+		}
+
+	DPRINTF("%sep max_packet:\n", prefix);
+		for(i=0;i<MAX_EP;i++) {
+			DPRINTF("%s%x\n", newpre, dev->max_packet[i]);
+		}
+}
+
+void dump_all_usbdev(char *prefix)
+{
+	int i;
+
+	for(i=0;i<MAX_USB_DEV;i++) {
+		if(usb_device[i].address) {
+			DPRINTF("%sDEVICE: %x\n", prefix, i);
+			dump_usbdev( usb_device +i, prefix);
+		}
+	}
+}
+
+void dump_device_descriptor( device_descriptor_t *des, char *prefix)
+{
+	DPRINTF("%sbLength: %02x\n", prefix, des->bLength);
+	DPRINTF("%stype: %02x\n", prefix, des->type);
+	DPRINTF("%sbcdVersion: %1x%1x\n", prefix, des->bcdVersion[1], des->bcdVersion[0]);
+	DPRINTF("%sClass: %02x\n",prefix, des->Class);
+	DPRINTF("%sSubClass: %02x\n",prefix, des->SubClass);
+	DPRINTF("%sprotocol: %02x\n",prefix, des->protocol);
+	DPRINTF("%smax_packet: %x\n",prefix, des->max_packet);
+	DPRINTF("%sidVendor: %04x\n", prefix, des->idVendor);
+	DPRINTF("%sidProduct: %04x\n", prefix, des->idProduct);
+	DPRINTF("%sbcdDeviceVersion: %1x%1x\n", prefix, des->bcdDevice[1], des->bcdDevice[0]);
+	DPRINTF("%siManufacturor: %02x\n", prefix, des->iManufacturor);
+	DPRINTF("%siProduct: %02x\n", prefix, des->iProduct);
+	DPRINTF("%siSerial: %02x\n", prefix, des->iSerial);
+	DPRINTF("%sbNumConfig: %02x\n", prefix, des->bNumConfig);
+
+}
+
+void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix)
+{
+
+	DPRINTF("%sbLength: %02x\n", prefix, iface->bLength);
+	DPRINTF("%stype: %02x\n", prefix, iface->type);
+	DPRINTF("%sbInterfaceNumber: %02x\n", prefix, iface->bInterfaceNumber);
+	DPRINTF("%sbAlternateSetting: %02x\n", prefix, iface->bAlternateSetting);
+	DPRINTF("%sbNumEndpoints: %02x\n", prefix, iface->bNumEndpoints);
+	DPRINTF("%sbInterfaceClass: %02x\n", prefix, iface->bInterfaceClass);
+	DPRINTF("%sbInterfaceSubClass: %02x\n", prefix, iface->bInterfaceSubClass);
+	DPRINTF("%sbInterfaceProtocol: %02x\n", prefix, iface->bInterfaceProtocol);
+	DPRINTF("%siInterface: %02x\n", prefix, iface->iInterface);
+}
+
+void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix)
+{
+
+	DPRINTF("%sbLength: %02x\n", prefix, ep->bLength);
+	DPRINTF("%stype: %02x\n", prefix, ep->type);
+	DPRINTF("%sbEndpointAddress: %02x\n", prefix, ep->bEndpointAddress);
+	DPRINTF("%sbmAttributes: %02x\n", prefix, ep->bmAttributes);
+	DPRINTF("%swMaxPacketSize: %02x\n", prefix, ep->wMaxPacketSize);
+	DPRINTF("%sbInterval: %02x\n", prefix, ep->bInterval);
+}
+
+void dump_config_descriptor( uchar *des, char *prefix)	// YES uchar *
+{
+	config_descriptor_t *config;
+	interface_descriptor_t *iface;
+	endpoint_descriptor_t *ep;
+	char newpre[64];
+	int i;
+
+	memset(newpre,0,sizeof(newpre));
+	newpre[0] = '\t';
+	strcpy(newpre+1, prefix);
+
+	config = (config_descriptor_t *) des;
+	iface = (interface_descriptor_t *) (des + config->bLength);
+	ep = (endpoint_descriptor_t *) (des + config->bLength + iface->bLength);
+	
+	// now, the config itself
+	DPRINTF("%sbLength: %02x\n", prefix, config->bLength);
+	DPRINTF("%stype: %02x\n", prefix, config->type);
+	DPRINTF("%swTotalLength: %04x\n", prefix, config->wTotalLength);
+	DPRINTF("%sbNumInterfaces: %02x\n", prefix, config->bNumInterfaces);
+	DPRINTF("%sbConfigurationValue: %02x\n", prefix, config->bConfigurationValue);
+	DPRINTF("%siConfiguration: %02x\n", prefix, config->iConfiguration);
+	DPRINTF("%sbmAttributes: %02x\n", prefix, config->bmAttributes);
+
+	DPRINTF("%sbMaxPower: %02x\n", prefix, config->bMaxPower);
+
+	DPRINTF("\n%sInterface(%x):\n", prefix, iface);
+	dump_interface_descriptor(iface, newpre);
+
+	newpre[1] = '\t';
+	strcpy(newpre+2, prefix);
+
+	for(i=0; i<iface->bNumEndpoints; i++) {
+		DPRINTF("\n%sEndpoint (%x):\n", newpre+1, ep+i);
+		dump_endpoint_descriptor( ep+i, newpre);
+	}
+}
+
+// Some control message bmRequestType defines
+#define CTRL_DEVICE 0
+#define CONTROL_INTERFACE 1
+#define CONTROL_ENDPOINT 2
+#define CONTROL_OTHER 3
+#define CONTROL_RECIPIENT_MASK 0x1f
+
+#define CONTROL_TYPE_STD 0
+#define CONTROL_TYPE_CLASS 0x20
+#define CONTROL_CLASS_VENDOR 0x40
+#define CONTROL_CLASS_MASK 0x60
+
+#define CONTROL_OUT 0
+#define CONTROL_IN 0x80
+#define CONTROL_DIR_MASK 0x80
+
+// bRequest values
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+#define SET_FEATURE 3
+#define SET_ADDRESS 5
+
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+
+#define SYNC_FRAME 12
+
+// descriptor types
+#define DEVICE_DESC 1
+#define CONFIGURATION_DESC 2
+#define STRING_DESC 3
+#define INTERFACE_DESC 4
+#define ENDPOINT_DESC 5
+#define OTHERSPEED_DESC 7
+#define POWER_DESC 8
+
+// features
+#define FEATURE_HALT 0
+void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix)
+{
+	DPRINTF("%sbmRequestType: %02x\n", prefix, msg->bmRequestType);
+	DPRINTF("%sbRequest: %02x\n", prefix, msg->bRequest);
+	DPRINTF("%swValue: %04x\n", prefix, msg->wValue);
+	DPRINTF("%swIndex: %04x\n", prefix, msg->wIndex);
+	DPRINTF("%swLength: %04x\n", prefix, msg->wLength);
+}
+

Added: trunk/filo/drivers/usb/debug_x.h
===================================================================
--- trunk/filo/drivers/usb/debug_x.h	                        (rev 0)
+++ trunk/filo/drivers/usb/debug_x.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,18 @@
+#ifndef _DEBUG_X_H
+#define _DEBUG_X_H
+
+void dump_hex(uchar *data, int len, char *prefix);
+void dump_link( link_pointer_t *link, char *prefix);
+void dump_td( td_t *td, char *prefix);
+void dump_queue_head( queue_head_t *qh, char *prefix);
+void dump_transaction( transaction_t *trans, char *prefix);
+void dump_usbdev( usbdev_t *dev, char *prefix);
+void dump_uhci(uint32_t port);
+//void dump_all_usbdev(char *prefix);
+void dump_device_descriptor( device_descriptor_t *des, char *prefix);
+void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix);
+void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix);
+void dump_config_descriptor( uchar *des, char *prefix);
+void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix);
+
+#endif

Added: trunk/filo/drivers/usb/ohci.c
===================================================================
--- trunk/filo/drivers/usb/ohci.c	                        (rev 0)
+++ trunk/filo/drivers/usb/ohci.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1434 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <arch/byteorder.h>
+#include <pci.h>
+
+        
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+
+#define DPRINTF debug
+
+#define DEBUG_TD 0
+#define DEBUG_ED 0
+
+
+#include "usb.h"
+#include "ohci.h"
+
+
+extern int usec_offset;
+
+ohci_regs_t *ohci_regs;
+
+// It will clear the enable bit
+void ohc_clear_stat(uchar dev)
+{
+        uint32_t value;
+	ohci_regs = (ohci_regs_t *)hc_base[dev];
+	
+	value = readl(&ohci_regs->cmdstatus);
+	writel(value, &ohci_regs->cmdstatus);
+}
+	
+void clear_oport_stat(uint32_t port)
+{
+        uint32_t value;
+
+        value = readl(port);
+        writel(value, port);
+}
+
+void oport_suspend( uint32_t port)
+{
+        writel( RH_PS_PSS, port);
+
+}
+void oport_wakeup( uint32_t port)
+{
+        writel( RH_PS_POCI, port);
+
+}
+#if 0
+void oport_resume( uint32_t port)
+{
+        uint32_t value;
+
+        value = readl(port);
+        value |= 0x40;
+        writel(value, port);
+        udelay(20000+usec_offset);
+        value &= ~0x40;
+        writel(value, port);
+
+        do {
+                value = readl(port);
+        } while(value & 0x40);
+}       
+#endif
+void oport_enable( uint32_t port)
+{
+	uint32_t value;
+	
+	value = readl(port);
+	
+	if((value & RH_PS_CCS)) {  // if connected
+		writel( RH_PS_PES, port);
+		udelay(10);
+		writel( RH_PS_PESC, port); // Clear Change bit
+	}
+
+}
+
+
+
+void oport_disable( uint32_t port)
+{
+        writel( RH_PS_CCS, port);
+}
+
+void oport_reset(uint32_t port)
+{
+
+        uint32_t value;
+
+        writel( RH_PS_PRS, port);
+        do {
+               value = readl( port );
+        } while (!(value & RH_PS_PRSC) );
+	writel(RH_PS_PRSC, port);  //Clear Change bit
+
+}
+
+void oport_reset_long(uint32_t port)
+{
+	oport_reset(port);
+}
+
+#if 0
+
+int ohc_stop(uchar dev)
+{
+        unsigned short tmp;
+	uint32_t ctl;
+       
+	ohci_regs = hc_base[dev];
+
+	ctl = readl( &ohci_regs->control);
+        ctl &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+        writel (ctl, &ohci_regs->control); 
+        
+        return(0);
+}  
+#endif
+
+
+#define MAX_OHCI_TD 32
+
+ohci_td_t *_ohci_td;
+uint8_t	_ohci_td_tag[MAX_OHCI_TD]; //1: used, 0:unused
+
+void init_ohci_td(){
+	_ohci_td = allot2(sizeof(ohci_td_t)*MAX_OHCI_TD, 0x1f); // 32 byte aligna
+	if(_ohci_td==0) {
+		printf("init_ohci_td: NOMEM\n");
+	}
+	memset(_ohci_td_tag, 0, sizeof(_ohci_td_tag));
+}
+
+ohci_td_t *td_alloc(ohci_t *ohci, int memflag){
+	int i;
+	ohci_td_t *td;
+	for(i = 0; i< MAX_OHCI_TD; i++ ) {
+		if(_ohci_td_tag[i]==1) continue;
+		td = &_ohci_td[i];
+		memset(td, 0, sizeof(ohci_td_t));
+		td->td_dma = (void *)virt_to_phys(td);
+		_ohci_td_tag[i] = 1;
+		return td;
+	}
+	printf("td_alloc: no free slot\n");
+	return 0;
+}
+
+int td_free(ohci_t *ohci, ohci_td_t *td) {
+	int i;
+	for(i = 0; i< MAX_OHCI_TD; i++ ) {
+                if(_ohci_td_tag[i]==0) continue;
+		if(&_ohci_td[i] == td ) {
+			_ohci_td_tag[i] = 0;
+			return 1;
+		}
+        }
+        return 0;
+}
+
+
+struct ohci_td *
+dma_to_td (struct ohci * hc, void *td_dma)
+{
+        int i;  
+        ohci_td_t *td;
+        for(i = 0; i< MAX_OHCI_TD; i++ ) {
+                if(_ohci_td_tag[i]==0) continue;
+		td = &_ohci_td[i];
+                if(td->td_dma == td_dma ) {
+                        return td;
+                }
+        }
+	printf("dma_to_td: can not find td\n");
+        return 0;
+
+}
+
+ohci_t _ohci_x[MAX_CONTROLLERS];
+
+void ohci_init(void)
+{       
+	init_ohci_td();
+}
+
+static int ohci_get_current_frame_number (struct usbdev *usb_dev)
+{
+        ohci_t * ohci = &_ohci_x[usb_dev->controller]; 
+ 
+        return le16_to_cpu (ohci->hcca->frame_no);
+}
+ 
+
+
+static u32 roothub_a (struct ohci *hc)
+        { return readl (&hc->regs->roothub.a); }
+static inline u32 roothub_b (struct ohci *hc)
+        { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+        { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+        { return readl (&hc->regs->roothub.portstatus[i]);}
+ 
+ 
+#if CONFIG_DEBUG_USB
+
+#define OHCI_VERBOSE_DEBUG
+
+# define dbg(...) \
+    do { printf(__VA_ARGS__); printf("\n"); } while (0)
+
+static void urb_print (struct urb * urb, char * str, int small)
+{
+        unsigned int pipe= urb->pipe;
+        
+        if (!urb->dev ) { 
+                dbg("%s URB: no dev", str);
+                return;
+        }
+
+#ifndef OHCI_VERBOSE_DEBUG
+        if (urb->status != 0)
+#endif
+        dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)",
+                        str,
+                        ohci_get_current_frame_number (urb->dev),
+                        usb_pipedevice (pipe),
+                        usb_pipeendpoint (pipe),
+                        usb_pipeout (pipe)? 'O': 'I',
+                        usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+                                (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+                        urb->transfer_flags,
+                        urb->actual_length,
+                        urb->transfer_buffer_length,
+                        urb->status, urb->status);
+#ifdef  OHCI_VERBOSE_DEBUG
+//        if (!small) {
+                int i, len;
+
+                if (usb_pipecontrol (pipe)) {
+                        printf ("ohci.c: cmd(8):");
+                        for (i = 0; i < 8 ; i++)
+                                printf (" %02x", ((u8 *) urb->setup_packet) [i]);
+                        printf ("\n");
+                }
+                if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+                         printf("ohci.c: data(%d/%d):",
+                                urb->actual_length,
+                                urb->transfer_buffer_length);
+                        len = usb_pipeout (pipe)?
+                                                urb->transfer_buffer_length: urb->actual_length;
+                        for (i = 0; i < 16 && i < len; i++)
+                                printf (" %02x", ((u8 *) urb->transfer_buffer) [i]);
+                        printf ("%s stat:%d\n", i < len? "...": "", urb->status);
+                }
+//        }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t * ohci, char * str) {
+        int i, j;
+         u32 * ed_p;
+        for (i= 0; i < 32; i++) {
+                j = 5;
+                ed_p = &(ohci->hcca->int_table [i]);
+                if (*ed_p == 0)
+                    continue;
+                printf ("ohci.c: %s branch int %2d(%2x):", str, i, i);
+#if 0
+                while (*ed_p != 0 && j--) {
+                        ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
+                        printk (" ed: %4x;", ed->hwINFO);
+                        ed_p = &ed->hwNextED;
+                }
+#endif
+                printf ("\n");
+        }
+}
+static void ohci_dump_intr_mask (char *label, u32 mask)
+{
+        dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+                label,
+                mask,
+                (mask & OHCI_INTR_MIE) ? " MIE" : "",
+                (mask & OHCI_INTR_OC) ? " OC" : "",
+                (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+                (mask & OHCI_INTR_FNO) ? " FNO" : "",
+                (mask & OHCI_INTR_UE) ? " UE" : "",
+                (mask & OHCI_INTR_RD) ? " RD" : "",
+                (mask & OHCI_INTR_SF) ? " SF" : "",
+                (mask & OHCI_INTR_WDH) ? " WDH" : "",
+                (mask & OHCI_INTR_SO) ? " SO" : ""
+                );
+}
+static void maybe_print_eds (char *label, u32 value)
+{
+        if (value)
+                dbg ("%s %08x", label, value);
+}
+static char *hcfs2string (int state)
+{
+        switch (state) {
+                case OHCI_USB_RESET:    return "reset";
+                case OHCI_USB_RESUME:   return "resume";
+                case OHCI_USB_OPER:     return "operational";
+                case OHCI_USB_SUSPEND:  return "suspend";
+        }
+        return "?";
+}
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+        struct ohci_regs        *regs = controller->regs;
+        u32                   temp;
+
+        temp = readl (&regs->revision) & 0xff;
+        if (temp != 0x10)
+                dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+        temp = readl (&regs->control);
+        dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+                (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+                (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+                (temp & OHCI_CTRL_IR) ? " IR" : "",
+                hcfs2string (temp & OHCI_CTRL_HCFS),
+                (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+                (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+                (temp & OHCI_CTRL_IE) ? " IE" : "",
+                (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+                temp & OHCI_CTRL_CBSR
+                );
+
+        temp = readl (&regs->cmdstatus);
+        dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+                (temp & OHCI_SOC) >> 16,
+                (temp & OHCI_OCR) ? " OCR" : "",
+                (temp & OHCI_BLF) ? " BLF" : "",
+                (temp & OHCI_CLF) ? " CLF" : "",
+                (temp & OHCI_HCR) ? " HCR" : ""
+                );
+
+        ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+        ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+        // intrdisable always same as intrenable
+        // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+        maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+        maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+        maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+        maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+        maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+        maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+        u32                   temp, ndp, i;
+
+        temp = roothub_a (controller);
+        if (temp == ~(u32)0)
+                return;
+        ndp = (temp & RH_A_NDP);
+
+        if (verbose) {
+                dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+                        ((temp & RH_A_POTPGT) >> 24) & 0xff,
+                        (temp & RH_A_NOCP) ? " NOCP" : "",
+                        (temp & RH_A_OCPM) ? " OCPM" : "",
+                        (temp & RH_A_DT) ? " DT" : "",
+                        (temp & RH_A_NPS) ? " NPS" : "",
+                        (temp & RH_A_PSM) ? " PSM" : "",
+                        ndp
+                        );
+                temp = roothub_b (controller);
+                dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+                        temp,
+                        (temp & RH_B_PPCM) >> 16,
+                        (temp & RH_B_DR)
+                        );
+                temp = roothub_status (controller);
+                dbg ("roothub.status: %08x%s%s%s%s%s%s",
+                        temp,
+                        (temp & RH_HS_CRWE) ? " CRWE" : "",
+                        (temp & RH_HS_OCIC) ? " OCIC" : "",
+                        (temp & RH_HS_LPSC) ? " LPSC" : "",
+                        (temp & RH_HS_DRWE) ? " DRWE" : "",
+                        (temp & RH_HS_OCI) ? " OCI" : "",
+                        (temp & RH_HS_LPS) ? " LPS" : ""
+                        );
+        }
+
+        for (i = 0; i < ndp; i++) {
+                temp = roothub_portstatus (controller, i);
+                dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+                        i,
+                        temp,
+                        (temp & RH_PS_PRSC) ? " PRSC" : "",
+                        (temp & RH_PS_OCIC) ? " OCIC" : "",
+                        (temp & RH_PS_PSSC) ? " PSSC" : "",
+                        (temp & RH_PS_PESC) ? " PESC" : "",
+                        (temp & RH_PS_CSC) ? " CSC" : "",
+
+                        (temp & RH_PS_LSDA) ? " LSDA" : "",
+                        (temp & RH_PS_PPS) ? " PPS" : "",
+                        (temp & RH_PS_PRS) ? " PRS" : "",
+                        (temp & RH_PS_POCI) ? " POCI" : "",
+                        (temp & RH_PS_PSS) ? " PSS" : "",
+
+                        (temp & RH_PS_PES) ? " PES" : "",
+                        (temp & RH_PS_CCS) ? " CCS" : ""
+                        );
+        }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+        dbg ("OHCI controller usb-%x state", controller->regs);
+
+        // dumps some of the state we know about
+        ohci_dump_status (controller);
+        if (verbose)
+                ep_print_int_eds (controller, "hcca");
+        dbg ("hcca frame #%04x", controller->hcca->frame_no);
+        ohci_dump_roothub (controller, 1);
+}
+void ohci_dump_x(uchar controller)
+{
+	ohci_t *ohci;
+        ohci = &_ohci_x[controller];
+        ohci_dump (ohci, 1);
+}
+#endif
+
+/* link an ed into one of the HC chains */
+
+/* ED is only enqueued and dequeued by HCD 
+	So ep_link may only to be called two times for every device (function) -- ed, one for controled and one for bulked 
+	one ohci may have several controled and bulked.
+*/
+
+int ep_link (ohci_t * ohci, ed_t * edi)
+{
+        volatile ed_t * ed = edi;
+
+        ed->state = ED_OPER;
+	
+        switch (ed->type) {
+        case PIPE_CONTROL:
+                ed->hwNextED = 0;
+                if (ohci->ed_controltail == NULL) {
+//			debug("ep_link control 21 ed->dma = %x\n", (uint32_t)ed->dma);
+                        writel ((uint32_t)ed->dma, &ohci->regs->ed_controlhead);
+                } else {
+//			debug("ep_link control 22 ed->dma = %x\n", (uint32_t)ed->dma);
+                        ohci->ed_controltail->hwNextED = cpu_to_le32 ((uint32_t)ed->dma);
+                }
+                ed->ed_prev = ohci->ed_controltail;
+                if (!ohci->ed_controltail) {
+			/* enable control ed list */
+                        ohci->hc_control |= OHCI_CTRL_CLE;  //5
+                        writel (ohci->hc_control, &ohci->regs->control);
+                }
+                ohci->ed_controltail = edi;
+                break;
+
+        case PIPE_BULK:
+                ed->hwNextED = 0;
+                if (ohci->ed_bulktail == NULL) {
+		//	debug("ep_link control 31 ed->dma = %x\n", (uint32_t)ed->dma);
+                        writel ((uint32_t)ed->dma, &ohci->regs->ed_bulkhead);
+                } else {
+		//	debug("ep_link control 32 ed->dma = %x\n", (uint32_t)ed->dma);
+                        ohci->ed_bulktail->hwNextED = cpu_to_le32 ((uint32_t)ed->dma);
+                }
+                ed->ed_prev = ohci->ed_bulktail;
+                if (!ohci->ed_bulktail) {
+			/* enable bulk ed list */
+                        ohci->hc_control |= OHCI_CTRL_BLE;  //5
+                        writel (ohci->hc_control, &ohci->regs->control);
+                }
+                ohci->ed_bulktail = edi;
+                break;
+        }
+        return 0;
+}
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless  so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+ed_t * ep_add_ed (
+        usbdev_t * usb_dev,
+        unsigned int pipe,
+        int interval,
+        int load,
+        int mem_flags
+)
+{
+        ohci_t * ohci = &_ohci_x[usb_dev->controller];
+        ohci_td_t * td;
+        ed_t * ed;
+        unsigned long flags;
+	int i;
+
+	/* We use preallocate ed in ohci struct
+		numbering rule ???
+	*/
+	i = (usb_pipeendpoint (pipe) << 1) |(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe));
+        ed = (ed_t *)&ohci->ed[i];
+
+//	debug("ep_add_ed: usb_dev port=%x, controller = %d ohci=%x ohci->ed=%x ed=%x ed->dma=%x\n", usb_dev->port,usb_dev->controller, ohci, ohci->ed, ed, ed->dma);
+
+        if (ed->state == ED_NEW) {
+                ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+                /* dummy td; end of td list for ed */
+                td = td_alloc (ohci, 0);
+                                               
+                ed->hwTailP = cpu_to_le32 ((uint32_t)td->td_dma);
+                ed->hwHeadP = ed->hwTailP;
+                ed->state = ED_UNLINK;
+                ed->type = usb_pipetype (pipe);
+                ohci->ed_cnt++;  // we will be used to calcaulate next pipe
+
+//	        debug("ep_add_ed 1 td=%x dma=%x ed->dma=%x ed->hwHeadP=%x ed->hwTailP=%x\n", td, td->td_dma, ed->dma, ed->hwHeadP, ed->hwTailP); 
+		
+        }
+
+        ohci->dev[usb_pipedevice (pipe)] = usb_dev;  // marked the ed to this dev
+
+        ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+                        | usb_pipeendpoint (pipe) << 7
+                        | (usb_pipeisoc (pipe)? 0x8000: 0)
+                        | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+                        | usb_pipeslow (pipe) << 13
+                        | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
+
+//	debug("ep_add_ed:  pipe=%x ed_num=%d ed->dma=%x ed->hwInfo=%x ed->hwHeadP=%x ed->hwTailP=%x\n", pipe, i, ed->dma, ed->hwINFO, ed->hwHeadP, ed->hwTailP);
+
+        return ed;
+}
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+void
+td_fill (ohci_t * ohci, unsigned int info,
+        void *data, int len,
+        struct urb * urb, int index) // *data should dma address of buffer
+{       
+        ohci_td_t  * td, * td_pt;
+        urb_priv_t * urb_priv = urb->hcpriv;
+        
+        if (index >= urb_priv->length) {
+                printf("internal OHCI error: TD index > length");
+                return;
+        }       
+
+        /* use this td as the next dummy */
+        td_pt = urb_priv->td [index];
+        td_pt->hwNextTD = 0;
+
+        /* fill the old dummy TD */
+        td = urb_priv->td [index] = dma_to_td (ohci,
+                        (void *)(le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf));
+	
+//	debug("td_fill 2 td = %x, dma=%x , ed->hwHeadP=%x, ed->hwTailP=%x \n", td, td->td_dma, urb_priv->ed->hwHeadP, urb_priv->ed->hwTailP ); 
+
+        td->ed = urb_priv->ed;
+        td->next_dl_td = NULL;
+        td->index = index;
+        td->urb = urb;
+        td->data_dma = data;
+        if (!len)
+                data = 0;
+
+
+        td->hwINFO = cpu_to_le32 (info);
+        td->hwCBP = cpu_to_le32 ((uint32_t)data);
+        if (data)
+                td->hwBE = cpu_to_le32 ((uint32_t)data + len - 1);
+        else
+                td->hwBE = 0;
+        td->hwNextTD = cpu_to_le32 ((uint32_t)td_pt->td_dma);
+
+        /* append to queue */
+        td->ed->hwTailP = td->hwNextTD;
+ //	debug("td_fill 4 td->td_dma=%x, td->hwINFO=%x\n", td->td_dma, td->hwINFO );
+ //       debug("td_fill 5 ed->dma=%x, ed->hwHeadP=%x, ed->hwTailP=%x \n", urb_priv->ed->dma, urb_priv->ed->hwHeadP, urb_priv->ed->hwTailP );
+}
+
+/* prepare all TDs of a transfer */
+        
+void td_submit_urb (struct urb * urb)
+{
+        urb_priv_t * urb_priv = urb->hcpriv;
+        ohci_t * ohci = (ohci_t *) &_ohci_x[urb->dev->controller];
+        void * data;
+        int data_len = urb->transfer_buffer_length;
+        int cnt = 0; 
+        u32 info = 0;
+        unsigned int toggle = 0;
+	void *setup_buffer;
+
+        /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+        if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
+                toggle = TD_T_TOGGLE;
+        } else {
+                toggle = TD_T_DATA0;
+                usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
+        }
+        
+        urb_priv->td_cnt = 0;
+        
+        if (data_len) {
+                data = (void *)virt_to_phys(urb->transfer_buffer);
+        } else  
+                data = 0;
+        switch (usb_pipetype (urb->pipe)) {
+                case PIPE_BULK:
+                        info = usb_pipeout (urb->pipe)?
+                                TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+                        while(data_len > 4096) {
+                                td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
+                                data += 4096; data_len -= 4096; cnt++;
+                        }
+                        info = usb_pipeout (urb->pipe)?
+                                TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+                        td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
+                        cnt++;
+#if 0
+                        /* If the transfer size is multiple of the pipe mtu,
+                         * we may need an extra TD to create a empty frame
+                         * Note : another way to check this condition is
+                         * to test if(urb_priv->length > cnt) - Jean II */
+                        if ((urb->transfer_flags & USB_ZERO_PACKET) &&
+                            usb_pipeout (urb->pipe) &&
+                            (urb->transfer_buffer_length != 0) &&
+                            ((urb->transfer_buffer_length % maxps) == 0)) {
+                                td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
+                                cnt++;
+                        }
+#endif
+
+//			debug("td_submit_urb 2 -- set OHCI_BLF\n");
+                        writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+                        (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+                        break;
+
+
+                case PIPE_CONTROL:
+                        info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+			setup_buffer = (void *)virt_to_phys(urb->setup_packet);	
+//			debug("td_sumbit_urb 11 setup_buffer = %x\n", setup_buffer);
+        	        td_fill (ohci, info, setup_buffer , 8, urb, cnt++);
+                        if (data_len > 0) {
+                                info = usb_pipeout (urb->pipe)?
+                                        TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+                                /* NOTE:  mishandles transfers >8K, some >4K */
+                                td_fill (ohci, info, data, data_len, urb, cnt++);
+                        }
+                        info = usb_pipeout (urb->pipe)?
+                                TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+                        td_fill (ohci, info, data, 0, urb, cnt++);
+//                        debug("td_sumbit_urb 11 data = %x\n", data);
+
+//			debug("td_submit_urb 2 -- set OHCI_CLF\n");
+                        writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+                        (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+                        break;
+
+        }
+        if (urb_priv->length != cnt) {
+                debug("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+	}
+}
+
+/* free HCD-private data associated with this URB */
+        
+void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
+{       
+        int             i;
+        int             last = urb_priv->length - 1;
+        int             len;
+        struct ohci_td       *td;
+                        
+        if (last >= 0) {
+#if 0
+                /* ISOC, BULK, INTR data buffer starts at td 0 
+                 * CTRL setup starts at td 0 */
+                td = urb_priv->td [0];
+                        
+                len = td->urb->transfer_buffer_length;
+                                
+                /* unmap CTRL URB setup */
+                if (usb_pipecontrol (td->urb->pipe)) {
+// it should be freed in usb_control_msg_x
+//			forget2((void *)phys_to_virt((uint32_t)td->data_dma));  // 8 bytes
+                 
+                        /* CTRL data buffer starts at td 1 if len > 0 */
+                        if (len && last > 0)
+                                td = urb_priv->td [1];
+                } 
+        
+                /* unmap data buffer */
+                if (len && td->data_dma) {
+// Don't need
+//				forget2((void *)phys_to_virt((uint32_t)td->data_dma)); 
+			}
+#endif
+ 
+                for (i = 0; i <= last; i++) {
+                        td = urb_priv->td [i];
+                        if (td)
+                                td_free (hc, td);
+                }
+        }
+#if URB_PRE_ALLOCATE!=1
+        forget2((void *)urb_priv);
+#endif
+}
+
+/* get a transfer request */    
+                                
+int ohci_submit_urb (struct urb * urb)
+{                       
+        ohci_t * ohci;
+        ed_t * ed;
+        urb_priv_t * urb_priv;
+        unsigned int pipe = urb->pipe;
+        int i, size = 0;        
+        int mem_flags = 0;
+
+        if (!urb->dev)
+                return -ENODEV;
+
+        if (urb->hcpriv)                        /* urb already in use */
+                return -EINVAL;
+
+
+        ohci = (ohci_t *) &_ohci_x[urb->dev->controller];
+//	printf("ohci_submit_urb: urb->dev port=%x, controller = %d ohci=%x ohci->ed=%x ohci->hcca=%x\n", urb->dev->port,urb->dev->controller, ohci, ohci->ed, ohci->hcca);
+
+#if CONFIG_DEBUG_USB==1
+//        urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+
+
+#if 0
+        /* handle a request to the virtual root hub */
+        if (usb_pipedevice (pipe) == ohci->rh.devnum)
+                return rh_submit_urb (urb);
+
+        /* when controller's hung, permit only roothub cleanup attempts
+         * such as powering down ports */
+        if (ohci->disabled) {
+                usb_dec_dev_use (urb->dev);
+                return -ESHUTDOWN;
+        }
+#endif
+
+        /* every endpoint has a ed, locate and fill it */
+        if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
+                return -ENOMEM;
+        }
+//	debug("ohci_submit_usb: ed->dma=%x\n", ed->dma);
+
+                                           /* for the private part of the URB we need the number of TDs (size) */
+        switch (usb_pipetype (pipe)) {
+                case PIPE_BULK: /* one TD for every 4096 Byte */
+                        size = (urb->transfer_buffer_length - 1) / 4096 + 1;
+#if 0
+                        /* If the transfer size is multiple of the pipe mtu,
+                         * we may need an extra TD to create a empty frame
+                         * Jean II */
+                        if ((urb->transfer_flags & USB_ZERO_PACKET) &&
+                            usb_pipeout (pipe) &&
+                            (urb->transfer_buffer_length != 0) &&
+                            ((urb->transfer_buffer_length % maxps) == 0))
+                                size++;
+#endif
+                        break;
+                case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+                        size = (urb->transfer_buffer_length == 0)? 2:
+                                                (urb->transfer_buffer_length - 1) / 4096 + 3;
+                        break;
+        }
+
+        /* allocate the private part of the URB */
+#if URB_PRE_ALLOCATE!=1
+        urb_priv = allot2 (sizeof (urb_priv_t) + size * sizeof (ohci_td_t *), 0xff);
+        if (urb_priv == 0) {
+		printf("ohci_submit_usb: urb_priv allocated no mem\n");
+                return -ENOMEM;
+        }
+#else 
+	urb_priv = ohci->urb_priv;
+#endif
+        memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (ohci_td_t *));
+
+        /* fill the private part of the URB */
+        urb_priv->length = size;
+        urb_priv->ed = ed;
+
+        /* allocate the TDs (updating hash chains) */
+        for (i = 0; i < size; i++) {
+                urb_priv->td[i] = td_alloc (ohci, 0);
+                if (!urb_priv->td[i]) {
+                        urb_priv->length = i;
+                        urb_free_priv (ohci, urb_priv);
+                        return -ENOMEM;
+                }
+        }
+
+        if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+                urb_free_priv (ohci, urb_priv);
+                return -EINVAL;
+        }
+
+        urb->actual_length = 0;
+        urb->hcpriv = urb_priv;
+        urb->status = USB_ST_URB_PENDING;
+        /* link the ed into a chain if is not already */
+        if (ed->state != ED_OPER) {
+                ep_link (ohci, ed);
+	}
+
+        /* fill the TDs and link it to the ed */
+        td_submit_urb (urb);
+
+#if 0
+        /* drive timeouts by SF (messy, but works) */
+        writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+        (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+#endif
+
+        return 0;
+}
+/* calculate the transfer length and update the urb */
+
+void dl_transfer_length(ohci_td_t * td)
+{
+        u32 tdINFO, tdBE, tdCBP;
+        struct urb * urb = td->urb;
+        urb_priv_t * urb_priv = urb->hcpriv;
+
+        tdINFO = le32_to_cpup (&td->hwINFO);
+        tdBE   = le32_to_cpup (&td->hwBE);
+        tdCBP  = le32_to_cpup (&td->hwCBP);
+
+
+                if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
+                                ((td->index == 0) || (td->index == urb_priv->length - 1)))) {
+                        if (tdBE != 0) {
+                                if (td->hwCBP == 0)
+                                        urb->actual_length += tdBE - (uint32_t)td->data_dma + 1;
+                                else
+                                        urb->actual_length += tdCBP - (uint32_t)td->data_dma;
+                        }
+			
+                }
+
+//	debug("td->td_dma=%x, urb->actual_length=%d\n", td->td_dma, urb->actual_length);	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+ohci_td_t * dl_reverse_done_list (ohci_t * ohci)
+{
+        u32 td_list_hc;
+        ohci_td_t * td_rev = NULL;
+        ohci_td_t * td_list = NULL;
+        urb_priv_t * urb_priv = NULL;
+	uint32_t value;
+	u32 td_list_hc2;
+	int timeout = 1000000; //1 second
+//        unsigned long flags;
+// Here need to process across the frame tds
+        td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	td_list_hc2 = readl(&ohci->regs->donehead);
+//	debug("ohci->hcca->done_head = %x ohci->hcca=%x ohci=%x ohci->regs->donehead=%x\n", td_list_hc, ohci->hcca, ohci, td_list_hc2);
+
+	td_list = dma_to_td (ohci, (void *)td_list_hc);
+	urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+	
+	while(/*(td_list_hc2!=0) || */(td_list->index < urb_priv->length-1) && (timeout>0)) { // wait another update for donehead
+		// To handle 1. ohci->hcca->donehead !=0 and regs->donehead!=0
+		//	     2. ohci->hcca->donehead !=0 and regs->donehead ==0 but regs-->donehead will be filled 
+	
+		ohci->hcca->done_head = 0;
+
+        	value = readl(&ohci->regs->intrstatus);
+        	value &= readl(&ohci->regs->intrenable);
+
+	//      We need to clear that the bit, otherwise We will not get next return.
+        	if(value & OHCI_INTR_WDH) {
+              		writel(value, &ohci->regs->intrstatus);
+	      		(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+//		      debug("OHCI_INTR_WDH cleared intrstatus=%x value=%x \n", readl(&ohci->regs->intrstatus), value);
+        	}
+		while(timeout>0) {  // wait for next DONEHEAD_WRITEBACK
+                	value = readl(&ohci->regs->intrstatus);
+                	if(!(value & OHCI_INTR_WDH)) {
+                        	udelay(1);
+                        	timeout--;
+                        	continue;
+                	} else {
+                        	break;
+                	}
+		}
+
+		td_list_hc2 = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+		// merge td_list_hc the tail of td_list_hc2 
+
+		if(td_list_hc2!=0) {
+
+			while (td_list_hc2) {
+                		td_list = dma_to_td (ohci, (void *)td_list_hc2);
+                		td_list_hc2 = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
+			}
+
+			td_list->hwNextTD = td_list_hc;
+
+			td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+
+			td_list = dma_to_td (ohci, (void *)td_list_hc);
+		} else {
+			printf(".");
+		}
+		
+	}
+
+	ohci->hcca->done_head = 0;
+	
+	value = readl(&ohci->regs->intrstatus);
+//        debug("OHCI_INTR_WDH value=%x \n", value);
+        value &= readl(&ohci->regs->intrenable);
+        
+//      We need to clear that the bit, otherwise We will not get next return.
+//        if(value & OHCI_INTR_WDH) {
+              writel(value, &ohci->regs->intrstatus);
+              (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+//            debug("OHCI_INTR_WDH cleared intrstatus=%x value=%x \n", readl(&ohci->regs->intrstatus), value);
+//        }	
+
+#if 0	
+        if (value & OHCI_INTR_SO) {
+                debug("USB Schedule overrun");
+                writel (OHCI_INTR_SO, &ohci->regs->intrenable);
+                (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+        }
+#endif
+           
+
+	while (td_list_hc) {
+//		debug("td_list_hc = %x\n", td_list_hc);
+                td_list = dma_to_td (ohci, (void *)td_list_hc);
+
+                if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+                        urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+                        debug(" USB-error/status: %x : %x\n",
+                                        TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
+                        if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
+                                if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
+                                        td_list->ed->hwHeadP =
+                                                (urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+                                                                        (td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+                                        urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+                                } else
+                                        td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
+                        }
+                }
+
+                td_list->next_dl_td = td_rev;
+                td_rev = td_list;
+                td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
+        }
+        return td_list;
+}
+/*-------------------------------------------------------------------------*/
+/* td done list */
+
+void dl_done_list (ohci_t * ohci, ohci_td_t * td_list)
+{
+        ohci_td_t * td_list_next = NULL;
+        ed_t * ed;
+ //       int cc = 0;
+        struct urb * urb;
+        urb_priv_t * urb_priv;
+        u32 tdINFO; //, edHeadP, edTailP;
+
+//        unsigned long flags;
+
+        while (td_list) {
+                td_list_next = td_list->next_dl_td;
+
+                urb = td_list->urb;
+                urb_priv = urb->hcpriv;
+                tdINFO = le32_to_cpup (&td_list->hwINFO);
+
+                ed = td_list->ed;
+
+                dl_transfer_length(td_list);
+#if 0
+                /* error code of transfer */
+                cc = TD_CC_GET (tdINFO);
+                if (cc == TD_CC_STALL)
+                        usb_endpoint_halt(urb->dev,
+                                usb_pipeendpoint(urb->pipe),
+                                usb_pipeout(urb->pipe));
+
+                if (!(urb->transfer_flags & USB_DISABLE_SPD)
+                                && (cc == TD_DATAUNDERRUN))
+                        cc = TD_CC_NOERROR;
+
+                if (++(urb_priv->td_cnt) == urb_priv->length) {
+                        if ((ed->state & (ED_OPER | ED_UNLINK))
+                                        && (urb_priv->state != URB_DEL)) {
+                                urb->status = cc_to_error[cc];
+                                ohci_return_urb (ohci, urb);
+                        } 
+			else {
+                                dl_del_urb (urb);
+                        }
+                }
+
+                if (ed->state != ED_NEW) {
+                        edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+                        edTailP = le32_to_cpup (&ed->hwTailP);
+
+                        /* unlink eds if they are not busy */
+                        if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+                                ep_unlink (ohci, ed);
+                }
+#endif
+
+                td_list = td_list_next;
+        }
+}
+
+void ohci_wait_urb_done(struct urb *urb, int timeout) { // timeout usually ==10000 --> 10milisecond
+        //here need to according the urb or ed type judge the BLF and CLF, We may need one time out in it
+	// Or need to check intrstatus and see if the hcca->done_head has been filled.
+	// We need to clear that the bit, otherwise We will get next return.
+	uint32_t pipe = urb->pipe;
+	uint32_t value;
+	usbdev_t *usb_dev = urb->dev;
+	ohci_t *ohci = &_ohci_x[usb_dev->controller];
+	uint32_t type;
+	while(timeout>0) {
+#if 1
+		value = readl(&ohci->regs->intrstatus);
+		if(!(value & OHCI_INTR_WDH)) {
+			udelay(1);
+			timeout--;
+			continue;
+		} else {
+			break;
+		}
+#endif
+	}
+#if 1
+	while (timeout>0) {
+                type = usb_pipetype (pipe);
+                if(type ==PIPE_BULK) {
+                                if( (readl(&ohci->regs->cmdstatus) & OHCI_BLF) == 0) break;
+                } else if(type == PIPE_CONTROL) {
+                                if( (readl(&ohci->regs->cmdstatus) & OHCI_CLF) == 0) break;
+                }
+                udelay(1); // 
+                timeout--;
+	}
+#endif
+
+	
+}
+void ohci_urb_complete(struct urb *urb) {
+
+        ohci_t *ohci = &_ohci_x[urb->dev->controller];
+        // it will clear the done list. and urb's actual_length is updated
+        dl_done_list (ohci, dl_reverse_done_list (ohci));
+
+#if CONFIG_DEBUG_USB
+        urb_print (urb, "RET", usb_pipein (urb->pipe));
+#endif          
+        	
+        urb_free_priv(ohci, urb->hcpriv); // free the priv and td list
+
+}
+/*-------------------------------------------------------------------*/
+// it will 1. call usb_bulk_msg_x 
+// 	   2. call dl_list and find the data return
+int ohci_bulk_transfer( uchar devnum, uchar ep, unsigned int data_len, uchar *data) {
+	int actual_length;
+        uint32_t t = devnum;
+        uint32_t pipe = ((ep&0x80)? 0x80:0)|(t<<8)|(3<<30);
+        t = ep;
+        pipe |=(t&0xf)<<15;
+	
+	usb_bulk_msg_x(&usb_device[devnum], pipe, data, data_len, &actual_length, 10000, ohci_urb_complete);
+	
+	return actual_length;
+
+
+}
+// it will 1. Call usb_control_msg_x
+//	   2. call dl_done_list to get the data returned ----> should be packed in one usb_complete_t function 
+//		and assigned that to urb
+
+int ohci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short
+wLength, void *data){
+
+	uint32_t t = devnum;
+        uint32_t pipe = ((request_type&0x80)? 0x80:0)|(t<<8)|(2<<30);
+	return usb_control_msg_x(&usb_device[devnum], pipe, request, request_type, wValue, wIndex, data, wLength, 10000, ohci_urb_complete);
+	
+}               
+
+int ohc_reset(uchar controller)
+{
+
+        int timeout = 30;
+        int smm_timeout = 50; /* 0,5 sec */
+        
+        debug("Resetting OHCI\n");
+        ohci_regs = (ohci_regs_t *)hc_base[controller];
+        ohci_t *ohci = &_ohci_x[controller];
+
+#ifndef __hppa__
+        /* PA-RISC doesn't have SMM, but PDC might leave IR set */
+        if (readl (&ohci_regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+                writel (OHCI_OCR, &ohci_regs->cmdstatus); /* request ownership */
+                debug("USB HC TakeOver from SMM");
+                while (readl (&ohci_regs->control) & OHCI_CTRL_IR) {
+                        mdelay (10);
+                        if (--smm_timeout == 0) {
+                                printf("USB HC TakeOver failed!");
+                                return -1;
+                        }
+                }
+        }
+#endif
+
+        debug("USB HC reset_hc usb-%08x: ctrl = 0x%x ;",
+                hc_base[controller],
+                readl (&ohci_regs->control));
+
+        /* Reset USB (needed by some controllers) */
+        writel (0, &ohci_regs->control);
+
+        /* Force a state change from USBRESET to USBOPERATIONAL for ALi */
+        (void) readl (&ohci_regs->control);    /* PCI posting */
+        writel (ohci->hc_control = OHCI_USB_OPER, &ohci_regs->control);
+
+        /* HC Reset requires max 10 ms delay */
+        writel (OHCI_HCR,  &ohci_regs->cmdstatus);
+        while ((readl (&ohci_regs->cmdstatus) & OHCI_HCR) != 0) {
+                if (--timeout == 0) {
+                        printf("USB HC reset timed out!");
+                        return -1;
+                }
+                udelay (1);
+        }
+        return 0;
+}
+         
+
+int ohc_start(uchar controller) {
+ //       unsigned short tmp;
+	u32 mask;
+	unsigned int fminterval;
+	int delaytime;
+	ohci_regs = (ohci_regs_t *)hc_base[controller];
+	ohci_t *ohci = &_ohci_x[controller];
+	
+        debug("Starting OHCI\n");
+	
+        writel (0, &ohci_regs->ed_controlhead);
+        writel (0, &ohci_regs->ed_bulkhead);
+
+        writel ((uint32_t)ohci->hcca_dma, &ohci_regs->hcca); /* a reset clears this */ //3
+
+        fminterval = 0x2edf;	//6
+        writel ((fminterval * 9) / 10, &ohci_regs->periodicstart); // Don't worry, we can disable periodic in contol or let the ED list null
+        fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+        writel (fminterval, &ohci_regs->fminterval);
+        writel (0x628, &ohci_regs->lsthresh);
+
+        /* start controller operations */
+	
+	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+        writel (ohci->hc_control, &ohci_regs->control); // PIE and IE is disabled
+							// DO we need to enable that but leave all ISO ED and INT ED list null??? 
+
+        mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+        writel (mask, &ohci->regs->intrenable);
+        writel (mask, &ohci->regs->intrstatus);
+
+        /* required for AMD-756 and some Mac platforms */
+        writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, &ohci->regs->roothub.a);
+        writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+
+	(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+	
+        // POTPGT delay is bits 24-31, in 2 ms units.
+	delaytime = ((roothub_a (ohci) >> 23) & 0x1fe)*5/2; // for apacer 256 usb 2.0 + NEC 2.0 chip
+//	delaytime = ((roothub_a (ohci) >> 23) & 0x1fe);
+	
+        mdelay (delaytime);
+	
+//	printf("delaytime: %d\n", delaytime);
+	
+        return(0);
+}
+	
+
+int ohc_init(pcidev_t dev)
+{       
+        uint16_t word;
+	uint32_t dword;
+	ohci_t *ohci;
+	ed_t * ed;
+	int i,j, NDP;
+	int size;
+                
+        dword=pci_read_config32(dev, 0x10);  // it will be 4k range
+        hc_base[num_controllers] =  (uint32_t)phys_to_virt(dword);
+	ohci = &_ohci_x[num_controllers];
+        debug("ohc_init num_controllers=%d ohci=%x\n", num_controllers, (uint32_t)ohci);	
+	memset(ohci, 0, sizeof(ohci_t));
+	ohci->regs = (ohci_regs_t *)hc_base[num_controllers];
+	ohci_regs  = ohci->regs;
+
+        ohci->hcca = allot2(sizeof (struct ohci_hcca), 0xff); //1
+        if (!ohci->hcca) {
+		printf("ohc_init: hcca allocated no MEM\n");
+                return -ENOMEM;
+        }
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+	ohci->hcca_dma = (void *)virt_to_phys(ohci->hcca);
+
+	//init ed;
+	ohci->ed = allot2(sizeof(ed_t)*NUM_EDS,0xf);
+	if(ohci->ed==0) {
+		printf("ohci_init: ed allocate no MEM\n");
+	}
+//	debug("ohci->ed = %x\n", ohci->ed);
+	for(i=0; i<NUM_EDS;i++) {
+		ed = (ed_t *)&ohci->ed[i];
+		ed->dma = (void *)virt_to_phys(ed);
+//		debug("i=%d, ed dma = %x\n", i, (uint32_t)ed->dma);
+		ed->state = ED_NEW;
+	}
+
+//	init urb and urb_priv
+        ohci->urb = (struct urb *)allot2(sizeof(struct urb),0xff);
+        if (!ohci->urb) {
+                printf("ohci_init:  urb allocate failed");
+        }
+        memset(ohci->urb, 0, sizeof(urb_t));
+
+	
+        /* allocate the private part of the URB */
+	size = 4;
+        ohci->urb_priv = allot2 (sizeof (urb_priv_t) + size * sizeof (ohci_td_t *), 0xff);
+        if (ohci->urb_priv == 0) {
+                printf("ohci_init: urb_priv allocated no mem\n");
+        }
+        memset (ohci->urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (ohci_td_t *));
+
+        // set master
+        word=pci_read_config16(dev, 0x04);
+        word |= 0x04;
+        pci_write_config16(dev, 0x04, word);
+
+        
+        DPRINTF("Found OHCI at %08x\n", hc_base[num_controllers]);
+        ohc_reset(num_controllers);
+
+	/* Here should or move to ohc_start
+	1. Init HCCA
+	2. Init ED and TD ---> in submit_urb
+	3. Assign HCCA to ohci_regs->hcca  ---> in ohc_init
+	4. Set Intr to ohci_regs->intrenable  ---> disable that in ohc_init
+	5. enable all queue in ohci_regs->control ---> in ep_link and it is called by submit_urb
+	6. set peridicstart to 0.9 of frameinterval  ---> ohc_start
+	*/
+	
+//	writel( 0, &ohci_regs->intrenable);   // no interrupts! //4
+//	writel( 0xffffffff, &ohci_regs->intrdisable);
+
+        NDP = readl(&ohci->regs->roothub.a) & 0xff;
+        for(j=0;j<NDP;j++) {
+        	writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[j]);
+	}
+
+        /* FIXME this is a second HC reset; why?? */
+        writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
+        (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+        mdelay (10);	
+
+        ohc_start(num_controllers);
+
+        num_controllers++;
+
+#if  CONFIG_DEBUG_USB==1
+//        ohci_dump (ohci, 1);
+#endif
+
+//	debug("ohci->ed = %x\n", ohci->ed);
+        return(0);
+}
+int poll_o_root_hub(uint32_t port, uchar controller)
+{
+        uint32_t value;
+        int addr=0;
+        int i;
+        static uint32_t do_over=0;
+	uint8_t what;
+	ohci_t *ohci;
+
+        value = readl(port);
+	
+	debug("poll_o_root_hub1 v=%08x port = %x, controller = %d\n", value, port, controller);
+
+	if(value == 0xffffffff) return addr; // stupid port 
+
+        if((value & RH_PS_CSC) || do_over == port) {
+		debug("poll_o_root_hub2 v=%08x\t", value);
+                do_over=0;
+                if(value & RH_PS_CCS ) {     // if port connected
+			debug("poll_o_root_hub21 v=%08x\t", value);
+                        DPRINTF("Connection on port %04x\n", port);
+
+                        writel(value, port);
+                        for(i=0; i<40; i++) {
+                                udelay(10000+usec_offset);
+                                value = readl(port);
+                                if(value & RH_PS_CSC) {
+                                        writel(value, port);  //Clear Change bit
+                                        i=0;
+                                        DPRINTF("BOUNCE!\n");
+                                }
+                        }
+//	 	 	debug("poll_o_root_hub211 v=%08x\t", value);
+
+                        oport_wakeup(port);
+//                      DPRINTF("Wakup %04x\n", port);
+                
+//   		 	debug("poll_o_root_hub212 v=%08x\t", readl(port)); 
+                        oport_reset(port);
+//  		     	debug("poll_o_root_hub213 v=%08x\t", readl(port));
+                        mdelay(10);
+                        oport_enable(port);
+// 		        debug("poll_o_root_hub214 v=%08x\t", readl(port));
+                
+                        if(!(value & RH_PS_CCS)) {
+                                DPRINTF("Device went away!\n");
+                                return(-1);
+                        }
+			
+                        addr = configure_device( port, controller, value & RH_PS_LSDA);
+
+#if  CONFIG_DEBUG_USB==1     
+			// some one clear enable bit??? why??? It costs me one week to find it out. 
+                        ohci = &_ohci_x[controller];
+                        ohci_dump (ohci, 1);
+#endif
+
+#if 1
+//			usb_control_msg(addr, 0x21, 0xff, 0, 0, 0, NULL);// reset device
+//			mdelay(10);
+			usb_control_msg(addr, 0xa1, 0xfe, 0, 0, 1, &what); // get MAX L // get MAX LUN
+#endif
+
+//			debug("poll_o_root_hub215 v=%08x  addr = %d\n", readl(port), addr);
+
+                        if(addr<0) {
+                                oport_disable(port);
+                                udelay(20000);
+//                              oport_reset(port);
+                                oport_reset_long(port);
+                                oport_suspend(port);
+                                do_over=port;
+                                ohc_clear_stat(controller);
+
+                        }
+                } else {
+//			debug("poll_o_root_hub22 v=%08x\t", readl(port));
+                        oport_suspend(port);
+                        oport_disable(port);
+                        DPRINTF("Port %04x disconnected\n", port);
+                        // wave hands, deconfigure devices on this port!
+                }
+        }
+
+        return(addr);
+}
+
+
+

Added: trunk/filo/drivers/usb/ohci.h
===================================================================
--- trunk/filo/drivers/usb/ohci.h	                        (rev 0)
+++ trunk/filo/drivers/usb/ohci.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,312 @@
+#ifndef _OHCI_H
+#define _OHCI_H
+
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+// for OHCI
+
+/* ED States */
+
+#define ED_NEW          0x00
+#define ED_UNLINK       0x01
+#define ED_OPER         0x02
+#define ED_DEL          0x04
+#define ED_URB_DEL      0x08
+
+/* usb_ohci_ed */
+struct ed {
+        u32 hwINFO;       
+        u32 hwTailP;
+        u32 hwHeadP;
+        u32 hwNextED;
+
+        struct ed * ed_prev;  
+        u8 int_period;  // No  use just for aligned
+        u8 int_branch;  // No use just for aligned
+        u8 int_load;    // No uae just for aligned
+        u8 int_interval; // No use just for aligned
+        u8 state;
+        u8 type;
+        u16 last_iso; // no use just for aligned
+        struct ed * ed_rm_list;  // No use just for aligned
+
+        void * dma;         
+
+        u32 unused[3];        
+};
+// __attribute((aligned(16)));   
+typedef struct ed ed_t;
+
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO      0x00010000
+#define TD_DEL      0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+#define MAXPSW 1
+
+struct ohci_td {
+        u32 hwINFO;
+        u32 hwCBP;            /* Current Buffer Pointer */
+        u32 hwNextTD;         /* Next TD Pointer */
+        u32 hwBE;             /* Memory Buffer End Pointer */
+        u16 hwPSW[MAXPSW];
+        u8 unused;
+        u8 index;
+        struct ed * ed;
+        struct ohci_td * next_dl_td;
+        struct urb * urb;  //defined in usb.h
+        void * td_dma;
+        void * data_dma;
+        u32 unused2[2];
+}; 
+//__attribute((aligned(32)));   /* normally 16, iso needs 32 */
+typedef struct ohci_td ohci_td_t;
+
+#define OHCI_ED_SKIP    (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32     /* part of the OHCI standard */
+struct ohci_hcca {
+        u32   int_table[NUM_INTS];    /* Interrupt ED table */
+        u16   frame_no;               /* current frame number */
+        u16   pad1;                   /* set to 0 on each frame_no change */
+        u32   done_head;              /* info returned for an interrupt */
+        u8              reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+
+#define MAX_ROOT_PORTS 15
+
+struct ohci_regs {
+        /* control and status registers */
+        u32   revision;
+        u32   control;
+        u32   cmdstatus;
+        u32   intrstatus;
+        u32   intrenable;
+        u32   intrdisable;
+        /* memory pointers */
+        u32   hcca;
+        u32   ed_periodcurrent;
+        u32   ed_controlhead;
+        u32   ed_controlcurrent;
+        u32   ed_bulkhead;
+        u32   ed_bulkcurrent;
+        u32   donehead;
+        /* frame counters */
+        u32   fminterval;
+        u32   fmremaining;
+        u32   fmnumber;
+        u32   periodicstart;
+        u32   lsthresh;
+        /* Root hub ports */
+        struct  ohci_roothub_regs {
+                u32   a;
+                u32   b;
+                u32   status;
+                u32   portstatus[MAX_ROOT_PORTS];
+        } roothub;
+} __attribute((aligned(32))); 
+typedef struct ohci_regs ohci_regs_t;
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR  (3 << 0)        /* control/bulk service ratio */
+#define OHCI_CTRL_PLE   (1 << 2)        /* periodic list enable */
+#define OHCI_CTRL_IE    (1 << 3)        /* isochronous enable */
+#define OHCI_CTRL_CLE   (1 << 4)        /* control list enable */
+#define OHCI_CTRL_BLE   (1 << 5)        /* bulk list enable */
+#define OHCI_CTRL_HCFS  (3 << 6)        /* host controller functional state */
+#define OHCI_CTRL_IR    (1 << 8)        /* interrupt routing */
+#define OHCI_CTRL_RWC   (1 << 9)        /* remote wakeup connected */
+#define OHCI_CTRL_RWE   (1 << 10)       /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#       define OHCI_USB_RESET   (0 << 6)
+#       define OHCI_USB_RESUME  (1 << 6)
+#       define OHCI_USB_OPER    (2 << 6)
+#       define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR        (1 << 0)        /* host controller reset */
+#define OHCI_CLF        (1 << 1)        /* control list filled */
+#define OHCI_BLF        (1 << 2)        /* bulk list filled */
+#define OHCI_OCR        (1 << 3)        /* ownership change request */
+#define OHCI_SOC        (3 << 16)       /* scheduling overrun count */
+
+/*      
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */     
+#define OHCI_INTR_SO    (1 << 0)        /* scheduling overrun */
+#define OHCI_INTR_WDH   (1 << 1)        /* writeback of done_head */
+#define OHCI_INTR_SF    (1 << 2)        /* start frame */
+#define OHCI_INTR_RD    (1 << 3)        /* resume detect */
+#define OHCI_INTR_UE    (1 << 4)        /* unrecoverable error */
+#define OHCI_INTR_FNO   (1 << 5)        /* frame number overflow */
+#define OHCI_INTR_RHSC  (1 << 6)        /* root hub status change */
+#define OHCI_INTR_OC    (1 << 30)       /* ownership change */
+#define OHCI_INTR_MIE   (1 << 31)       /* master interrupt enable */
+
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+        (OHCI_CTRL_CBSR & 0x3) 
+//| OHCI_CTRL_IE | OHCI_CTRL_PLE   
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001         /* current connect status */
+#define RH_PS_PES            0x00000002         /* port enable status*/
+#define RH_PS_PSS            0x00000004         /* port suspend status */
+#define RH_PS_POCI           0x00000008         /* port over current indicator */
+#define RH_PS_PRS            0x00000010         /* port reset status */
+#define RH_PS_PPS            0x00000100         /* port power status */
+#define RH_PS_LSDA           0x00000200         /* low speed device attached */
+#define RH_PS_CSC            0x00010000         /* connect status change */
+#define RH_PS_PESC           0x00020000         /* port enable status change */
+#define RH_PS_PSSC           0x00040000         /* port suspend status change */
+#define RH_PS_OCIC           0x00080000         /* over current indicator change */
+#define RH_PS_PRSC           0x00100000         /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS            0x00000001         /* local power status */
+#define RH_HS_OCI            0x00000002         /* over current indicator */
+#define RH_HS_DRWE           0x00008000         /* device remote wakeup enable */
+#define RH_HS_LPSC           0x00010000         /* local power status change */
+#define RH_HS_OCIC           0x00020000         /* over current indicator change */
+#define RH_HS_CRWE           0x80000000         /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR         0x0000ffff              /* device removable flags */
+#define RH_B_PPCM       0xffff0000              /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP        (0xff << 0)             /* number of downstream ports */
+#define RH_A_PSM        (1 << 8)                /* power switching mode */
+#define RH_A_NPS        (1 << 9)                /* no power switching */
+#define RH_A_DT         (1 << 10)               /* device type (mbz) */
+#define RH_A_OCPM       (1 << 11)               /* over current protection mode */
+#define RH_A_NOCP       (1 << 12)               /* no over current protection */
+#define RH_A_POTPGT     (0xff << 24)            /* power on to power good time */
+
+typedef struct
+{
+        ed_t * ed;
+        u16 length;   // number of tds associated with this request
+        u16 td_cnt;   // number of tds already serviced
+        int   state;
+#if 0
+        wait_queue_head_t * wait;
+#endif
+        ohci_td_t * td[0];   // list pointer to all corresponding TDs associated with this request
+
+} urb_priv_t;
+
+#define NUM_EDS 32              /* num of preallocated endpoint descriptors */
+
+typedef struct ohci {
+        struct ohci_hcca *hcca;         /* hcca */
+        void * hcca_dma;
+	
+        ohci_regs_t * regs;        /* OHCI controller's memory */
+        
+	ed_t * ed_bulktail;       /* last endpoint of bulk list */
+        ed_t * ed_controltail;    /* last endpoint of control list */
+
+        int intrstatus;
+        u32 hc_control;               /* copy of the hc control reg */
+
+	uint32_t ed_cnt;
+	ed_t   *ed;	// Allocate that from ed_buffer in ohc_init
+	usbdev_t *dev[NUM_EDS];
+	urb_t *urb; // one ohci one urb
+	urb_priv_t *urb_priv;
+	struct usb_ctrlrequest *dr; 
+} ohci_t;
+
+
+extern ohci_t _ohci_x[MAX_CONTROLLERS];
+
+#define usb_to_ohci(usb_dev) (&_ohci_x[(usb_dev)->controller])
+
+extern ohci_regs_t *ohci_regs;
+
+void clear_oport_stat(uint32_t port);
+//int ohc_init(struct pci_dev *dev);
+int poll_o_root_hub(uint32_t port, uchar controller);
+
+int ohci_bulk_transfer( uchar devnum, uchar ep, unsigned int data_len, uchar *data);
+int ohci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short
+	wLength, void *data);
+void ohci_wait_urb_done(struct urb *urb, int timeout);
+
+void ohci_init(void);
+int ohc_init(pcidev_t dev);
+int ohci_submit_urb (struct urb * urb);
+#endif

Added: trunk/filo/drivers/usb/scsi.h
===================================================================
--- trunk/filo/drivers/usb/scsi.h	                        (rev 0)
+++ trunk/filo/drivers/usb/scsi.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,226 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/*
+ * This header file contains public constants and structures used by
+ * the scsi code for linux.
+ */
+
+#ifndef _SCSI_SCSI_H
+#define _SCSI_SCSI_H	1
+
+//#include <features.h>
+
+/*
+ *      SCSI opcodes
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define READ_TOC              0x43
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define RESERVE_10            0x56
+#define RELEASE_10            0x57
+#define MODE_SENSE_10         0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define MOVE_MEDIUM           0xa5
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define READ_ELEMENT_STATUS   0xb8
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
+
+/*
+ *  Status codes
+ */
+
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define COMMAND_TERMINATED   0x11
+#define QUEUE_FULL           0x14
+
+#define STATUS_MASK          0x3e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/*
+ *  DEVICE TYPES
+ */
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk -
+				     * - treated as TYPE_DISK */
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_ENCLOSURE	    0x0d    /* Enclosure Services Device */
+#define TYPE_NO_LUN         0x7f
+
+/*
+ * standard mode-select header prepended to all mode-select commands
+ *
+ * moved here from cdrom.h -- kraxel
+ */
+
+struct ccs_modesel_head
+  {
+    unsigned char _r1;			/* reserved.  */
+    unsigned char medium;		/* device-specific medium type.  */
+    unsigned char _r2;			/* reserved.  */
+    unsigned char block_desc_length;	/* block descriptor length.  */
+    unsigned char density;		/* device-specific density code.  */
+    unsigned char number_blocks_hi;	/* number of blocks in this block
+					   desc.  */
+    unsigned char number_blocks_med;
+    unsigned char number_blocks_lo;
+    unsigned char _r3;
+    unsigned char block_length_hi;	/* block length for blocks in this
+					   desc.  */
+    unsigned char block_length_med;
+    unsigned char block_length_lo;
+  };
+
+/*
+ *  MESSAGE CODES
+ */
+
+#define COMMAND_COMPLETE    0x00
+#define EXTENDED_MESSAGE    0x01
+#define     EXTENDED_MODIFY_DATA_POINTER    0x00
+#define     EXTENDED_SDTR                   0x01
+#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
+#define     EXTENDED_WDTR                   0x03
+#define SAVE_POINTERS       0x02
+#define RESTORE_POINTERS    0x03
+#define DISCONNECT          0x04
+#define INITIATOR_ERROR     0x05
+#define ABORT               0x06
+#define MESSAGE_REJECT      0x07
+#define NOP                 0x08
+#define MSG_PARITY_ERROR    0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET    0x0c
+
+#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
+#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
+
+#define SIMPLE_QUEUE_TAG    0x20
+#define HEAD_OF_QUEUE_TAG   0x21
+#define ORDERED_QUEUE_TAG   0x22
+
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ */
+/* These are a few other constants only used by scsi devices.  */
+
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/* Used to turn on and off tagged queuing for scsi devices.  */
+
+#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
+#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
+
+/* Used to obtain the host number of a device.  */
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+
+/* Used to get the bus number for a device.  */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
+
+#endif /* scsi/scsi.h */

Added: trunk/filo/drivers/usb/scsi_cmds.c
===================================================================
--- trunk/filo/drivers/usb/scsi_cmds.c	                        (rev 0)
+++ trunk/filo/drivers/usb/scsi_cmds.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,508 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <arch/byteorder.h> 
+
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+
+#define DPRINTF debug
+
+
+#include "scsi.h"
+
+
+#include "usb_scsi_low.h"
+
+#ifndef NULL
+#define NULL (void *) 0x0
+#endif
+
+#include "scsi_cmds.h"
+
+devhandle sgh;
+
+typedef struct sense_data {
+	uchar code;
+	
+	uchar sense_key:4;
+	uchar res1:4;
+
+	uchar additional_code;
+	uchar qualifier;
+
+	uchar res2[3];
+
+	uchar length;
+} __attribute__ ((packed)) sense_data_t;
+
+typedef struct fixed_sense_data {
+	uchar code:7;
+	uchar valid:1;
+
+	uchar obs1;
+
+	uchar sense_key:4;
+	uchar res1:1;
+	uchar ili:1;
+	uchar eom:1;
+	uchar mark:1;
+
+	unsigned int  info;
+
+	uchar add_len;
+} __attribute__ ((packed)) fixed_sense_data_t;
+
+typedef struct additional_fixed_data {
+	unsigned int info;
+	
+	uchar code;
+	uchar qualifier;
+	uchar fru;
+
+	uchar specific[3];
+} __attribute__ ((packed)) additional_fixed_data_t;
+	
+
+void PrintSense(uchar *sense, int len)
+{
+	int i;
+
+	DPRINTF( "sense data ");
+	for(i=0;i<len; i++) {
+		DPRINTF(  ":%02x", sense[i]);
+	}
+	DPRINTF("\n\n");
+
+	if( (sense[0] & 0x7f) >=0x72) {
+		sense_data_t *sd = (sense_data_t *) sense;
+		uchar *pos = sense+sizeof(sense_data_t);
+		uchar remaining = sd->length;
+		int dlen;
+		
+		DPRINTF("code = %02x, key = %1x, additional = %02x, qual = %02x\n", sd->code, sd->sense_key, sd->additional_code, sd->qualifier);
+
+		while(remaining) {
+			DPRINTF("type = %02x", pos[0]);
+			dlen = pos[1];
+			pos+=2;
+			remaining -=2;
+
+			for(i=0; i<dlen; i++) 
+				DPRINTF( ": %02x", pos[i]);
+
+			DPRINTF("\n");
+			pos+=i;
+			remaining -=i;
+		}
+
+	} else {
+		fixed_sense_data_t *fd = (fixed_sense_data_t *) sense;
+		uchar remaining = fd->add_len;
+		additional_fixed_data_t *afd;
+
+		
+		DPRINTF("code = %02x key = %1x\n", fd->code, fd->sense_key);
+		if(fd->mark) {
+			DPRINTF("filemark ");
+		}
+
+		if(fd->eom) {
+			DPRINTF(" End Of Media ");
+		}
+
+		if(fd->ili) {
+			DPRINTF("Illegal instruction");
+		}
+
+		DPRINTF("\n");
+
+		if(fd->valid) {
+			DPRINTF( "(valid) ");
+		}
+
+		DPRINTF( "Info: %08x\n", ntohl(fd->info));
+
+		afd = (additional_fixed_data_t *) (sense + 8);
+
+//		while(remaining) {
+		if(remaining) {
+			DPRINTF("command info = %08x\n", ntohl(afd->info));
+			DPRINTF("code = %02x, qual = %02x, fru = %02x\n", afd->code, afd->qualifier, afd->fru);
+			DPRINTF("sense key data = %02x:%02x:%02x\n\n", afd->specific[2], afd->specific[1], afd->specific[0]);
+
+			afd++;
+			remaining -= sizeof(additional_fixed_data_t);
+		}
+	}
+		
+}
+	
+typedef struct query_response {
+	uchar type:5;
+	uchar qualifier:3;
+
+	uchar reserved1:7;
+	uchar removable:1;
+
+	uchar version;
+
+	uchar ResponseDataFormat:4;	// should == 2
+	uchar HiSup:1;			// report luns cmd supported
+	uchar NormACA:1;
+	uchar obsolete:1;
+	uchar aerc:1;
+
+	uchar AdditionalLength;		// length of vendor specific data (beyond 96 bytes)
+
+	uchar reserved2:7;
+	uchar sccs:1;			// have raid controller
+
+	uchar addr16:1;			// 
+	uchar obsolete2:2;
+	uchar MChnger:1;		// media changer
+	uchar MultiP:1;			// multi port
+	uchar vs:1;			// ???
+	uchar EncServ:1;		// enclosure service
+	uchar BQue:1;			// basic command queueing
+
+	uchar vs2:1;
+	uchar CmdQue:1;			// full command queueing
+	uchar obsolete4:1;
+	uchar linked:1;
+	uchar sync:1;
+	uchar wbus16:1;			//
+	uchar obsolete3:1;
+	uchar RelAddr:1;		// treletive addressing
+
+	char vendor[8];
+	char product[16];
+	char revision[4];
+	char vendor_data[20];
+
+	uchar ius:1;
+	uchar qas:1;
+	uchar clocking:2;		// 
+	uchar reserved3:4;
+
+	unsigned short version_desc[8];
+
+	char reserved4[21];
+} query_response_t;
+
+typedef struct ReadBlockCMD {
+	uchar cmd;
+
+	uchar reladdr:1;
+	uchar reserved:2;
+	uchar fua:1;		// force unit access flush to media
+	uchar dpo:1;		// direct page out, do not cache
+	uchar reserved2:3;
+
+	unsigned int block_address;
+	uchar reserved3;
+	
+	unsigned short block_count;
+
+	uchar control;
+} __attribute__ ((packed)) ReadBlockCMD_t ;
+
+int ll_read_block(devhandle sgd, unsigned char *buffer, int blocknum, int count)
+{
+	int ret;
+	ReadBlockCMD_t rb;
+	unsigned char sensedat[32];
+
+	memset(&rb,0,sizeof(rb));
+	rb.cmd = READ_10;
+	rb.block_address = htonl(blocknum);
+	rb.block_count = htons(count);
+	
+	ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_FROM_DEV,  buffer, count * 512, sensedat, sizeof(sensedat));
+
+	if(ret<0) {
+		DPRINTF("ERROR: ll_read_block( %x, %x, %x, %x) = %d\n", sgd, buffer, blocknum, count, ret);
+		PrintSense(sensedat, 32);
+	}
+
+	return(ret);
+
+}
+
+int ll_write_block(devhandle sgd, unsigned char *buffer, int blocknum, int count)
+{
+	int ret;
+	ReadBlockCMD_t rb;
+	unsigned char sensedat[32];
+
+	memset(&rb,0,sizeof(rb));
+	rb.cmd = WRITE_10;
+	rb.block_address = htonl(blocknum);
+	rb.block_count = htons(count);
+	
+	ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_TO_DEV,  buffer, count * 512, sensedat, sizeof(sensedat));
+
+	return(ret);
+}
+
+typedef struct ReadLongCMD {
+	uchar cmd;
+
+	uchar reladdr:1;
+	uchar correct:1;
+	uchar reserved:5;
+
+	unsigned int block_address;
+	uchar reserved3;
+	
+	unsigned short length;
+
+	uchar control;
+} __attribute__ ((packed)) ReadLongCMD_t ;
+
+int ll_read_long(devhandle sgd, unsigned char *buffer, int blocknum, int size)
+{
+	int ret;
+	ReadLongCMD_t rb;
+	unsigned char sensedat[32];
+
+	memset(&rb,0,sizeof(rb));
+	rb.cmd = READ_LONG;
+	rb.block_address = htonl(blocknum);
+	rb.length = htons(size);
+	
+	ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_FROM_DEV,  buffer, size, sensedat, sizeof(sensedat));
+	return(ret);
+}
+
+unsigned char ReadCapacityCMD[10] = { READ_CAPACITY, 0, 0,0,0,0, 0,0,0, 0};
+
+struct ReadCapacityResponse {
+	unsigned int block_address;
+	unsigned int block_length;
+};
+
+int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len)
+{
+	int ret;
+	struct ReadCapacityResponse response;
+	unsigned char sensedat[32];
+
+	ret = scsi_command(sgd, ReadCapacityCMD, sizeof(ReadCapacityCMD), SG_DXFER_FROM_DEV, (uint8_t *)&response, sizeof(response), sensedat, sizeof(sensedat) );
+	if(ret<0) {
+		DPRINTF("ERROR:get capacity: %d\n", ret);
+		PrintSense(sensedat,32);
+	}
+
+
+	*block_count = ntohl(response.block_address) +1;
+	*blk_len = ntohl(response.block_length);
+
+	return(ret);
+}
+
+#define INQ_REP_LEN 96
+unsigned char InquiryCMD[6] = { INQUIRY, 0, 0, 0, INQ_REP_LEN, 0};
+
+int query(devhandle sgd, query_response_t *qr)
+{
+	int ret;
+	unsigned char sensedat[32];
+
+	ret = scsi_command(sgd, InquiryCMD, sizeof(InquiryCMD), SG_DXFER_FROM_DEV, (uint8_t *)qr, sizeof(query_response_t), sensedat, sizeof(sensedat) );
+
+	if(ret<0){
+		DPRINTF("query: IOCTL");
+	}
+
+	return(ret);
+}
+
+typedef struct lun_list {
+	unsigned int list_length;
+	unsigned int reserved;
+	unsigned long long lun[16];
+} lun_list_t;
+
+#define REPORT_LUNS 0xa0
+unsigned char ReportLunsCMD[12] = { REPORT_LUNS, 0, 2, 0, 0, 0, 0, 0, 0, 128, 0, 0 };
+
+int ReportLUNS(devhandle sgd, lun_list_t *list)
+{
+	int ret;
+	unsigned char sensedat[32];
+
+	memset (list, 0, sizeof(lun_list_t));
+	ret = scsi_command(sgd, ReportLunsCMD, sizeof(ReportLunsCMD), SG_DXFER_FROM_DEV, (uint8_t *)list, sizeof(lun_list_t), sensedat, sizeof(sensedat) );
+
+	if(ret<0) {
+		DPRINTF("Report Luns: IOCTL");
+	}
+
+	list->list_length = ntohl(list->list_length);
+
+	return(ret);
+}
+
+typedef struct command_descriptor {
+	uchar opcode;
+	uchar reserved;
+	unsigned short service_action;
+	uchar reserved2;
+
+	uchar action_valid:1;
+	uchar reserved3:7;
+
+	unsigned short cdb_len;
+} __attribute__ ((packed)) command_descriptor_t;
+
+typedef struct report_opcodes_result {
+	unsigned long length;
+
+	command_descriptor_t command[256];
+} __attribute__ ((packed)) report_opcode_result_t;
+
+
+#define REPORT_OPCODES 0xa3
+
+typedef struct report_opcodes_cmd {
+	uchar cmd;
+	uchar reserved[5];
+	unsigned int reply_len;
+	uchar reserved2;
+	uchar control;
+} __attribute__ ((packed)) ReportOpcodesCMD_t;
+
+//ReportOpcodesCMD_t ReportOpcodesCMD = { cmd : REPORT_OPCODES, reply_len: htonl(sizeof(report_opcode_result_t)) };
+
+int ReportOpCodes(devhandle sgd, report_opcode_result_t *list)
+{
+	int ret;
+	unsigned char sensedat[32];
+	ReportOpcodesCMD_t ReportOpcodesCMD;
+
+	memset (list, 0, sizeof(report_opcode_result_t));
+	ReportOpcodesCMD.cmd = REPORT_OPCODES;
+	ReportOpcodesCMD.reply_len = htonl( sizeof(report_opcode_result_t));
+
+	ret = scsi_command(sgd, (uint8_t *)&ReportOpcodesCMD, sizeof(ReportOpcodesCMD_t), SG_DXFER_FROM_DEV, (uint8_t *)list, sizeof(report_opcode_result_t), sensedat, sizeof(sensedat) );
+
+	if(ret<0) {
+		DPRINTF("Report Luns: IOCTL");
+	}
+
+	list->length = ntohl(list->length);
+
+	return(ret);
+}
+
+
+#define READ_ATTRIBUTE 0x8c
+#define VOLUME_LIST 2
+#define PARTITION_LIST 3
+
+typedef struct read_attribute_cmd {
+	uchar cmd;
+	
+	uchar action:5;
+	uchar res:3;
+
+	uchar restricted[3];
+
+	uchar volume;
+	uchar res2;
+	uchar partition;
+
+	ushort attribute;
+	unsigned int reply_len;
+	uchar res3;
+	uchar control;
+} __attribute__ ((packed)) ReadAttributeCMD_t;
+
+int CheckVolumes(devhandle sgd)
+{
+	int ret;
+	uchar reply[4];
+	uchar sensedat[32];
+	ReadAttributeCMD_t cmd;
+
+	memset(&cmd,0,sizeof(cmd));
+
+	cmd.cmd=READ_ATTRIBUTE;
+	cmd.action = VOLUME_LIST;
+	cmd.reply_len = htonl(4);
+
+	ret = scsi_command(sgd, (uint8_t *)&cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
+	if(ret<0) {
+		DPRINTF("Report Volumes: IOCTL");
+		return(-1);
+	}
+
+	if(! reply[0] && !reply[1])
+		return(0);
+
+	return(reply[3]);
+}
+
+int CheckPartitions(devhandle sgd)
+{
+	int ret;
+	uchar reply[4];
+	uchar sensedat[32];
+	ReadAttributeCMD_t cmd;
+
+	memset(&cmd,0,sizeof(cmd));
+
+	cmd.cmd=READ_ATTRIBUTE;
+	cmd.action = PARTITION_LIST;
+	cmd.reply_len = htonl(4);
+
+	ret = scsi_command(sgd, (uint8_t *)&cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
+	if(ret<0) {
+		DPRINTF("Report PARTITIONVolumes: IOCTL");
+		return(-1);
+	}
+
+	if(! reply[0] && !reply[1])
+		return(0);
+
+	return(reply[3]);
+}
+
+int UnitReady(devhandle sgd)
+{
+	uchar cmd[6];
+	uchar sensedat[32];
+	int ret;
+
+	memset(cmd,0,sizeof(cmd));
+	
+	ret = scsi_command(sgd, (uint8_t *)&cmd, sizeof(cmd), SG_DXFER_FROM_DEV, NULL, 0, sensedat, sizeof(sensedat) );
+	if(ret<0) {
+		DPRINTF("UnitReady :");
+		return(0);
+	}
+
+	return(1);
+}
+

Added: trunk/filo/drivers/usb/scsi_cmds.h
===================================================================
--- trunk/filo/drivers/usb/scsi_cmds.h	                        (rev 0)
+++ trunk/filo/drivers/usb/scsi_cmds.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,14 @@
+#ifndef _SCSI_CMDS_H
+#define _SCSI_CMDS_H
+
+#define devhandle uint8_t
+
+#define uchar uint8_t
+#define ushort uint16_t
+
+void PrintSense(uchar *sense, int len);
+int ll_read_block(devhandle sgd, unsigned char *buffer, int blocknum, int count);
+
+int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len);
+int UnitReady(uchar sgd);
+#endif

Added: trunk/filo/drivers/usb/uhci.c
===================================================================
--- trunk/filo/drivers/usb/uhci.c	                        (rev 0)
+++ trunk/filo/drivers/usb/uhci.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1134 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+#define DPRINTF debug
+#include "usb.h"
+#include "uhci.h"
+#include "debug_x.h"
+
+#define ALLOCATE 1
+
+extern int usec_offset;
+
+int wait_head( queue_head_t *head, int count)
+{
+	td_t *td;
+
+
+	while(!head->depth.terminate) {
+		td = MEM_ADDR(head->depth.link);
+		if(!td->active)
+			return(-1);	// queue failed
+
+		if(count)
+			if(! --count)
+				return(0);	// still active
+				
+		udelay(500);	// give it some time
+	}
+
+	return(1);	// success
+}
+
+queue_head_t *free_qh;
+queue_head_t _queue_heads[MAX_QUEUEHEAD];
+queue_head_t *queue_heads = _queue_heads;
+
+queue_head_t *new_queue_head(void)
+{
+	queue_head_t *qh;
+
+	if(!free_qh)
+		return(NULL);
+
+	qh = free_qh;
+	free_qh = MEM_ADDR(qh->bredth.link);
+
+	memset(qh,0,sizeof(queue_head_t));
+	qh->bredth.terminate = qh->depth.terminate=1;
+
+	return(qh);
+}
+
+void free_queue_head( queue_head_t *qh)
+{
+
+	qh->bredth.link = LINK_ADDR(free_qh);
+	if(!free_qh)
+		qh->bredth.terminate=1;
+
+	qh->depth.terminate=1;
+	free_qh = qh;
+}
+
+void init_qh(void)
+{
+	int i;
+
+	for(i=0; i<MAX_QUEUEHEAD-1; i++) {
+		memset(queue_heads+i, 0, sizeof(queue_head_t));
+		queue_heads[i].bredth.link = LINK_ADDR( &queue_heads[i+1] );
+		queue_heads[i].depth.terminate=1;
+	}
+
+	queue_heads[MAX_QUEUEHEAD-1].depth.terminate=1;
+	queue_heads[MAX_QUEUEHEAD-1].bredth.terminate=1;
+
+	free_qh = queue_heads;
+}
+
+td_t *free_td_list;
+td_t _tds[MAX_TD];
+td_t *tds = _tds;	// indirection added for kernel testing
+
+
+void init_td(void)
+{
+	int i;
+
+	for(i=0; i<MAX_TD-1; i++) {
+		memset(tds+i, 0, sizeof(td_t));
+		tds[i].link.link = LINK_ADDR( &tds[i+1]);
+	}
+
+	memset( &tds[MAX_TD-1], 0, sizeof(td_t));
+	tds[MAX_TD-1].link.terminate=1;
+
+	free_td_list = tds;
+}
+
+td_t *new_td(void)
+{
+	td_t *td;
+
+	if(!free_td_list)
+		return(NULL);
+
+//	DPRINTF("new_td: free_td = %p\n", free_td_list);
+	td = free_td_list;
+
+	free_td_list = MEM_ADDR( td->link.link);
+//	DPRINTF("new_td: free_td_list = %p\n", free_td_list);
+
+	memset(td, 0, sizeof(td_t));
+	td->link.terminate=1;
+
+//	DPRINTF("new_td: returning %p\n", td);
+	return(td);
+}
+
+td_t *find_last_td(td_t *td)
+{
+	td_t *last;
+
+	last = td;
+
+	while(!last->link.terminate)
+		last = MEM_ADDR(last->link.link);
+
+	return(last);
+}
+
+void free_td( td_t *td)
+{
+	td_t *last_td;
+
+	last_td = find_last_td(td);
+
+	last_td->link.link = LINK_ADDR(free_td_list);
+	if(!free_td_list) 
+		last_td->link.terminate=1;
+	else
+		last_td->link.terminate=0;
+
+	free_td_list = td;
+	
+}
+
+link_pointer_t *queue_end( queue_head_t *queue)
+{
+	link_pointer_t *link;
+
+	link = &(queue->depth);
+
+	while(!link->terminate)
+		link = MEM_ADDR(link->link);
+
+	return(link);
+}
+
+void add_td( queue_head_t *head, td_t *td)
+{
+	link_pointer_t *link;
+
+	link = queue_end(head);
+
+	link->link = LINK_ADDR(td);
+	link->terminate=0;
+}
+
+transaction_t transactions[MAX_TRANSACTIONS];
+transaction_t *free_transactions;
+
+void init_transactions(void)
+{
+	int i;
+
+	memset(transactions, 0, sizeof(transactions));
+
+	for(i=0; i<MAX_TRANSACTIONS-1; i++)
+		transactions[i].next = &transactions[i+1];
+
+	free_transactions = transactions;
+}
+
+void free_transaction( transaction_t *trans )
+{
+	transaction_t *my_current, *last;
+
+	my_current = trans;
+
+	if(my_current==0) return;
+	
+	while(my_current) {
+		free_td( my_current->td_list );
+		free_queue_head( my_current->qh );
+
+		last = my_current;
+		my_current = my_current->next;
+	}
+	
+	last->next = free_transactions;
+	free_transactions = trans;
+}
+
+transaction_t *new_transaction(td_t *td)
+{
+	transaction_t *trans = free_transactions;
+	queue_head_t *qh;
+
+	if(!trans) {
+		DPRINTF("new_transaction( td = %x) failed!\n", td);
+		return(NULL);
+	}
+
+	free_transactions = trans->next;
+
+	memset(trans, 0, sizeof(transaction_t));
+
+	if(td) {
+		qh = new_queue_head();
+		if(!qh) {
+			free_transaction(trans);
+			return(NULL);
+		}
+
+		trans->qh = qh;
+		trans->td_list = td;
+		qh->depth.link = LINK_ADDR(td);
+		qh->depth.terminate = 0;
+		qh->bredth.terminate=1;
+	}
+
+	return(trans);
+}
+
+transaction_t *add_transaction( transaction_t *trans, td_t *td)
+{
+	transaction_t *t1;
+
+
+	t1 = new_transaction(td);
+	if(!t1)
+		return(NULL);
+
+	trans->next = t1;
+	trans->qh->bredth.terminate=0;
+	trans->qh->bredth.link = LINK_ADDR(t1->qh);
+	trans->qh->bredth.queue=1;
+
+	return(trans);
+}
+
+link_pointer_t *frame_list[MAX_CONTROLLERS];
+#if 0
+uchar fl_buffer[MAX_CONTROLLERS][8192];
+#endif
+
+void init_framelist(uchar dev)
+{
+
+	int i;
+#if 0
+	DPRINTF("raw frame_list is at %x\n", fl_buffer[dev]);
+	frame_list[dev] = (link_pointer_t *) ((bus_to_virt)(((unsigned int)virt_to_bus(fl_buffer[dev]) & ~0xfff) + 0x1000));
+#else 
+	frame_list[dev] = (link_pointer_t *) allot2(sizeof(link_pointer_t)*1024, 0xfff);  // 4K alignment
+	if(frame_list[dev]==0) {
+		printf("init_framelist: no mem\n");
+	}
+#endif
+	memset(frame_list[dev], 0, 1024 * sizeof(link_pointer_t));
+
+
+	DPRINTF("frame_list is at %x\n", frame_list[dev]);
+
+	for(i=0;i<1024;i++)
+		frame_list[dev][i].terminate=1;
+
+}
+
+
+extern int num_controllers;
+
+extern uint32_t hc_base[MAX_CONTROLLERS];
+extern uint8_t  hc_type[MAX_CONTROLLERS];
+
+void uhc_clear_stat()
+{
+	unsigned short value;
+
+	value = inw(USBSTS(0));
+	outw(value, USBSTS(0));
+}
+
+void clear_uport_stat(unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	outw(value, port);
+}
+
+void uport_suspend( unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	value |= 0x1000;
+	outw( value, port);
+
+}
+
+void uport_wakeup( unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	value &= ~0x1000;
+	outw( value, port);
+
+}
+
+#if 0
+void uport_resume( unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	value |= 0x40;
+	outw(value, port);
+	udelay(20000+usec_offset);
+	value &= ~0x40;
+	outw(value, port);
+
+	do {
+		value = inw(port);
+	} while(value & 0x40);
+}
+
+#endif
+void uport_enable( unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	value |= 0x04;
+	outw( value, port);
+
+	do {
+		value = inw(port);
+	} while( !(value & 0x04) && (value & 0x01));
+
+}
+
+
+void uport_disable( unsigned short port)
+{
+	unsigned short value;
+
+	value = inw(port);
+	value &= ~0x04;
+	outw( value, port);
+}
+
+void uport_reset(unsigned short port)
+{
+	unsigned short value;
+	int i;
+
+	value = inw(port);
+	value |= 0x200;
+
+	outw( value, port);
+
+	for(i=0;i<5;i++)
+		udelay(10000+usec_offset);
+
+	value &= ~0x200;
+	outw( value, port);
+
+//	DPRINTF("Port %04x reset\n", port);
+}
+
+void uport_reset_long(unsigned short port)
+{
+	unsigned short value;
+	int i;
+
+	value = inw(port);
+	value |= 0x200;
+	outw( value, port);
+
+	for(i=0; i<20; i++)
+		udelay(10000);
+
+	value &= ~0x200;
+	outw( value, port);
+
+//	DPRINTF("Port %04x reset\n", port);
+}
+
+void uhc_reset(uchar controller)
+{
+	DPRINTF("Resetting UHCI\n");
+	outw(0x04, USBCMD(controller));
+	udelay(20000);
+	outw(0, USBCMD(controller));
+}
+#if 0
+int uhc_stop(uchar dev)
+{
+	unsigned short tmp;
+
+	tmp = inw(USBCMD(dev));
+	tmp &= ~USBCMDRUN;
+	outw( tmp, USBCMD(dev));
+
+	while(! (inw(USBSTS(dev)) & USBSTSHALTED) );
+	outw( USBSTSHALTED, USBSTS(dev));	// clear the status
+
+	return(0);
+}
+
+#endif
+
+int uhc_start(uchar dev) {
+	unsigned short tmp;
+
+	DPRINTF("Starting UHCI\n");
+
+	tmp = inw(USBCMD(dev));
+	tmp |= USBCMDRUN;
+
+//	tmp |= USBCMD_DEBUG;
+	outw( tmp, USBCMD(dev));
+
+	return(0);
+}
+
+int uhc_init(pcidev_t dev)
+{
+	int16_t word;
+
+
+	word=pci_read_config16(dev, 0x20);
+	hc_base[num_controllers] = word;
+	hc_base[num_controllers] &= ~1;
+
+	DPRINTF("Found UHCI at %04x\n", hc_base[num_controllers]);
+	uhc_reset(num_controllers);
+
+	// set master
+	word=pci_read_config16(dev, 0x04);
+	word |= 0x04;
+	pci_write_config16(dev, 0x04, word);
+
+#if 0
+	if( ((unsigned int) virt_to_bus(frame_list[num_controllers])) != ( ( (unsigned int)virt_to_bus(frame_list[num_controllers])) & ~0x7ff) ) {
+		DPRINTF("UHCI: grave error, misaligned framelist (%x)\n", frame_list[num_controllers]);
+		return(-1);
+	}
+#endif
+
+	DPRINTF("uhc_init setting framelist to: %08x\n", (unsigned int) virt_to_bus( (frame_list[num_controllers]) ));
+	outl( (unsigned int) virt_to_bus(frame_list[num_controllers]), FLBASE(num_controllers));
+	outw( 0, FRNUM(num_controllers));
+	outw( 0, USBINTR(num_controllers));	// no interrupts!
+
+	outw(0x1000, PORTSC1(num_controllers));
+	outw(0x1000, PORTSC2(num_controllers));
+
+	uhc_start(num_controllers);
+
+	dump_uhci(hc_base[num_controllers]);
+
+	num_controllers++;
+	return(0);
+}
+
+queue_head_t *sched_queue[MAX_CONTROLLERS];
+queue_head_t *term_qh[MAX_CONTROLLERS];
+//td_t *dummy_td[MAX_CONTROLLERS];
+td_t *loop_td[MAX_CONTROLLERS];
+
+void init_sched(uchar dev)
+{
+	int i;
+
+//	dummy_td[dev] = new_td();
+	loop_td[dev] = new_td();
+	term_qh[dev] = new_queue_head();
+
+	sched_queue[dev] = new_queue_head();
+	sched_queue[dev]->bredth.terminate=0;
+	sched_queue[dev]->bredth.queue=1;
+	sched_queue[dev]->bredth.link=LINK_ADDR(term_qh[dev]);
+	sched_queue[dev]->depth.terminate=1;
+
+	term_qh[dev]->bredth.terminate=1;
+	term_qh[dev]->depth.link = LINK_ADDR(loop_td[dev]);
+	term_qh[dev]->depth.terminate=0;
+
+//	dummy_td->link.link = LINK_ADDR(sched_queue);
+//	dummy_td->link.queue = 1;
+//	dummy_td->link.depth=1;
+//	dummy_td->link.terminate=0;
+//	dummy_td->packet_type = IN_TOKEN;
+//	dummy_td->max_transfer = 0x7;
+//	dummy_td->isochronous=1;
+//	dummy_td->active=1;
+//	dummy_td->device_addr = 0x7f;
+//	dummy_td->endpoint=0x01;
+//	dummy_td->buffer = virt_to_bus(&dummy_td->data[2]);
+//	dummy_td->retrys=3;
+
+//dump_hex( (uchar *) dummy_td, sizeof(td_t), "dummy_td ");
+
+	loop_td[dev]->link.link = LINK_ADDR(loop_td[dev]);
+	loop_td[dev]->link.terminate=0;
+	loop_td[dev]->link.queue=0;
+	loop_td[dev]->packet_type = IN_TOKEN;
+	loop_td[dev]->max_transfer=7;
+	loop_td[dev]->retrys=0;
+	loop_td[dev]->device_addr=0x7f;
+
+	for(i=0; i< 1024; i++) {
+		frame_list[dev][i].link = LINK_ADDR(sched_queue[dev]);
+		frame_list[dev][i].queue=1;
+		frame_list[dev][i].terminate=0;
+//		frame_list[dev][i].terminate=1;
+	}
+
+	dump_link( frame_list[dev], "frame_list_link: ");
+//	DPRINTF("dummy_td = %x\n", dummy_td[dev]);
+
+//	dump_frame_list("sched:");
+
+}
+
+void uhci_init(void)
+{
+	int i;
+
+	init_td();
+	init_qh();
+	init_transactions();
+
+	for(i=0;i<MAX_CONTROLLERS; i++) {
+		if(hc_type[i] == 0x00) {
+			init_framelist(i);
+			init_sched(i);
+		}
+	}
+
+	// From now should not change num_controllers any more
+}
+
+int poll_queue_head( queue_head_t *qh)
+{
+	td_t *td;
+	int strikes=3;
+
+	if(qh->depth.terminate)
+		return(1);
+
+	while(strikes--) {
+		if(qh->depth.terminate)
+			return(1);
+
+		td = MEM_ADDR(qh->depth.link);
+
+		if(td->active)
+			return(0);
+
+		udelay(1000);
+
+//		if(!td->active)
+//			return(1);
+	}
+
+	return(1);
+}
+
+int wait_queue_complete( queue_head_t *qh)
+{
+	int ret;
+	int spins=1000;
+
+	while( --spins && !(ret = poll_queue_head(qh))) {
+		udelay(1500);
+//		if(!(spins%30))
+//			DPRINTF("wait_queue_complete: spin\n");
+	}
+//	DPRINTF("wait_queue_complete: returning %d\n", ret);
+
+	if(!spins)
+		return(-1);
+
+	return(ret);
+}
+
+#define BULK_DEPTH 1
+
+transaction_t *_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data)
+{
+	uchar dt;
+	transaction_t *trans;
+	td_t *td, *cur, *last;
+	int remaining = len;
+	uchar *pos = data;
+	int max;
+	uchar type = OUT_TOKEN;
+	int packet_length;
+
+
+	if(ep & 0x80)
+		type = IN_TOKEN;
+
+	ep &= 0x7f;
+
+	td = cur = last = NULL;
+	dt = usb_device[devnum].toggle[ep];
+	max = usb_device[devnum].max_packet[ep];
+
+	while(remaining) {
+		cur = new_td();
+		cur->packet_type = type;
+		cur->data_toggle = dt;
+		cur->endpoint = ep&0x7f;
+		cur->device_addr = devnum;
+		cur->detect_short=1;
+		cur->active=1;
+		dt = dt^0x01;
+		
+		if(!td){
+			td = cur;
+		}
+
+		if(last) {
+			last->link.terminate=0;
+			last->link.link = LINK_ADDR(cur);
+		}
+
+		cur->buffer = (void *) virt_to_bus(pos);
+
+		if(remaining>max) {
+			packet_length = max;
+		}
+		else {
+			packet_length = remaining;
+		}
+		
+		cur->max_transfer=packet_length-1;
+		cur->link.depth = BULK_DEPTH;
+
+		remaining -= packet_length;
+		pos+= packet_length;
+		last = cur;
+	}
+
+//	if( packet_length == max) {	// if final packet wasn't short, add a zero packet
+//		cur = new_td();
+//		dt = dt^0x01;
+//		cur->packet_type = type;
+//		cur->max_transfer = 0x7ff;	// zero length code
+//		last->link.terminate=0;
+//		last->link.link = LINK_ADDR(cur);
+//		
+//	}
+
+	cur->link.terminate=1;
+
+	trans = new_transaction(td);
+	usb_device[devnum].toggle[ep] = dt;
+
+	return(trans);
+}
+
+#define DEPTH 0
+
+transaction_t *ctrl_msg(uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, uchar *data)
+{
+	td_t *td;
+	td_t *current_td;
+	td_t *last_td;
+	transaction_t *trans;
+
+	ctrl_msg_t *message;
+
+	unsigned char type;
+	int remaining = wLength;
+	uchar *pos = data;
+	uchar dt=1;
+
+//	DPRINTF("ctrl_msg( %02x, %02x, %02x, %04x, %04x, %04x, %p)\n", devnum, request_type, request, wValue, wIndex, wLength, data);
+//	DPRINTF("%d bytes in payload\n", remaining);
+//	DPRINTF("lowspeed = %u\n", usb_device[devnum].lowspeed);
+	last_td = td = new_td();
+
+	td->packet_type = SETUP_TOKEN;
+	td->device_addr = devnum & 0x7f;
+	td->max_transfer = 7;		// fixed for setup packets
+	td->retrys = CTRL_RETRIES;
+	td->active=1;
+	td->data_toggle=0;
+	td->link.depth=DEPTH;
+	td->detect_short=0;
+	td->interrupt=1;
+	td->lowspeed = usb_device[devnum].lowspeed;
+
+// steal 8 bytes from so-called software area to hole the control message itself
+	td->buffer = (void *) virt_to_bus(&(td->data[2]));
+	message = bus_to_virt( (unsigned int) td->buffer);
+
+	message->bmRequestType = request_type;
+	message->bRequest = request;
+	message->wValue = wValue;
+	message->wIndex = wIndex;
+	message->wLength = wLength;
+//dump_hex(td, sizeof(td_t), "ctrl_msg:");
+	trans = new_transaction(td);
+
+	if(!trans) {
+		DPRINTF("ctrl_msg: couldn't allocate a transaction!\n");
+		return(NULL);
+	}
+
+	if(request_type & CONTROL_DIR_MASK) 
+		type = IN_TOKEN;
+	else
+		type = OUT_TOKEN;
+
+	while(remaining >0)	{
+		int length;
+
+//		DPRINTF("ctrl_msg loop %d remaining, maxpacket = %u\n", remaining, usb_device[devnum].max_packet[0]);
+		current_td = new_td();
+
+		last_td->link.link = LINK_ADDR(current_td);
+		last_td->link.terminate=0;
+		last_td->link.queue=0;
+		last_td->link.depth=DEPTH;
+		
+
+		current_td->device_addr = devnum & 0x7f;
+		current_td->retrys = CTRL_RETRIES;
+		current_td->active=1;
+		current_td->data_toggle=dt;
+		current_td->link.depth=DEPTH;
+		current_td->lowspeed = usb_device[devnum].lowspeed;
+		current_td->detect_short=1;
+
+		dt = dt^0x01;
+
+		current_td->packet_type = type;
+//		if(type == IN_TOKEN)
+//			current_td->detect_short=1;
+
+		if(remaining >usb_device[devnum].max_packet[0])
+			length = usb_device[devnum].max_packet[0];
+		else
+			length = remaining;
+
+		current_td->max_transfer = length-1;
+		current_td->buffer = (void *) virt_to_bus(pos);
+		remaining -= length;
+		pos += length;
+
+		last_td = current_td;
+	}
+
+	current_td = new_td();
+
+	current_td->device_addr =  devnum & 0x7f;
+	current_td->retrys = CONTROL_STS_RETRIES;
+	current_td->active=1;
+	current_td->lowspeed = usb_device[devnum].lowspeed;
+
+	if(type == IN_TOKEN)
+		current_td->packet_type = OUT_TOKEN;
+	else
+		current_td->packet_type = IN_TOKEN;
+
+	current_td->max_transfer=0x7ff;
+
+	current_td->link.terminate=1;
+	current_td->data_toggle=1;
+	current_td->link.depth=DEPTH;
+
+	
+	last_td->link.link = LINK_ADDR(current_td);
+	last_td->link.terminate=0;
+	last_td->link.queue=0;
+	last_td->link.depth=DEPTH;
+
+	return(trans);
+}
+	
+
+int schedule_transaction( uchar dev, transaction_t *trans)
+{
+	unsigned short value;
+
+	if(!sched_queue[dev]->depth.terminate)
+		return(-EBUSY);
+
+	sched_queue[dev]->depth.link = LINK_ADDR(trans->qh);
+	sched_queue[dev]->depth.terminate = 0;
+	sched_queue[dev]->depth.queue=1;
+
+	if(hc_type[dev]==0x00) {
+		value = inw(hc_base[dev]);
+		value |=1;
+		outw( value, hc_base[dev]);
+	} 
+#if 0
+	else if (hc_type[dev]==0x10) {
+		uint32_t value;
+		ohci_regs_t *ohci_regs = (ohci_regs_t *) hc_base[dev];
+                value = readl(&ohci_regs->control);
+                value |=OHCI_USB_OPER;
+                writel( value, &ohci_regs->control);
+	
+	}
+#endif
+	
+	return(0);
+}
+
+int wait_transaction( transaction_t *trans)
+{
+	queue_head_t *qh;
+
+	qh = trans->qh;
+
+	while(!qh->bredth.terminate) 
+		qh = MEM_ADDR(qh->bredth.link);
+
+	return( wait_queue_complete(qh));
+}
+
+void unlink_transaction( uchar dev, transaction_t *trans)
+{
+	sched_queue[dev]->depth.terminate=1;
+	sched_queue[dev]->depth.link = 0;	// just in case
+}
+
+int uhci_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data)
+{
+	transaction_t *trans;
+	td_t *td;
+	int data_len;
+	int ret;
+	uchar *buffer;
+	DPRINTF("bulk_transfer: ep = %x len=%d\n", ep, len);
+#if ALLOCATE==1
+        buffer = allot2(2048, 0x7ff);
+	
+	if(buffer==0){
+                printf("bulk_transfer: can not allot\n");
+        }
+	memset(buffer,0,2048);
+//	DPRINTF("bulk_transfer: buffer(virt) = %x buffer(phys) = %x len = %d\n", buffer, virt_to_phys(buffer), len);
+
+        if( !(ep & 0x80))
+                memcpy(buffer, data, len);
+#else
+	buffer = data;
+#endif
+	
+
+	trans = _bulk_transfer(devnum, ep, len, buffer);
+#if 0
+#ifdef DEBUG
+	dump_transaction(trans, "bulk_transfer:");
+#endif
+#endif
+	schedule_transaction( usb_device[devnum].controller, trans);
+	ret = wait_transaction(trans);
+
+	if(ret<0) {
+#ifdef DEBUG
+		dump_uhci(hc_base[usb_device[devnum].controller] );
+		dump_td(trans->td_list, "failed_bulk_transaction: ");
+#endif
+ 		unlink_transaction( usb_device[devnum].controller, trans);
+		free_transaction(trans);
+#if ALLOCATE==1
+                forget2(buffer);
+#endif
+		return(-1);
+	}
+
+	unlink_transaction( usb_device[devnum].controller, trans);
+
+	data_len=0;
+	td = trans->td_list;
+	do {
+		if(td->active)
+			break;
+
+		if(td->max_transfer == 0x7ff)
+			break;
+
+		data_len += td->actual +1;
+
+		if(td->actual < td->max_transfer) // short packet also check for errors here
+			break;
+
+		if(!td->link.terminate){
+			td = MEM_ADDR(td->link.link);
+		}
+		else {
+			td=NULL;
+		}
+	} while(td);
+#if 0
+
+#ifdef DEBUG
+	dump_td(trans->td_list, "bulk_transfer_success:");
+#endif
+#endif
+
+	if(data_len < len) {
+		DPRINTF("bulk_transfer( dev= %d, ep = %d, len = %d, buffer = %x) = %d:short transaction:\n", devnum, ep, len, data, data_len);
+		dump_td(trans->td_list, "short_transaction:");
+	}
+
+	free_transaction(trans);
+
+#if ALLOCATE==1
+	if( (ep & 0x80))
+	        memcpy(data, buffer, len);
+        forget2(buffer);
+#endif
+
+
+	DPRINTF("bulk_transfer returning %d\n", data_len);
+	return(data_len);
+}
+
+int uhci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, void *data)
+{
+	transaction_t *trans;
+	td_t *td;
+	int data_len=0;
+	uchar *buffer;
+	int ret;
+        DPRINTF("uhci_control_msg: request_type = %x request = %x wLength=%d\n", request_type, request, wLength);
+#if ALLOCATE==1
+//	if( (wLength!=0) && (data!=NULL) ) {
+	        buffer = allot2(2048+wLength,0x7ff);
+	        if(buffer==0){
+        	        printf("uhci_control_msg: can not allot\n");
+        	}
+		
+		memset(buffer,0,2048+wLength);
+	//DPRINTF("uhci_control_msg: buffer(virt) = %x buffer(phys) = %x wLength=%d\n", buffer, virt_to_phys(buffer), wLength);
+        	if( !(request_type & 0x80))
+                	memcpy(buffer, data, wLength);
+//	} else {
+//		buffer=NULL;
+//	}
+	
+#else
+        buffer = data;
+#endif
+
+	trans = ctrl_msg(devnum, request_type, request, wValue, wIndex, wLength, buffer);
+	if(!trans) {
+		DPRINTF("uhci_control_msg: ctrl_msg failed!\n");
+#if ALLOCATE==1
+                forget2(buffer);
+#endif
+		return(-1);
+	}
+	
+	schedule_transaction( usb_device[devnum].controller, trans);
+	ret = wait_transaction(trans);
+
+	if(ret<0) {
+#ifdef DEBUG
+		dump_uhci(hc_base[usb_device[devnum].controller] );
+		dump_td(trans->td_list, "failed_transaction: ");
+#endif
+		unlink_transaction( usb_device[devnum].controller, trans);
+		free_transaction(trans);
+#if ALLOCATE==1
+                forget2(buffer);
+#endif
+		return(ret);
+	}
+
+//#ifdef DEBUG
+//	dump_td(trans->td_list, "success: ");
+//#endif
+
+	unlink_transaction( usb_device[devnum].controller, trans);
+
+	// now, see what happened
+
+	if(!trans->qh->depth.terminate) {
+//		handle setup error
+
+		dump_uhci(hc_base[usb_device[devnum].controller]);
+		dump_td(trans->td_list, "qh->depth failed_transaction: ");
+
+		free_transaction(trans);
+#if ALLOCATE==1
+                forget2(buffer);
+#endif
+		return(-1);
+	}
+
+	td = trans->td_list;
+
+	do {
+		if(td->packet_type != SETUP_TOKEN)
+			data_len += td->actual;
+
+		if(td->actual < td->max_transfer) // short packet also check for errors here
+			break;
+
+		if(!td->link.terminate) {
+			td = MEM_ADDR(td->link.link);
+		}
+		else {
+			td=NULL;
+		}
+	} while(td);
+
+	free_transaction(trans);
+
+#if ALLOCATE==1
+	if ( (wLength!=0) && (data!=NULL)){
+	        if( (request_type & 0x80))
+        	        memcpy(data, buffer, wLength);
+        	forget2(buffer);
+	}
+#endif
+
+	DPRINTF("usb_control_message returning %d\n", data_len);
+
+	return(data_len);
+}
+
+
+int poll_u_root_hub(unsigned short port, uchar controller)
+{
+	ushort value;
+	int addr=0;
+	int i;
+	static int do_over=0;
+
+	value = inw(port);
+	
+	debug("poll_u_root_hub1 v=%08x\t", value);
+
+	if(value & 0x02 || do_over == port) {
+		debug("poll_u_root_hub2 v=%08x\t", value);
+		do_over=0;
+		if(value & 0x01 ) {	// if port connected
+			debug("poll_u_root_hub21 v=%08x\t", value);
+			DPRINTF("Connection on port %04x\n", port);
+
+			outw(value, port);
+			for(i=0; i<40; i++) {
+				udelay(10000+usec_offset);
+				value = inw(port);
+				if(value & 0x02) {
+					outw(value, port);
+					i=0;
+					DPRINTF("BOUNCE!\n");
+				}
+			}
+
+			uport_wakeup(port);
+//			DPRINTF("Wakup %04x\n", port);
+
+			uport_reset(port);
+			udelay(10);
+			uport_enable(port);
+
+			if(!value & 0x01) {
+				DPRINTF("Device went away!\n");
+				return(-1);
+			}
+
+			addr = configure_device( port, controller, value & 0x100);
+
+			if(addr<0) {
+				uport_disable(port);
+				udelay(20000);
+//				uport_reset(port);
+				uport_reset_long(port);
+				uport_suspend(port);
+				do_over=port;
+				uhc_clear_stat();
+//				dump_uhci(0x38c0);
+			}
+		} else {
+			uport_suspend(port);
+			uport_disable(port);
+			DPRINTF("Port %04x disconnected\n", port);
+			// wave hands, deconfigure devices on this port!
+		}
+	}
+			
+	
+	return(addr);
+}

Added: trunk/filo/drivers/usb/uhci.h
===================================================================
--- trunk/filo/drivers/usb/uhci.h	                        (rev 0)
+++ trunk/filo/drivers/usb/uhci.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,175 @@
+#ifndef _UHCI_H
+#define _UHCI_H
+
+/*
+ * The link pointer is multi use. Some fields are valid only for some uses. 
+ * In other cases, they must be 0
+ *
+ */
+
+#define MAX_POLLDEV 10
+
+#define MAX_TRANSACTIONS 10
+#define MAX_QUEUEHEAD 255
+#define MAX_TD 1024
+
+
+typedef struct link_pointer {
+        unsigned long terminate:1;
+        unsigned long queue:1;
+        unsigned long depth:1;
+        unsigned long reserved:1;
+        unsigned long link:28;
+} __attribute__((packed)) link_pointer_t;
+
+extern link_pointer_t *frame_list[];
+
+void init_framelist(uchar dev);
+
+
+#define SETUP_TOKEN 0x2d
+#define IN_TOKEN 0x69
+#define OUT_TOKEN 0xe1
+
+#define CTRL_RETRIES 3
+#define CONTROL_STS_RETRIES 0
+
+
+// some port features
+#define PORT_CONNECTION 0
+#define PORT_ENABLE 1
+#define PORT_SUSPEND 2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET 4
+#define PORT_POWER 8
+#define PORT_LOW_SPEED 9
+#define C_PORT_CONNECTION 16
+#define C_PORT_ENABLE 17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET 20
+
+// features
+#define FEATURE_HALT 0
+
+typedef struct td {
+	
+	link_pointer_t link;
+
+	unsigned long actual:11;	// actual length
+	unsigned long reserved2:5;
+
+// status/error flags
+	unsigned long res1:1;
+	unsigned long bitstuff:1;
+	unsigned long crc:1;
+	unsigned long nak:1;
+	unsigned long babble:1;
+	unsigned long buffer_error:1;
+	unsigned long stall:1;
+	unsigned long active:1;
+
+	unsigned long interrupt:1;	// interrupt on complete
+	unsigned long isochronous:1;
+	unsigned long lowspeed:1;
+	unsigned long retrys:2;
+	unsigned long detect_short:1;
+	unsigned long reserved3:2;
+
+	unsigned long packet_type:8;	// one of in (0x69), out (0xe1) or setup (0x2d)
+	unsigned long device_addr:7;
+	unsigned long endpoint:4;
+	unsigned long data_toggle:1;
+	unsigned long reserved:1;
+	unsigned long max_transfer:11;	// misnamed. Desired length might be better
+
+	void *buffer;
+	unsigned long data[4];	// free use by driver
+} __attribute__((packed)) td_t;
+
+typedef struct queue_head {
+	link_pointer_t bredth;	// depth must = 0
+	link_pointer_t depth;	// depth may vary randomly, ignore
+	unsigned long int udata[2];
+} __attribute__((packed)) queue_head_t;
+
+typedef struct transaction {
+	queue_head_t	*qh;
+	td_t		*td_list;
+	struct transaction *next;
+} transaction_t;
+
+//#####################################################
+int wait_head( queue_head_t *head, int count);
+
+extern queue_head_t *free_qh;
+extern queue_head_t *queue_heads;
+
+queue_head_t *new_queue_head(void);
+void free_queue_head( queue_head_t *qh);
+void init_qh(void);
+
+extern td_t *free_td_list;
+extern td_t *tds;
+
+void init_td(void);
+td_t *new_td(void);
+td_t *find_last_td(td_t *td);
+void free_td( td_t *td);
+link_pointer_t *queue_end( queue_head_t *queue);
+void add_td( queue_head_t *head, td_t *td);
+
+extern transaction_t transactions[MAX_TRANSACTIONS];
+extern transaction_t *free_transactions;
+
+void init_transactions(void);
+void free_transaction( transaction_t *trans );
+transaction_t *new_transaction(td_t *td);
+transaction_t *add_transaction( transaction_t *trans, td_t *td);
+
+
+#define USBCMD(x) hc_base[x]
+#define USBSTS(x) (hc_base[x] + 0x02)
+#define USBINTR(x) (hc_base[x] + 0x04)
+#define FRNUM(x) ( hc_base[x] + 0x06)
+#define FLBASE(x) ( hc_base[x] + 0x08)
+#define SOFMOD(x) ( hc_base[x] + 0x0c)
+#define PORTSC1(x) ( hc_base[x] + 0x10)
+#define PORTSC2(x) ( hc_base[x] + 0x12)
+
+#define USBCMDRUN 0x01
+#define USBCMD_DEBUG 0x20
+
+#define USBSTSHALTED 0x20
+
+
+void hc_reset(uchar dev);
+int hc_stop(void);
+int hc_start(uchar dev);
+
+extern queue_head_t *sched_queue[];
+
+void init_sched(uchar dev);
+int poll_queue_head( queue_head_t *qh);
+int wait_queue_complete( queue_head_t *qh);
+
+extern int num_polls;
+extern int (*devpoll[MAX_POLLDEV])(uchar);
+extern uchar parm[MAX_POLLDEV];
+
+transaction_t *_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
+transaction_t *ctrl_msg(uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, uchar *data);
+int schedule_transaction( uchar dev, transaction_t *trans);
+int wait_transaction( transaction_t *trans);
+void unlink_transaction( uchar dev, transaction_t *trans);
+int uhci_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
+int uhci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, void *data);
+
+
+// defined in uhci.c
+int uhc_init(pcidev_t dev);
+void uhci_init(void);
+void clear_uport_stat(unsigned short port);
+int poll_u_root_hub(unsigned short port, uchar controller);
+
+#endif

Added: trunk/filo/drivers/usb/usb.c
===================================================================
--- trunk/filo/drivers/usb/usb.c	                        (rev 0)
+++ trunk/filo/drivers/usb/usb.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,826 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <arch/byteorder.h>
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+#define DPRINTF debug
+#include "usb.h"
+#include "uhci.h"
+#include "ohci.h"
+#include "debug_x.h"
+
+
+usbdev_t usb_device[MAX_USB_DEV];
+
+
+#define ALLOCATE 1
+
+int usec_offset=0;
+
+int num_controllers=0;
+
+uint32_t hc_base[MAX_CONTROLLERS];
+uint8_t  hc_type[MAX_CONTROLLERS];
+
+static void pci_scan_for_usb(int bus)
+{
+	int slot, func;
+	unsigned int val;
+	unsigned char hdr;
+
+	for (slot = 0; slot < 0x20; slot++) {
+		for (func = 0; func < 8; func++) {
+			uint8_t prog_if;
+			uint16_t devclass;
+			pcidev_t dev = PCI_DEV(bus, slot, func);
+
+			val = pci_read_config32(dev, REG_VENDOR_ID);
+			if (val == 0xffffffff || val == 0x00000000 ||
+			    val == 0x0000ffff || val == 0xffff0000)
+				continue;
+
+			devclass = pci_read_config16(dev, 0x0a);
+			prog_if = pci_read_config8(dev, 9);
+
+			if (devclass == 0x0c03) {
+
+				switch (prog_if) {
+				case 0x00: // UHCI
+					hc_type[num_controllers] = prog_if;
+					uhc_init(dev);
+					break;
+				case 0x10: // OHCI
+					hc_type[num_controllers] = prog_if;
+					ohc_init(dev);
+#if 0 
+				case 0x20: // EHCI
+					hc_type[num_controllers] = prog_if;
+					ehc_init(dev);
+#endif
+				}
+			}
+
+			if (num_controllers >= MAX_CONTROLLERS)
+				return;
+
+			hdr = pci_read_config8(dev, REG_HEADER_TYPE) & 0x7f;
+			if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
+				unsigned int next_bus;
+				next_bus = (pci_read_config32(dev, REG_PRIMARY_BUS) >> 8) & 0xff;
+				pci_scan_for_usb(next_bus);
+
+			}
+		}
+	}
+}
+
+void hci_init(void)
+{
+	int i;
+
+	for(i=0;i<MAX_CONTROLLERS; i++) {
+		hc_type[i] = 0xff;
+	}
+
+        /* Find a PCI_SERIAL_USB class device */
+	num_controllers = 0;
+	pci_scan_for_usb(0);
+
+	// From now should not change num_controllers any more
+	
+	uhci_init();
+	ohci_init();
+}
+
+
+int next_usb_dev;
+usbdev_t usb_device[MAX_USB_DEV];
+
+void init_devices(void) 
+{
+
+	memset(usb_device,0,sizeof(usb_device));
+	usb_device[0].max_packet[0] = 8;
+	next_usb_dev=2; // 0 for all controller root hub, use MAX_CONTROLLERS instead??? 
+			// do we need have one for every controller ?? or just use hc_base and hc_type instead
+			// For example 0 --> controller 1 root hub
+			// 	       1 --> controller 2 root hub
+			//	       2 --> controller 3 root hub....
+}
+
+
+inline int set_address( uchar address)
+{
+	int ret;
+
+	ret = usb_control_msg(0, 0, SET_ADDRESS, address, 0, 0, NULL);
+
+	return(ret);
+}
+
+inline int clear_stall(uchar device, uchar endpoint)
+{
+	int ret;
+
+	ret = usb_control_msg(device, CONTROL_ENDPOINT, CLEAR_FEATURE, FEATURE_HALT, endpoint, 0, NULL);
+	if(hc_type[device]==0x00) {
+		usb_device[device].toggle[endpoint]=0;
+	}
+	else if(hc_type[device]==0x10) {
+		usb_settoggle(&usb_device[device], endpoint & 0xf, ((endpoint & 0x80)>>7)^1, 0);
+	}
+
+	return(ret);
+}
+
+inline int device_reset(uchar device) {
+	return usb_control_msg(device, 0x21, 0xff, 0, 0, 0, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+//	String Descriptors
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+#define STRING_DESCRIPTOR 0x0300
+
+int get_string( uchar addr, uchar string, int len, uchar *buffer)
+{
+	int ret;
+	int i,j;
+	int real_len;
+	ushort lang;
+
+	if(!string) {
+		strcpy((char *)buffer, "unknown");
+		return(0);
+	}
+
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, 0, 4, buffer);
+	real_len = buffer[0];
+	if(real_len>len)
+		real_len = len;
+
+	lang = buffer[2] | buffer[3]<<8;
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, lang, real_len, buffer);
+
+	// de-unicode it!
+	for(i=0, j=2; j<real_len; i++, j+=2)
+		buffer[i] = buffer[j];
+
+	buffer[i]=0;
+	real_len/=2;
+
+	return(real_len);
+}
+
+int get_string2( uchar addr, uchar string, ushort lang, int len, uchar *buffer)
+{
+        int ret;
+        int i,j;
+        int real_len;
+
+
+        ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, lang, len, buffer);
+
+        real_len = buffer[0];
+        if(real_len>len)
+                real_len = len;
+
+	if(real_len<=4)  {
+		strcpy((char *)buffer, "USB");
+		real_len = 3;
+		buffer[real_len] = 0;
+	} else {
+        	// de-unicode it!
+        	for(i=0, j=2; j<real_len; i++, j+=2)
+                	buffer[i] = buffer[j];
+
+        	buffer[i]=0;
+        	real_len/=2;
+	}
+
+        return(real_len);
+}
+ushort get_lang( uchar addr, uchar string, int len, uchar *buffer)
+{
+        int ret;
+        int i,j;
+        int real_len;
+	ushort lang;
+        
+        ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, 0, 4, buffer);
+	lang = buffer[2] | buffer[3]<<8;
+
+        return lang;
+}       
+
+///////////////////////////////////////////////////////////////////////////////////////
+//
+// HUB functions. This will be moved to it's own module soonishly
+//
+///////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct port_charge {
+	ushort c_port_connection:1;
+	ushort c_port_enable:1;
+	ushort c_port_suspend:1;
+	ushort c_port_over_current:1;
+	ushort c_port_reset:1;
+	ushort reserved:11;
+} port_change_t;
+
+typedef struct port_status {
+	ushort port_connection:1;
+	ushort port_enable:1;
+	ushort port_suspend:1;
+	ushort port_over_current:1;
+	ushort port_reset:1;
+	ushort reserved:3;
+	ushort port_power:1;
+	ushort port_lowspeed:1;
+	ushort port_highspeed:1;
+	ushort port_test:1;
+	ushort port_indicator:1;
+} __attribute__ ((packed)) portstatus_t;
+
+
+typedef struct portstat {
+	portstatus_t  stat;
+	port_change_t change;
+} __attribute__ ((packed)) portstat_t;
+
+int hub_port_reset( uchar addr, uchar port)
+{
+	int ret;
+	int tries=100;
+	portstat_t status;
+
+	ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_RESET, port, 0, NULL);	// reset port
+
+	while(tries--) {
+		udelay(10000);
+		ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, port, 4, &status);
+		if(!status.change.c_port_reset)
+			continue;
+
+		ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_RESET, port, 0, NULL);	// clear status
+		return(0);
+	}
+
+	DPRINTF("hub_port_reset(%x, %x) failed,\n", addr, port);
+	dump_hex((uint8_t *)&status, 4, "status=");
+
+	return(-1);
+}
+
+int hub_port_resume( uchar addr, uchar port)
+{
+	int ret;
+	int tries=100;
+	portstat_t status;
+
+	ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, PORT_SUSPEND, port, 0, NULL);	// reset port
+
+	while(tries--) {
+		udelay(10000);
+		ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, port, 4, &status);
+		if(!status.change.c_port_suspend)
+			continue;
+
+		ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_SUSPEND, port, 0, NULL);	// clear status
+		return(0);
+	}
+
+	return(-1);
+}
+
+int poll_hub(uchar addr)
+{
+	int i;
+	int ret;
+	uchar devaddr=0;
+	hub_descriptor_t *desc;
+	portstat_t status;
+
+	DPRINTF("Poll hub (%x)\n", addr);
+	desc = usb_device[addr].private;
+
+	for(i=1; i<= desc->bNbrPorts; i++) {
+		ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, i, 4, &status);
+//		DPRINTF("Get status for port %u returns: %d\n", i, ret);
+//		dump_hex(&status, 4, "status=");	
+
+		if(status.change.c_port_connection) {
+			ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_CONNECTION, i, 0, NULL);	// clear status
+
+			if(status.stat.port_connection) {
+				udelay(desc->bPwrOn2PwrGood * 20000);
+
+				hub_port_resume(addr, i);
+
+				ret = hub_port_reset(addr,i);
+				udelay(10);
+				ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_ENABLE, i, 0, NULL);	// enable port
+
+//		ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, i, 4, &status);
+//		DPRINTF("*****Get status again  for port %u returns: %d\n", i, ret);
+//		dump_hex(&status, 4, "status=");	
+
+				devaddr = configure_device(i, usb_device[addr].controller, status.stat.port_lowspeed);
+
+				// configure
+			} else {
+				ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_SUSPEND, i, 0, NULL);	// suspend port
+				ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, PORT_ENABLE, i, 0, NULL);	// disable port
+				DPRINTF("Hub %d, Port %04x disconnected\n", addr, i);
+				// deconfigure
+			}
+		}
+	}
+	return(devaddr);
+
+}
+
+int usb_hub_init( uchar addr) 
+{
+	int i;
+	int ret;
+	hub_descriptor_t *desc;
+
+	desc = malloc(sizeof(hub_descriptor_t));
+
+	memset(desc, 0 , sizeof(hub_descriptor_t));
+
+	DPRINTF("hub init (%d)\n", addr);
+
+	ret = usb_control_msg(addr, 0xa0, GET_DESCRIPTOR, 0x2900, 0, 8, desc);
+	ret = usb_control_msg(addr, 0xa0, GET_DESCRIPTOR, 0x2900, 0, desc->bLength, desc);
+
+	usb_device[addr].private = desc;
+
+	for(i=1; i<=desc->bNbrPorts; i++)
+		ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_POWER, i, 0, NULL);	// power port
+
+
+	// register hub to be polled
+
+	devpoll[num_polls] = poll_hub;
+	parm[num_polls++] = addr;
+
+	return(0);
+}
+
+extern void ohci_dump_x(uchar controller);
+
+// will set up whatever device is answering at address 0.
+int configure_device(uint32_t port, uchar controller, unsigned int lowspeed)
+{
+	device_descriptor_t *desc;
+	config_descriptor_t *conf;
+	interface_descriptor_t *iface;
+	endpoint_descriptor_t *epd;
+	int ret;
+	int i;
+	int addr = next_usb_dev++;
+	uchar buffer[512];
+	uchar string[255];
+	ushort lang;
+	uchar x[2];
+
+	desc = (device_descriptor_t *) buffer;
+
+	memset( &usb_device[addr], 0, sizeof(usbdev_t));
+
+	printf("New USB device, setting address %d\n", addr);
+	if(lowspeed) {
+		usb_device[addr].lowspeed = usb_device[0].lowspeed = 1;
+		DPRINTF("LOWSPEED\n");
+	} else
+		usb_device[addr].lowspeed = usb_device[0].lowspeed = 0;
+
+	usb_device[0].port = usb_device[addr].port = port;
+	usb_device[0].controller = usb_device[addr].controller = controller;
+	usb_device[addr].toggle2[0]=0;
+	usb_device[addr].toggle2[1]=0;
+
+//	hc_clear_stat();
+
+	ret = set_address(addr);
+	if(ret<0) {
+		DPRINTF("configure_device: set_address failed!\n");
+		next_usb_dev--;
+		return(-1);
+	}
+
+	mdelay(10);   /* Let the SET_ADDRESS settle */
+		
+	usb_device[addr].max_packet[0] = 8;
+	
+
+	DPRINTF("Fetching device descriptor length\n");
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x100, 0, 8, desc);
+
+	usb_device[addr].max_packet[0] = desc->max_packet;
+
+	DPRINTF("Fetching device descriptor\n");
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x100, 0, desc->bLength, desc);
+	if(ret < desc->bLength)
+		return(-1);
+
+	DPRINTF("Fetching config descriptor length\n");
+	conf = (config_descriptor_t *) (buffer + sizeof(device_descriptor_t));
+
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x200, 0, 8, conf);
+
+	DPRINTF("Fetching config descriptor\n");
+	ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x200, 0, conf->wTotalLength, conf);
+	if(ret < conf->wTotalLength)
+		return(-1);
+
+	iface = (interface_descriptor_t *) (buffer + sizeof(device_descriptor_t) + conf->bLength);
+	epd = (endpoint_descriptor_t *) (buffer + conf->bLength + iface->bLength + sizeof(device_descriptor_t));
+
+	DPRINTF("device:\n");
+	dump_device_descriptor( desc, "");
+	DPRINTF("config:\n");
+	dump_config_descriptor( (uchar *)conf, "");
+
+	DPRINTF("Selecting Configuration number %x:\n", conf->bConfigurationValue);
+	ret = usb_control_msg(addr, 0, SET_CONFIGURATION, conf->bConfigurationValue, 0, 0, NULL);
+	
+//	mdelay(20);
+
+#if 0
+	usb_control_msg(addr, 0x80,    GET_CONFIGURATION, 0, 0, 1 , x);
+	DPRINTF("Configuration number = %x\n", x[0]);
+
+        usb_control_msg(addr, 0x80, GET_STATUS, 0, addr, 2, x);
+        DPRINTF("status = %x %x\n", x[0], x[1]);
+
+        usb_control_msg(addr, 0x81, GET_STATUS, 0, 0, 2, x);
+        DPRINTF("status = %x %x\n", x[0], x[1]);
+#endif
+
+	for(i=0; i<iface->bNumEndpoints;i++) {
+		if(!epd[i].bEndpointAddress) {
+			usb_device[addr].max_packet[ 1 ] = epd[i].wMaxPacketSize & 0x3ff;
+		} else {
+			usb_device[addr].max_packet[ epd[i].bEndpointAddress & 0x7f ] = epd[i].wMaxPacketSize & 0x3ff;
+		}
+
+		if( (epd[i].bmAttributes & 0x03) == 0x01) // interrupt
+			usb_device[addr].interrupt = epd[i].bEndpointAddress;
+
+		if( (epd[i].bmAttributes & 0x03) == 0x02) { // bulk
+#if 0
+			DPRINTF("clear stall on ep=%x\n", epd[i].bEndpointAddress);
+			clear_stall(addr, epd[i].bEndpointAddress);	// to reset data toggle
+			udelay(10);
+#endif
+
+#if 0
+			usb_control_msg(addr, 0x82, GET_STATUS, 0, epd[i].bEndpointAddress, 2, x);
+			DPRINTF("status = %x %x\n", x[0], x[1]);
+#endif
+
+			if(epd[i].bEndpointAddress & 0x80){  //in
+				usb_device[addr].bulk_in = epd[i].bEndpointAddress; 
+			}
+			else { //out
+				usb_device[addr].bulk_out = epd[i].bEndpointAddress; 
+			}
+		}
+
+	}
+
+	// determine device class
+	if(desc->Class) {
+		usb_device[addr].class = desc->Class;
+		usb_device[addr].subclass = desc->SubClass;
+		usb_device[addr].protocol = desc->protocol;
+	} else {
+		usb_device[addr].class = iface->bInterfaceClass;
+		usb_device[addr].subclass = iface->bInterfaceSubClass;
+		usb_device[addr].protocol = iface->bInterfaceProtocol;
+	}
+
+	printf("%02x:%02x:%02x\n", usb_device[addr].class, usb_device[addr].subclass, usb_device[addr].protocol);
+#if 0
+	get_string(addr, desc->iManufacturor, sizeof(string), string);
+	printf("Manufacturor: %s\n", string);
+
+	get_string(addr, desc->iProduct, sizeof(string), string);
+	printf("Product: %s\n", string);
+
+	get_string(addr, desc->iSerial, sizeof(string), string);
+	printf("Serial: %s\n", string);
+#else	
+        lang = get_lang(addr, 0, sizeof(string), string);
+	
+	get_string2(addr, desc->iManufacturor, lang, sizeof(string), string);
+        printf("Manufacturor: %s\n", string);
+
+        get_string2(addr, desc->iProduct, lang,sizeof(string), string);
+        printf("Product: %s\n", string);
+
+        get_string2(addr, desc->iSerial, lang, sizeof(string), string);
+        printf("Serial: %s\n", string);
+#endif
+	
+	switch( usb_device[addr].class) {
+		case 0x09:	// hub
+			usb_hub_init(addr);
+			break;
+
+		default:
+			break;
+
+	}
+		
+	DPRINTF("DEVICE CONFIGURED\n");
+
+	return(addr);
+}
+
+int num_polls=0;
+int (*devpoll[MAX_POLLDEV])(uchar);
+uchar parm[MAX_POLLDEV];
+
+int poll_usb()
+{
+	int addr;
+	int found=0;
+	int i;
+	int j;
+
+	for(i=0; i<num_controllers; i++) {
+		debug("poll_usb1 i=%d\t", i);
+		// if addr >0, should probably see what was attached!
+		if(hc_type[i]==0x00) {
+			addr = poll_u_root_hub(PORTSC1(i), i);
+			if(addr && !found)
+				found=addr;
+
+			addr = poll_u_root_hub(PORTSC2(i), i);
+			if(addr && !found)
+				found=addr;
+		} 
+
+		else if(hc_type[i]==0x10) {
+			int NDP;
+			NDP = readl(&ohci_regs->roothub.a) & 0xff;
+			ohci_regs = (ohci_regs_t *)hc_base[i];
+			for(j=0;j<NDP;j++) { 
+	                        addr = poll_o_root_hub((uint32_t)&ohci_regs->roothub.portstatus[j], i);
+        	                if(addr && !found)
+                	                found=addr;
+			}
+			
+		}
+		
+	}
+
+	// now poll registered drivers (such as the hub driver
+	for(i=0;i<num_polls; i++) {
+		debug("poll_usb2 i=%d\t", i);
+		addr = devpoll[i](parm[i]);
+		if(addr && !found)
+			found=addr;
+	}
+
+	return(found);	
+}
+
+
+int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data)
+{
+	uint8_t hc_num = usb_device[devnum].controller;
+	if(ep&0x80) {
+		ep = usb_device[devnum].bulk_in;
+	} else {
+		ep = usb_device[devnum].bulk_out;
+	}
+	
+	if(hc_type[hc_num] == 0x00) { //UHCI
+		return uhci_bulk_transfer(devnum, ep, len, data);
+	} 
+	else if( hc_type[hc_num] == 0x10 ) {  //OHCI
+		return ohci_bulk_transfer(devnum, ep, len, data);
+	}
+#if 0 
+	else if (hc_type[hc_num] == 0x20 ) {  //EHCI
+		return ehci_bulk_transfer(devnum, ep, len, data);
+	}
+#endif
+	return 0;
+}
+int usb_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, 
+	unsigned short wLength, void *data)
+{
+	
+	uint8_t hc_num = usb_device[devnum].controller;
+
+        if(hc_type[hc_num] == 0x00) { //UHCI
+                return uhci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
+        } 
+        else if( hc_type[hc_num] == 0x10 ) {  //OHCI
+                return ohci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
+        }
+#if 0 
+        else if (hc_type[hc_num] == 0x20 ) {  //EHCI
+                return ehci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
+        }
+#endif
+        return 0;	
+}
+
+
+struct urb *usb_alloc_urb(int controller)
+{
+        struct urb *urb;
+	ohci_t *ohci = NULL;
+#if URB_PRE_ALLOCATE!=1
+        urb = (struct urb *)allot2(sizeof(struct urb),0xff);
+        if (!urb) {
+                printf("usb_alloc_urb:  allot2 failed");
+                return NULL;
+        }
+#else 
+	if(hc_type[controller] == 0x10) { //OHCI
+		ohci = &_ohci_x[controller];
+		urb = ohci->urb;
+	} else {
+		urb = NULL;
+	}
+#endif
+
+        memset(urb, 0, sizeof(*urb));
+
+        return urb;
+}
+/**
+ *      usb_free_urb - frees the memory used by a urb
+ *      @urb: pointer to the urb to free
+ *
+ *      If an urb is created with a call to usb_create_urb() it should be
+ *      cleaned up with a call to usb_free_urb() when the driver is finished
+ *      with it.
+ */
+void usb_free_urb(struct urb* urb)
+{
+#if URB_PRE_ALLOCATE!=1
+        if (urb)
+                forget2(urb);
+#endif
+}
+
+void usb_wait_urb_done(struct urb* urb, int timeout)
+{
+	usbdev_t *usb_dev = urb->dev;
+	if(hc_type[usb_dev->controller]==0x10) {
+		ohci_wait_urb_done(urb, timeout);
+	}
+	
+}
+
+
+int usb_submit_urb(struct urb *urb)
+{
+        if (urb && urb->dev) {
+#if 0
+		if(hc_type[urb->dev->controller] == 0x00) {
+                        return uhci_submit_urb(urb);
+                } else 
+#endif
+		if(hc_type[urb->dev->controller] == 0x10) {
+                	return ohci_submit_urb(urb);
+		} 
+#if 0
+		else if(hc_type[urb->dev->controller] == 0x20) {
+                        return ohci_submit_urb(urb);
+                }
+#endif
+		return 0;
+	}
+        else
+                return -ENODEV;
+}
+
+// Starts urb and waits for completion or timeout
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
+{ 
+        int status;
+        status = usb_submit_urb(urb);
+
+//for OHCI We will check the BLF and CLF, because HC after processing all td list, it will clear the BLF and CLF
+	usb_wait_urb_done(urb, timeout);
+//Add by LYH to call complete function
+	if(urb->complete!=0) urb->complete(urb);
+
+        if (actual_length)
+                *actual_length = urb->actual_length;
+
+        usb_free_urb(urb);
+        return status;
+}
+// returns status (negative) or length (positive)
+int usb_internal_control_msg(struct usbdev *usb_dev, unsigned int pipe,
+                            struct usb_ctrlrequest *cmd,  void *data, int len, int timeout, usb_complete_t complete)
+{
+        struct urb *urb;
+        int retv;
+        int length;
+
+        urb = usb_alloc_urb(usb_dev->controller);
+        if (!urb)
+                return -ENOMEM;
+
+        FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
+                   complete,0);
+
+        retv = usb_start_wait_urb(urb, timeout, &length);
+        if (retv < 0)
+                return retv;
+        else
+                return length;
+}
+int usb_control_msg_x(struct usbdev *dev, unsigned int pipe, u8 request, u8 requesttype,
+                         u16 value, u16 index, void *data, u16 size, int timeout, usb_complete_t complete)
+{
+        struct usb_ctrlrequest *dr;
+        int ret;
+	int controller = dev->controller;
+	ohci_t *ohci;
+
+#if URB_PRE_ALLOCATE!=1
+	dr = allot2(sizeof(struct usb_ctrlrequest), 0xf);
+        if (!dr) {
+		printf("usb_control_msg_x: dr allocate no MEM\n");
+                return -ENOMEM;
+	}
+#else
+        if(hc_type[controller] == 0x10) { //OHCI
+                ohci = &_ohci_x[controller];
+                dr = ohci->dr;
+        } else {
+		dr = NULL;
+	}
+	
+#endif
+
+        dr->bRequestType = requesttype;
+        dr->bRequest = request;
+        dr->wValue = cpu_to_le16p(&value);
+        dr->wIndex = cpu_to_le16p(&index);
+        dr->wLength = cpu_to_le16p(&size);
+
+        ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout, complete);
+
+#if URB_PRE_ALLOCATE!=1
+        forget2(dr);
+#endif
+
+        return ret;
+}
+int usb_bulk_msg_x(struct usbdev *usb_dev, unsigned int pipe,
+                        void *data, int len, int *actual_length, int timeout, usb_complete_t complete)
+{
+        struct urb *urb;
+
+        if (len < 0)
+                return -EINVAL;
+
+        urb=usb_alloc_urb(usb_dev->controller);
+        if (!urb)
+                return -ENOMEM;
+
+        FILL_BULK_URB(urb, usb_dev, pipe, data, len,
+                    complete, 0);
+
+        return usb_start_wait_urb(urb,timeout,actual_length);
+}
+

Added: trunk/filo/drivers/usb/usb.h
===================================================================
--- trunk/filo/drivers/usb/usb.h	                        (rev 0)
+++ trunk/filo/drivers/usb/usb.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,434 @@
+#ifndef _USB_H
+#define _USB_H
+
+#define forget2(x) free(x)
+#define allot2(size, align) memalign(align, size)
+
+#define URB_PRE_ALLOCATE 1
+
+#define uchar uint8_t
+#define ushort uint16_t
+#define EBUSY  1
+#define ENOMEM 12
+#define ENODEV 19
+#define EINVAL 22
+#define EINPROGRESS 115
+
+#define LINK_ADDR(x) ( virt_to_bus(x) >> 4)
+#define MEM_ADDR(x) (void *) (  bus_to_virt( ((unsigned int) (x)) <<4) )
+
+#define MAX_CONTROLLERS 4
+
+extern int num_controllers;
+
+extern uint32_t hc_base[];
+extern uint8_t hc_type[];
+
+// Some control message bmRequestType defines
+#define CTRL_DEVICE 0
+#define CONTROL_INTERFACE 1
+#define CONTROL_ENDPOINT 2
+#define CONTROL_OTHER 3
+#define CONTROL_RECIPIENT_MASK 0x1f
+
+#define CONTROL_TYPE_STD 0
+#define CONTROL_TYPE_CLASS 0x20
+#define CONTROL_CLASS_VENDOR 0x40
+#define CONTROL_CLASS_MASK 0x60
+
+#define CONTROL_OUT 0
+#define CONTROL_IN 0x80
+#define CONTROL_DIR_MASK 0x80
+
+// bRequest values
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+#define SET_FEATURE 3
+#define SET_ADDRESS 5
+
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+
+#define SYNC_FRAME 12
+
+// descriptor types
+#define DEVICE_DESC 1
+#define CONFIGURATION_DESC 2
+#define STRING_DESC 3
+#define INTERFACE_DESC 4
+#define ENDPOINT_DESC 5
+#define OTHERSPEED_DESC 7
+#define POWER_DESC 8
+
+
+typedef struct device_descriptor {
+        uchar bLength;
+        uchar type;
+        
+        uchar bcdVersion[2];
+        uchar Class;
+        uchar SubClass;
+        uchar protocol;
+        uchar max_packet;
+        
+        unsigned short idVendor;
+        unsigned short idProduct;
+        
+        uchar bcdDevice[2];
+        uchar iManufacturor;
+        uchar iProduct;
+        uchar iSerial;
+        uchar bNumConfig;
+} __attribute__((packed)) device_descriptor_t;
+
+#define GET_DESCRIPTOR 6
+
+typedef struct config_descriptor {
+        uchar bLength;
+        uchar type;
+
+        unsigned short wTotalLength;
+        uchar bNumInterfaces;
+        uchar bConfigurationValue;
+        uchar iConfiguration;
+
+        uchar bmAttributes;
+        uchar bMaxPower;
+} __attribute__((packed)) config_descriptor_t;
+
+typedef struct interface_descriptor {
+        uchar bLength;
+        uchar type;
+
+        uchar bInterfaceNumber;
+        uchar bAlternateSetting;
+
+        uchar bNumEndpoints;
+        uchar bInterfaceClass;
+        uchar bInterfaceSubClass;
+        uchar bInterfaceProtocol;
+        uchar iInterface;
+} __attribute__((packed)) interface_descriptor_t;
+
+typedef struct endpoint_descriptor {
+        uchar bLength;
+        uchar type;
+
+        uchar bEndpointAddress;
+        uchar bmAttributes;
+        unsigned short wMaxPacketSize;
+        uchar bInterval;
+} __attribute__((packed)) endpoint_descriptor_t;
+
+typedef struct ctrl_msg {
+        uchar bmRequestType;
+        uchar bRequest;
+        unsigned short wValue;
+        unsigned short wIndex;
+        unsigned short wLength;
+} __attribute__((packed)) ctrl_msg_t;
+
+// Some descriptors for hubs, will be moved later
+typedef struct hub_descriptor {
+        uchar bLength;
+        uchar type;
+
+        uchar bNbrPorts;
+        ushort wHubCharacteristics;
+        uchar bPwrOn2PwrGood;
+        uchar bHubCntrCurrent;
+
+        uchar DeviceRemovable;  // assume bNbrPorts <=8
+        uchar PortPwrCntrMask;
+} __attribute__((packed)) hub_descriptor_t;
+
+#define MAX_USB_DEV 127
+#define MAX_EP 8
+        
+typedef struct usbdev {
+        uint32_t        port;
+        uchar           address;
+        uchar           controller;
+        uchar           class;
+        uchar           subclass;
+        uchar           protocol;
+        uchar           bulk_in;
+        uchar           bulk_out;
+        uchar           interrupt;
+        uchar           lowspeed;
+        uint32_t        toggle2[2]; //For OHCI
+	uint32_t	halted[2];
+	uchar		toggle[MAX_EP]; //for UHCI
+        unsigned short  max_packet[MAX_EP];
+        void            *private;
+} usbdev_t;
+
+// I will use urb as transaction for OHCI to remember the td and ed
+
+struct urb;
+typedef void (*usb_complete_t)(struct urb *);
+
+struct urb
+{
+#if 0
+        spinlock_t lock;                // lock for the URB
+#endif
+        void *hcpriv;                   // private data for host controller
+#if 0
+        struct list_head urb_list;      // list pointer to all active urbs 
+        struct urb *next;               // pointer to next URB  
+#endif
+        struct usbdev *dev;         // pointer to associated USB device
+        unsigned int pipe;              // pipe information
+        int status;                     // returned status
+        unsigned int transfer_flags;    // USB_DISABLE_SPD | USB_ISO_ASAP | etc.
+        void *transfer_buffer;          // associated data buffer
+        void *transfer_dma;        // dma addr for transfer_buffer
+        int transfer_buffer_length;     // data buffer length
+        int actual_length;              // actual data buffer length    
+        int bandwidth;                  // bandwidth for this transfer request (INT or ISO)
+        unsigned char *setup_packet;    // setup packet (control only)
+        void * setup_dma;           // dma addr for setup_packet
+        //
+        int start_frame;                // start frame (iso/irq only)
+        int number_of_packets;          // number of packets in this request (iso)
+        int interval;                   // polling interval (irq only)
+        int error_count;                // number of errors in this transfer (iso only)
+        int timeout;                    // timeout (in jiffies)
+        //
+        void *context;                  // context for completion routine
+        usb_complete_t complete;        // pointer to completion routine
+        //
+#if 0
+        struct iso_packet_descriptor iso_frame_desc[0];
+#endif
+};
+
+typedef struct urb urb_t;
+
+/*
+ * urb->transfer_flags:
+ */
+#define USB_DISABLE_SPD         0x0001
+#define URB_SHORT_NOT_OK        USB_DISABLE_SPD
+#define USB_ISO_ASAP            0x0002
+#define USB_ASYNC_UNLINK        0x0008
+#define USB_QUEUE_BULK          0x0010
+#define USB_NO_FSBR             0x0020
+#define USB_ZERO_PACKET         0x0040  // Finish bulk OUTs always with zero length packet
+#define URB_NO_INTERRUPT        0x0080  /* HINT: no non-error interrupt needed */
+                                        /* ... less overhead for QUEUE_BULK */
+#define USB_TIMEOUT_KILLED      0x1000  // only set by HCD!
+
+
+struct usb_ctrlrequest {
+        u8 bRequestType;
+        u8 bRequest;
+        u16 wValue;
+        u16 wIndex;
+        u16 wLength;
+} __attribute__ ((packed));
+
+/*
+ * USB-status codes:
+ * USB_ST* maps to -E* and should go away in the future
+ */
+
+#define USB_ST_NOERROR          0
+#define USB_ST_CRC              (-EILSEQ)
+#define USB_ST_BITSTUFF         (-EPROTO)
+#define USB_ST_NORESPONSE       (-ETIMEDOUT)                    /* device not responding/handshaking */
+#define USB_ST_DATAOVERRUN      (-EOVERFLOW)
+#define USB_ST_DATAUNDERRUN     (-EREMOTEIO)
+#define USB_ST_BUFFEROVERRUN    (-ECOMM)
+#define USB_ST_BUFFERUNDERRUN   (-ENOSR)
+#define USB_ST_INTERNALERROR    (-EPROTO)                       /* unknown error */
+#define USB_ST_SHORT_PACKET     (-EREMOTEIO)
+#define USB_ST_PARTIAL_ERROR    (-EXDEV)                        /* ISO transfer only partially completed */
+#define USB_ST_URB_KILLED       (-ENOENT)                       /* URB canceled by user */
+#define USB_ST_URB_PENDING      (-EINPROGRESS)
+#define USB_ST_REMOVED          (-ENODEV)                       /* device not existing or removed */
+#define USB_ST_TIMEOUT          (-ETIMEDOUT)                    /* communication timed out, also in urb->status**/
+#define USB_ST_NOTSUPPORTED     (-ENOSYS)                       
+#define USB_ST_BANDWIDTH_ERROR  (-ENOSPC)                       /* too much bandwidth used */
+#define USB_ST_URB_INVALID_ERROR  (-EINVAL)                     /* invalid value/transfer type */
+#define USB_ST_URB_REQUEST_ERROR  (-ENXIO)                      /* invalid endpoint */
+#define USB_ST_STALL            (-EPIPE)                        /* pipe stalled, also in urb->status*/
+
+/**
+ * FILL_CONTROL_URB - macro to help initialize a control urb
+ * @URB: pointer to the urb to initialize.
+ * @DEV: pointer to the struct usb_device for this urb.
+ * @PIPE: the endpoint pipe
+ * @SETUP_PACKET: pointer to the setup_packet buffer
+ * @TRANSFER_BUFFER: pointer to the transfer buffer
+ * @BUFFER_LENGTH: length of the transfer buffer
+ * @COMPLETE: pointer to the usb_complete_t function
+ * @CONTEXT: what to set the urb context to.
+ *
+ * Initializes a control urb with the proper information needed to submit
+ * it to a device.  This macro is depreciated, the usb_fill_control_urb()
+ * function should be used instead.
+ */
+#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    do {\
+        (URB)->dev=DEV;\
+        (URB)->pipe=PIPE;\
+        (URB)->setup_packet=SETUP_PACKET;\
+        (URB)->transfer_buffer=TRANSFER_BUFFER;\
+        (URB)->transfer_buffer_length=BUFFER_LENGTH;\
+        (URB)->complete=COMPLETE;\
+        (URB)->context=CONTEXT;\
+    } while (0)
+
+
+/**
+ * FILL_BULK_URB - macro to help initialize a bulk urb
+ * @URB: pointer to the urb to initialize.
+ * @DEV: pointer to the struct usb_device for this urb.
+ * @PIPE: the endpoint pipe
+ * @TRANSFER_BUFFER: pointer to the transfer buffer
+ * @BUFFER_LENGTH: length of the transfer buffer
+ * @COMPLETE: pointer to the usb_complete_t function
+ * @CONTEXT: what to set the urb context to.
+ *
+ * Initializes a bulk urb with the proper information needed to submit it
+ * to a device.  This macro is depreciated, the usb_fill_bulk_urb()
+ * function should be used instead.
+ */
+#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    do {\
+        (URB)->dev=DEV;\
+        (URB)->pipe=PIPE;\
+        (URB)->transfer_buffer=TRANSFER_BUFFER;\
+        (URB)->transfer_buffer_length=BUFFER_LENGTH;\
+        (URB)->complete=COMPLETE;\
+        (URB)->context=CONTEXT;\
+    } while (0)
+
+
+/*
+ * USB directions
+ */
+#define USB_DIR_OUT                     0               /* to device */
+#define USB_DIR_IN                      0x80            /* to host */
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_UNDEF_0                 0xf0
+#define USB_PID_OUT                     0xe1
+#define USB_PID_ACK                     0xd2
+#define USB_PID_DATA0                   0xc3
+#define USB_PID_PING                    0xb4    /* USB 2.0 */
+#define USB_PID_SOF                     0xa5
+#define USB_PID_NYET                    0x96    /* USB 2.0 */
+#define USB_PID_DATA2                   0x87    /* USB 2.0 */
+#define USB_PID_SPLIT                   0x78    /* USB 2.0 */
+#define USB_PID_IN                      0x69
+#define USB_PID_NAK                     0x5a
+#define USB_PID_DATA1                   0x4b
+#define USB_PID_PREAMBLE                0x3c    /* Token mode */
+#define USB_PID_ERR                     0x3c    /* USB 2.0: handshake mode */
+#define USB_PID_SETUP                   0x2d
+#define USB_PID_STALL                   0x1e
+#define USB_PID_MDATA                   0x0f    /* USB 2.0 */
+
+#define PIPE_ISOCHRONOUS                0
+#define PIPE_INTERRUPT                  1
+#define PIPE_CONTROL                    2
+#define PIPE_BULK                       3
+
+#define usb_maxpacket(dev, pipe, out)   ((dev)->max_packet[usb_pipeendpoint(pipe)])
+#define usb_packetid(pipe)      (((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
+
+#define usb_pipeout(pipe)       ((((pipe) >> 7) & 1) ^ 1)
+#define usb_pipein(pipe)        (((pipe) >> 7) & 1)
+#define usb_pipedevice(pipe)    (((pipe) >> 8) & 0x7f)
+#define usb_pipe_endpdev(pipe)  (((pipe) >> 8) & 0x7ff)
+#define usb_pipeendpoint(pipe)  (((pipe) >> 15) & 0xf)
+#define usb_pipedata(pipe)      (((pipe) >> 19) & 1)
+#define usb_pipeslow(pipe)      (((pipe) >> 26) & 1)
+#define usb_pipetype(pipe)      (((pipe) >> 30) & 3)
+#define usb_pipeisoc(pipe)      (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
+#define usb_pipeint(pipe)       (usb_pipetype((pipe)) == PIPE_INTERRUPT)
+#define usb_pipecontrol(pipe)   (usb_pipetype((pipe)) == PIPE_CONTROL)
+#define usb_pipebulk(pipe)      (usb_pipetype((pipe)) == PIPE_BULK)
+
+#define PIPE_DEVEP_MASK         0x0007ff00
+
+
+/* The D0/D1 toggle bits */
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle2[out] >> (ep)) & 1)
+#define usb_dotoggle(dev, ep, out)  ((dev)->toggle2[out] ^= (1 << (ep)))
+static inline void usb_settoggle(struct usbdev *dev,
+                                 unsigned int ep,
+                                 unsigned int out,
+                                 int bit)
+{
+        dev->toggle2[out] &= ~(1 << ep);
+        dev->toggle2[out] |= bit << ep;
+}
+
+
+/* Endpoint halt control/status */
+#define usb_endpoint_out(ep_dir)        (((ep_dir >> 7) & 1) ^ 1)
+#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
+#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
+#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
+
+
+static inline unsigned int __create_pipe(usbdev_t *dev, unsigned int endpoint)
+{
+        return (dev->address << 8) | (endpoint << 15) |
+                ((dev->lowspeed == 1) << 26);
+}
+
+static inline unsigned int __default_pipe(struct usbdev *dev)
+{
+        return ((dev->lowspeed == 1) << 26);
+}
+
+/* Create various pipes... */
+#define usb_sndctrlpipe(dev,endpoint)   ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)   ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#if 0
+#define usb_sndisocpipe(dev,endpoint)   ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvisocpipe(dev,endpoint)   ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#endif
+#define usb_sndbulkpipe(dev,endpoint)   ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvbulkpipe(dev,endpoint)   ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#if 0
+#define usb_sndintpipe(dev,endpoint)    ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvintpipe(dev,endpoint)    ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#endif
+#define usb_snddefctrl(dev)             ((PIPE_CONTROL << 30) | __default_pipe(dev))
+#define usb_rcvdefctrl(dev)             ((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
+
+
+extern int next_usb_dev;
+extern usbdev_t usb_device[MAX_USB_DEV];
+
+void init_devices(void);
+void hci_init(void);
+int hc_init(pcidev_t dev);
+inline int set_address(uchar address);
+inline int clear_stall(uchar device, uchar endpoint);
+int poll_usb();
+int configure_device(uint32_t  port, uchar controller, unsigned int lowspeed);
+int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
+int usb_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex,
+        unsigned short wLength, void *data);
+
+int usb_control_msg_x(struct usbdev *dev, unsigned int pipe, u8 request, u8 requesttype,
+                         u16 value, u16 index, void *data, u16 size, int timeout, usb_complete_t complete);
+int usb_bulk_msg_x(struct usbdev *usb_dev, unsigned int pipe,
+                        void *data, int len, int *actual_length, int timeout, usb_complete_t complete);
+
+#endif

Added: trunk/filo/drivers/usb/usb_scsi_low.c
===================================================================
--- trunk/filo/drivers/usb/usb_scsi_low.c	                        (rev 0)
+++ trunk/filo/drivers/usb/usb_scsi_low.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+
+#define DPRINTF debug
+
+#define uchar uint8_t
+
+//#include "debug_x.h"
+#include "usb_scsi_low.h"
+
+int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
+
+#define SG_DXFER_FROM_DEV -3
+#define SG_DXFER_TO_DEV -2
+
+#define REQUEST_SENSE 0x03
+
+#define CBW_SIG 0x43425355
+
+typedef struct usb_cbw {
+	unsigned int 	signature;
+	unsigned int 	tag;
+	unsigned int 	transfer_len;	// this is exclusive of cbw and csw
+
+	uchar		res1:7;
+	uchar 		direction:1;	// 1 = device to host (read)
+	
+	uchar 		lun:4;
+	uchar		res:4;
+	
+	uchar		cbw_len:5;	// the length of the SCSI command
+	uchar		res3:3;
+
+	uchar		scsi_cmd[16];
+} __attribute__ ((packed)) usb_cbw_t;
+
+#define CSW_SIG 0x53425355
+
+typedef struct usb_csw {
+	unsigned int	signature;
+	unsigned int	tag;
+	unsigned int	residue;
+	uchar		status;
+} __attribute__ ((packed)) usb_csw_t;
+
+
+int scsi_command( uchar device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, unsigned char *sense_data, int sense_len)
+{
+	usb_cbw_t cbw;
+	usb_csw_t csw;
+	int ret;
+
+	memset(&cbw,0,sizeof(usb_cbw_t));
+	memset(&csw,0,sizeof(usb_csw_t));
+
+	cbw.signature = CBW_SIG;
+	cbw.tag = 777;
+
+	memcpy(cbw.scsi_cmd, cmd, cmd_len);
+	cbw.cbw_len = cmd_len;
+
+	if(direction == SG_DXFER_FROM_DEV)
+		cbw.direction=1;
+
+	cbw.transfer_len = data_len;
+	
+	ret = usb_bulk_transfer(device, 2, sizeof(cbw), (uchar *) &cbw);
+	if(ret<0){
+		DPRINTF("ERROR:Bulk write:\n");
+	}
+
+	if(data_len) {
+		if(cbw.direction) {
+			DPRINTF("scsi_command reading %d bytes\n", data_len);
+			ret = usb_bulk_transfer(device, 0x81, data_len, data);
+			DPRINTF("scsi_command read %d bytes\n", ret);
+			if(ret<0 || ret <data_len) {
+				DPRINTF("ERROR:Bulk read data ret = %d\n", ret);
+			}
+		} else {
+//			DPRINTF("scsi_command writing %u bytes\n", data_len);
+			ret = usb_bulk_transfer(device, 0x2, data_len, data);
+//			DPRINTF("scsi_command wrote %u bytes\n", ret);
+			if(ret<0) {
+				DPRINTF("ERROR:Bulk write data\n");
+			}
+		}
+	}
+
+//	DPRINTF("scsi_command fetching csw\n");
+	ret = usb_bulk_transfer(device, 0x81, sizeof(csw), (uchar *) &csw);
+//	DPRINTF("scsi_command csw is %d bytes\n", ret);
+	if(ret<0 || ret < sizeof(csw)) {
+		DPRINTF("ERROR: Bulk read CSW ret = %d\n", ret);
+		return(-1);
+	}
+
+	if(csw.status) {
+		DPRINTF("CSW: residue = %08x, status = %02x\n", csw.residue, csw.status);
+		DPRINTF("Getting sense data\n");
+		request_sense( device, sense_data, sense_len);
+		return(-csw.status);
+	}
+
+	return(data_len - csw.residue);
+}
+
+int request_sense( uchar device, unsigned char *sense_data, int len)
+{
+	usb_cbw_t cbw;
+	usb_csw_t csw;
+	int ret;
+
+	memset(&cbw,0,sizeof(usb_cbw_t));
+	memset(&csw,0,sizeof(usb_csw_t));
+
+	cbw.signature = CBW_SIG;
+	cbw.tag = 666;
+
+	cbw.scsi_cmd[0] = REQUEST_SENSE;
+	cbw.scsi_cmd[4] = len;
+	cbw.cbw_len = 6;
+	cbw.direction=1;
+	cbw.transfer_len = len;
+
+	ret = usb_bulk_transfer(device, 2, sizeof(usb_cbw_t), (uchar *) &cbw);
+	if(ret<0 || ret < sizeof(usb_cbw_t)) {
+		DPRINTF("ERROR: sense Bulk write ret = %d\n", ret);
+	}
+
+	ret = usb_bulk_transfer(device, 0x81, len, sense_data);
+	if(ret<0 || ret < len) {
+		DPRINTF("ERROR: sense Bulk read data ret = %d\n", ret);
+	}
+
+	ret = usb_bulk_transfer(device, 0x81, sizeof(usb_csw_t), (uchar *) &csw);
+	if(ret<0 || ret < sizeof(usb_csw_t)) {
+		DPRINTF("ERROR: sense Bulk read CSW ret = %d\n", ret);
+	}
+
+	return(-csw.status);
+}
+

Added: trunk/filo/drivers/usb/usb_scsi_low.h
===================================================================
--- trunk/filo/drivers/usb/usb_scsi_low.h	                        (rev 0)
+++ trunk/filo/drivers/usb/usb_scsi_low.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,10 @@
+#ifndef _USB_SCSI_LOW_H
+#define _USB_SCSI_LOW_H
+
+#define SG_DXFER_FROM_DEV -3
+#define SG_DXFER_TO_DEV -2
+
+int scsi_command( unsigned char device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, unsigned char *sense_data, int sense_len);
+int request_sense( unsigned char device, unsigned char *sense_data, int len);
+
+#endif

Added: trunk/filo/drivers/usb/usb_x.c
===================================================================
--- trunk/filo/drivers/usb/usb_x.c	                        (rev 0)
+++ trunk/filo/drivers/usb/usb_x.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ *
+ *
+ *	Copyright 2003 Steven James <pyro at linuxlabs.com> and
+ *	LinuxLabs http://www.linuxlabs.com
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#define DEBUG_THIS CONFIG_DEBUG_USB
+#include <debug.h>
+
+#define DPRINTF debug
+
+#include "usb.h"
+#include "scsi_cmds.h"
+
+struct usbdisk_info_t {
+        struct controller *ctrl;
+        uint16_t heads;
+        uint16_t cylinders;
+        uint16_t sectors_per_track;
+        uint8_t  model_number[41];
+        uint8_t  slave;
+        sector_t sectors;
+        int  address_mode;
+#define ADDRESS_MODE_CHS    0
+#define ADDRESS_MODE_LBA    1
+#define ADDRESS_MODE_LBA48  2
+#define ADDRESS_MODE_PACKET 3
+        uint32_t hw_sector_size;
+        unsigned drive_exists : 1;
+        unsigned slave_absent : 1;
+        unsigned removable : 1;
+	
+	unsigned char usb_device_address;	
+};
+
+struct usbdisk_info_t usbdisk_info;
+
+#define TEST 0
+
+#if TEST==1
+#include "usb_scsi_low.h"
+typedef struct partition_entry {
+        uchar boot_flag;
+
+        uchar chs[7];
+
+        unsigned int lba_start;
+        unsigned int lba_len;
+} __attribute__ ((packed)) partition_entry_t;
+
+typedef struct partition {
+        char loader[446];
+        partition_entry_t entry[4];
+        char sig[2];
+} __attribute__ ((packed)) partition_t;
+#endif
+
+int usb_probe(int drive)
+{
+	struct usbdisk_info_t *info = &usbdisk_info;
+#if TEST==1
+	partition_t part;
+	unsigned char sense_data[32];
+#endif
+        int i,res;
+        int error_count=100;
+
+	printf("LinuxLabs USB bootloader\n");
+
+//	outb( 0x30, 0x70);	// reset primary boot
+//	outb( 0xff, 0x71);
+	init_devices();
+	hci_init();
+
+	info->usb_device_address = 0;
+        // find first usb device
+
+        while(error_count && (res = poll_usb()))        // keep polling usb until no more devices are enumerated
+                if(res<0)
+                        if(!--error_count)
+                                printf("There is a USB device, but it won't init! This is a bad thing.\n");
+
+        for(i=0; i< next_usb_dev ; i++) {
+                if(usb_device[i].class == 0x08 && usb_device[i].subclass == 0x06 && usb_device[i].protocol == 0x50) {
+                        printf("Found USB block device %d\n", i);
+			if(drive==0) {
+                        	info->usb_device_address = i;
+				break;
+			}
+			drive--;
+                }
+        }
+	
+	if(info->usb_device_address == 0) return -1;
+
+	UnitReady(info->usb_device_address);
+
+#if TEST==1
+//Test
+        printf("Requesting initial sense data\n");
+        request_sense( info->usb_device_address, sense_data, 32);
+        PrintSense(sense_data, 32);
+
+        res = ll_read_block(info->usb_device_address, (uint8_t *)&part, 0, 1);
+
+        printf("ll_read_block returns %d\n", res);
+
+        res=-1;
+
+	debug("part address (phy) = %x, (virt) = %x\n", (uint32_t) virt_to_phys(&part), (uint32_t)&part);
+
+        for(i=0; i<4; i++) {
+                printf("%d: boot=%02x, start=%08x length=%08x\n",i,  part.entry[i].boot_flag, part.entry[i].lba_start, part.entry[i]
+.lba_len);
+                }
+
+
+#endif
+
+	return 0;
+}
+
+int usb_read(int drive, sector_t sector, void *buffer)
+{
+        struct usbdisk_info_t *info = &usbdisk_info;
+        int result;
+	int blocknum = sector;
+#if 0
+	int i;
+#endif
+//	printf("sector= %d\t", blocknum);
+	result = ll_read_block(info->usb_device_address, buffer,blocknum, 1);
+#if 0
+       for(i=0;i<128;i++) {
+             if((i%4)==0) printf("\n %08x:",i*4);
+             printf(" %08x ",(uint32_t)*((uint32_t *)buffer+i));
+       }
+#endif
+
+        if(result!=512) return -1;	
+
+	return 0;	
+}

Added: trunk/filo/drivers/via-sound.c
===================================================================
--- trunk/filo/drivers/via-sound.c	                        (rev 0)
+++ trunk/filo/drivers/via-sound.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,101 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <sound.h>
+#define DEBUG_THIS CONFIG_DEBUG_VIA_SOUND
+#include <debug.h>
+
+static u16 viasnd_iobase;
+
+static u16 via_ac97_read(u8 reg)
+{
+	u32 data;
+
+	data = ((u32) reg << 16) | (1 << 23) | (1 << 25);
+	outl(data, viasnd_iobase + 0x80);
+	for (;;) {
+		if ((inl(viasnd_iobase + 0x80) & ((1 << 24) | (1 << 25))) == (1 << 25))
+			break;
+	}
+	udelay(25);
+	data = inl(viasnd_iobase + 0x80);
+	outb(2, viasnd_iobase + 0x83);
+	if (((data & 0x7f0000) >> 16) != reg) {
+		printf("not our reg\n");
+		return 0;
+	}
+	return data & 0xffff;
+}
+
+static void via_ac97_write(u8 reg, u16 value)
+{
+	u32 data;
+
+	data = ((u32) reg << 16) | value;
+	outl(data, viasnd_iobase + 0x80);
+	udelay(10);
+
+	for (;;) {
+		if ((inl(viasnd_iobase + 0x80) & (1 << 24)) == 0)
+			break;
+	}
+}
+
+static void viasnd_stop(void)
+{
+	via_ac97_write(0x18, via_ac97_read(0x18) | 0x8000);	/* PCM mute */
+	outb(0x40, viasnd_iobase + 1);	/* SGD stop */
+}
+
+static int viasnd_init(pcidev_t dev)
+{
+	viasnd_iobase = pci_read_config16(dev, 0x10) & ~1;
+	debug("Found VIA sound device at %#x\n", viasnd_iobase);
+	pci_write_config8(dev, 0x41, 0xcc);	/* Enable AC link, VSR on, SGD on */
+	pci_write_config8(dev, 0x48, 0x05);	/* Disable FM interrupt */
+	outl(0, viasnd_iobase + 0x8c);	/* Disable codec GPI interrupt */
+
+	viasnd_stop();
+
+	via_ac97_write(0x2a, via_ac97_read(0x2a) | 1);	/* variable rate on */
+	via_ac97_write(0x26, 0x0100);	/* Input power down, all other power up */
+
+	via_ac97_write(0x18, 0x8808);	/* PCM out 0dB mute */
+	via_ac97_write(0x02, 0x0000);	/* Master 0dB unmute */
+	via_ac97_write(0x2c, 44100);	/* DAC rate */
+	debug("DAC rate set to %dHz\n", via_ac97_read(0x2c));
+
+#if 0
+	viasnd_sgtable.base = DMA_ADDR;
+	viasnd_sgtable.count = DMA_SIZE | (1 << 31);	/* EOL flag */
+	outl(virt_to_phys(&viasnd_sgtable), viasnd_iobase + 4);	/* SGD table pointer */
+	outb(0xb0, viasnd_iobase + 2);	/* Loop, 16-bit stereo, no interrupt */
+#endif
+
+	return 0;
+}
+
+static struct sound_ops viasnd_ops = {
+	.init = viasnd_init,
+	.stop = viasnd_stop,
+};
+
+const struct sound_driver viasnd_driver[] __sound_driver = {
+	{0x1106, 0x3058, &viasnd_ops},	/* VT82C686 AC97 Audio Controller */
+};

Added: trunk/filo/fs/Makefile.inc
===================================================================
--- trunk/filo/fs/Makefile.inc	                        (rev 0)
+++ trunk/filo/fs/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-y += fs/blockdev.o fs/vfs.o
+TARGETS-$(CONFIG_ELTORITO) += fs/eltorito.o
+TARGETS-$(CONFIG_FSYS_EXT2FS) += fs/fsys_ext2fs.o
+TARGETS-$(CONFIG_FSYS_FAT) += fs/fsys_fat.o
+TARGETS-$(CONFIG_FSYS_JFS) += fs/fsys_jfs.o
+TARGETS-$(CONFIG_FSYS_MINIX) += fs/fsys_minix.o
+TARGETS-$(CONFIG_FSYS_REISERFS) += fs/fsys_reiserfs.o
+TARGETS-$(CONFIG_FSYS_XFS) += fs/fsys_xfs.o
+TARGETS-$(CONFIG_FSYS_ISO9660) += fs/fsys_iso9660.o
+TARGETS-$(CONFIG_FSYS_CRAMFS) += fs/fsys_cramfs.o
+TARGETS-$(CONFIG_FSYS_CRAMFS) += fs/mini_inflate.o
+TARGETS-$(CONFIG_FSYS_SQUASHFS) += fs/fsys_squashfs.o
+TARGETS-$(CONFIG_FSYS_SQUASHFS) += fs/squashfs_zlib.o
+TARGETS-$(CONFIG_ARTEC_BOOT) += fs/fsys_aboot.o
+

Added: trunk/filo/fs/blockdev.c
===================================================================
--- trunk/filo/fs/blockdev.c	                        (rev 0)
+++ trunk/filo/fs/blockdev.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,467 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <fs.h>
+
+#define DEBUG_THIS CONFIG_DEBUG_BLOCKDEV
+#include <debug.h>
+
+#define NUM_CACHE		64
+
+static unsigned char buf_cache[NUM_CACHE][DEV_SECTOR_SIZE];
+static unsigned long cache_sect[NUM_CACHE];
+
+static char dev_name[256];
+
+int dev_type = -1;
+int dev_drive = -1;
+unsigned long part_start;
+unsigned long part_length;
+int using_devsize;
+
+static inline int has_pc_part_magic(unsigned char *sect)
+{
+    return sect[510]==0x55 && sect[511]==0xAA;
+}
+
+static inline int is_pc_extended_part(unsigned char type)
+{
+    return type==5 || type==0xf || type==0x85;
+}
+
+/* IBM-PC/MS-DOS style partitioning scheme */
+static int open_pc_partition(int part, unsigned long *start_p,
+	unsigned long *length_p)
+{
+    /* Layout of PC partition table */
+    struct pc_partition {
+	unsigned char boot;
+	unsigned char head;
+	unsigned char sector;
+	unsigned char cyl;
+	unsigned char type;
+	unsigned char e_head;
+	unsigned char e_sector;
+	unsigned char e_cyl;
+	unsigned char start_sect[4]; /* unaligned little endian */
+	unsigned char nr_sects[4]; /* ditto */
+    } *p;
+    unsigned char buf[DEV_SECTOR_SIZE];
+
+    /* PC partition probe */
+    if (!devread(0, 0, sizeof(buf), buf)) {
+	debug("device read failed\n");
+	return 0;
+    }
+    if (!has_pc_part_magic(buf)) {
+	debug("pc partition magic number not found\n");
+	//debug_hexdump(buf, DEV_SECTOR_SIZE);
+	return PARTITION_UNKNOWN;
+    }
+    p = (struct pc_partition *) (buf + 0x1be);
+    if (part < 4) {
+	/* Primary partition */
+	p += part;
+	if (p->type==0 || is_pc_extended_part(p->type)) {
+	    printf("Partition %d does not exist\n", part+1);
+	    return 0;
+	}
+	*start_p = get_le32(p->start_sect);
+	*length_p = get_le32(p->nr_sects);
+	return 1;
+    } else {
+	/* Extended partition */
+	int i;
+	int cur_part;
+	unsigned long ext_start, cur_table;
+	/* Search for the extended partition
+	 * which contains logical partitions */
+	for (i = 0; i < 4; i++) {
+	    if (is_pc_extended_part(p[i].type))
+		break;
+	}
+	if (i >= 4) {
+	    printf("Extended partition not found\n");
+	    return 0;
+	}
+	debug("Extended partition at %d\n", i+1);
+	/* Visit each logical partition labels */
+	ext_start = get_le32(p[i].start_sect);
+	cur_table = ext_start;
+	cur_part = 4;
+	for (;;) {
+	    debug("cur_part=%d at %lu\n", cur_part, cur_table);
+	    if (!devread(cur_table, 0, sizeof(buf), buf))
+		return 0;
+	    if (!has_pc_part_magic(buf)) {
+		debug("no magic\n");
+		break;
+	    }
+
+	    p = (struct pc_partition *) (buf + 0x1be);
+	    /* First entry is the logical partition */
+	    if (cur_part == part) {
+		if (p->type==0) {
+		    printf("Partition %d is empty\n", part+1);
+		    return 0;
+		}
+		*start_p = cur_table + get_le32(p->start_sect);
+		*length_p = get_le32(p->nr_sects);
+		return 1;
+	    }
+	    /* Second entry is link to next partition */
+	    if (!is_pc_extended_part(p[1].type)) {
+		debug("no link\n");
+		break;
+	    }
+	    cur_table = ext_start + get_le32(p[1].start_sect);
+
+	    cur_part++;
+	}
+	printf("Logical partition %d not exist\n", part+1);
+	return 0;
+    }
+}
+
+static void flush_cache(void)
+{
+    int i;
+    for (i = 0; i < NUM_CACHE; i++)
+	cache_sect[i] = (unsigned long) -1;
+}
+
+static int parse_device_name(const char *name, int *type, int *drive,
+	int *part, uint64_t *offset, uint64_t *length)
+{
+    *offset = *length = 0;
+
+    if (memcmp(name, "hd", 2) == 0) {
+	*type = DISK_IDE;
+	name += 2;
+	if (*name < 'a' || *name > 'z') {
+	    printf("Invalid drive\n");
+	    return 0;
+	}
+	*drive = *name - 'a';
+	name++;
+    } else if (memcmp(name, "ud", 2) == 0) {
+	*type = DISK_NEW_USB;
+	name += 2;
+        if (*name < 'a' || *name > 'z') {
+	    printf("Invalid drive\n");
+	    return 0;
+	}
+	*drive = *name - 'a';
+	name++;
+    } 
+	else if (memcmp(name, "flash", 5) == 0) {
+	*type = DISK_FLASH;
+	name += 5;
+        if (*name < 'a' || *name > 'z') {
+	    printf("Invalid flash chip\n");
+	    return 0;
+	}
+	*drive = *name - 'a';
+	name++;
+    } else if (memcmp(name, "mem", 3) == 0) {
+	*type = DISK_MEM;
+	name += 3;
+	*drive = 0;
+    } else {
+	printf("Unknown device type\n");
+	return 0;
+    }
+
+    *part = (int) simple_strtoull(name, (char **)&name, 0);
+
+    if (*name == '@') {
+	name++;
+	*offset = strtoull_with_suffix(name, (char **)&name, 0);
+	if (*name == ',')
+	    *length = strtoull_with_suffix(name+1, (char **)&name, 0);
+	debug("offset=%#Lx length=%#Lx\n", *offset, *length);
+    }
+
+    if (*name != '\0') {
+	printf("Can't parse device name\n");
+	return 0;
+    }
+
+    return 1;
+}
+
+int devopen(const char *name, int *reopen)
+{
+    int type, drive, part;
+    uint64_t offset, length;
+    uint32_t disk_size = 0;
+
+    /* Don't re-open the device that's already open */
+    if (strcmp(name, dev_name) == 0 && dev_type != -1 ) {
+	debug("already open\n");
+	*reopen = 1;
+	return 1;
+    }
+    *reopen = 0;
+
+    if (!parse_device_name(name, &type, &drive, &part, &offset, &length)) {
+	debug("failed to parse device name: %s\n", name);
+	return 0;
+    }
+    
+    /* If we have another dev open, close it first! */
+    if (dev_type != type && dev_type != -1)
+    	devclose();
+
+    /* Do simple sanity check first */
+    if (offset & DEV_SECTOR_MASK) {
+	printf("Device offset must be multiple of %d\n", DEV_SECTOR_SIZE);
+	return 0;
+    }
+    if (length & DEV_SECTOR_MASK) {
+	printf("WARNING: length is rounded up to multiple of %d\n", DEV_SECTOR_SIZE);
+	length = (length + DEV_SECTOR_MASK) & ~DEV_SECTOR_MASK;
+    }
+
+    switch (type) {
+#ifdef CONFIG_IDE_DISK
+    case DISK_IDE:
+	if (ide_probe(drive) != 0) {
+	    debug("failed to open ide\n");
+	    return 0;
+	}
+	disk_size = (uint32_t) -1; /* FIXME */
+	break;
+#endif
+
+#ifdef CONFIG_USB_NEW_DISK
+    case DISK_NEW_USB:
+        if (usb_new_probe(drive) != 0) {
+            debug("failed to open usb\n");
+            return 0;
+        }
+        disk_size = (uint32_t) -1; /* FIXME */
+        break;
+#endif
+
+#ifdef CONFIG_USB_DISK
+    case DISK_USB:
+        if (usb_probe(drive) != 0) {
+            debug("failed to open usb\n");
+            return 0;
+        }
+        disk_size = (uint32_t) -1; /* FIXME */
+        break;
+#endif
+
+#ifdef CONFIG_FLASH_DISK
+	case DISK_FLASH:
+		if(flash_probe(drive) != 0)
+		{
+			debug("failed to open flash\n");
+			return 0;
+		}
+		disk_size = (uint32_t) -1; /* FIXME */
+		break;
+#endif
+
+	case DISK_MEM:
+	disk_size = 1 << (32 - DEV_SECTOR_BITS); /* 4GB/512-byte */
+	break;
+
+	default:
+		printf("Unknown device type %d\n", type);
+	return 0;
+    }
+
+    if (dev_type != type || dev_drive != drive)
+	flush_cache();
+
+    /* start with whole disk */
+    dev_type = type;
+    dev_drive = drive;
+    part_start = 0;
+    part_length = disk_size;
+    using_devsize = 1;
+
+    if (part != 0) {
+	/* partition is specified */
+	int ret;
+	ret = open_pc_partition(part - 1, &part_start, &part_length);
+	if (ret == PARTITION_UNKNOWN) {
+	    ret = open_eltorito_image(part - 1, &part_start, &part_length);
+	    if (ret == PARTITION_UNKNOWN) {
+		printf("Unrecognized partitioning scheme\n");
+		return 0;
+	    }
+	}
+	if (ret == 0) {
+	    debug("can't open partition %d\n", part);
+	    return 0;
+	}
+
+	debug("Partition %d start %lu length %lu\n", part,
+		part_start, part_length);
+    }
+
+    if (offset) {
+	if (offset >= (uint64_t) part_length << DEV_SECTOR_BITS) {
+	    printf("Device offset is too high\n");
+	    return 0;
+	}
+	part_start += offset >> DEV_SECTOR_BITS;
+	part_length -= offset >> DEV_SECTOR_BITS;
+	debug("after offset: start %lu, length %lu\n", part_start, part_length);
+    }
+
+    if (length) {
+	if (length > (uint64_t) part_length << DEV_SECTOR_BITS) {
+	    printf("Specified length exceeds the size of device\n");
+	    return 0;
+	}
+	part_length = length >> DEV_SECTOR_BITS;
+	debug("after length: length %lu\n", part_length);
+	using_devsize = 0;
+    }
+
+    strncpy(dev_name, name, sizeof(dev_name)-1);
+
+    return 1;
+}
+
+void devclose(void)
+{
+#ifdef CONFIG_FLASH_DISK
+	/* Try to close NAND if it was left open */
+	if (dev_type == DISK_FLASH)
+		NAND_close();
+#endif
+	
+	dev_type = -1;
+}
+
+/* Read a sector from opened device with simple/stupid buffer cache */
+static void *read_sector(unsigned long sector)
+{
+    unsigned int hash;
+    void *buf;
+
+    /* If reading memory, just return the memory as the buffer */
+    if (dev_type == DISK_MEM) {
+	unsigned long phys = sector << DEV_SECTOR_BITS;
+	//debug("mem: %#lx\n", phys);
+	return phys_to_virt(phys);
+    }
+
+    /* Search in the cache */
+    hash = sector % NUM_CACHE;
+    buf = buf_cache[hash];
+    if (cache_sect[hash] != sector) {
+	cache_sect[hash] = (unsigned long) -1;
+	switch (dev_type) {
+#ifdef CONFIG_IDE_DISK
+	case DISK_IDE:
+	    if (ide_read(dev_drive, sector, buf) != 0)
+		goto readerr;
+	    break;
+#endif
+#ifdef CONFIG_USB_NEW_DISK
+	case DISK_NEW_USB:
+		if (usb_new_read(dev_drive, sector, buf) != 0)
+		goto readerr;
+		break;
+#endif
+#ifdef CONFIG_USB_DISK
+	case DISK_USB:
+		if (usb_read(dev_drive, sector, buf) != 0)
+		goto readerr;
+		break;
+#endif
+
+#ifdef CONFIG_FLASH_DISK
+	case DISK_FLASH:
+		if (flash_read(dev_drive, sector, buf) != 0)
+			return 0;
+		break;
+#endif
+
+	default:
+	    printf("read_sector: device not open\n");
+	    return 0;
+	}
+	cache_sect[hash] = sector;
+    }
+    return buf;
+
+readerr:
+    printf("Disk read error dev=%d drive=%d sector=%lu\n",
+	    dev_type, dev_drive, sector);
+    dev_name[0] = '\0'; /* force re-open the device next time */
+    return 0;
+}
+
+int devread(unsigned long sector, unsigned long byte_offset,
+	unsigned long byte_len, void *buf)
+{
+    char *sector_buffer;
+    char *dest = buf;
+    unsigned long len;
+
+    sector += byte_offset >> 9;
+    byte_offset &= 0x1ff;
+
+    if (sector + ((byte_len + 0x1ff) >> 9) > part_length) {
+	printf("Attempt to read out of device/partition\n");
+	debug("sector=%lu part_length=%lu byte_len=%lu\n",
+		sector, part_length, byte_len);
+	return 0;
+    }
+
+    while (byte_len > 0) {
+	sector_buffer = read_sector(part_start + sector);
+	if (!sector_buffer) {
+	    debug("read sector failed\n");
+	    return 0;
+	}
+	len = 512 - byte_offset;
+	if (len > byte_len)
+	    len = byte_len;
+	memcpy(dest, sector_buffer + byte_offset, len);
+	sector++;
+	byte_offset = 0;
+	byte_len -= len;
+	dest += len;
+    }
+    return 1;
+}
+
+uint32_t get_le32(const unsigned char *p)
+{
+	return ((unsigned int) p[0] << 0)
+		| ((unsigned int) p[1] << 8)
+		| ((unsigned int) p[2] << 16)
+		| ((unsigned int) p[3] << 24);
+}
+
+uint16_t get_le16(const unsigned char *p)
+{
+	return ((unsigned int) p[0] << 0) 
+		| ((unsigned int) p[1] << 8);
+}
+

Added: trunk/filo/fs/eltorito.c
===================================================================
--- trunk/filo/fs/eltorito.c	                        (rev 0)
+++ trunk/filo/fs/eltorito.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,160 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#define DEBUG_THIS CONFIG_DEBUG_ELTORITO
+#include <debug.h>
+
+#define ELTORITO_PLATFORM_X86 0
+#define ELTORITO_PLATFORM_PPC 1
+#define ELTORITO_PLATFORM_MAC 2
+#include <arch/eltorito.h>
+
+#ifndef ELTORITO_PLATFORM
+#error "ELTORITO_PLATFORM is not defined for this arch"
+#endif
+
+/* El Torito boot record at sector 0x11 of bootable CD */
+struct boot_record {
+    uint8_t ind;
+    uint8_t iso_id[5];
+    uint8_t version;
+    uint8_t boot_id[32];
+    uint8_t reserved[32];
+    uint8_t catalog_offset[4];
+};
+
+/* First entry of the catalog */
+struct validation_entry {
+    uint8_t header_id;
+    uint8_t platform;
+    uint8_t reserved[2];
+    uint8_t id[24];
+    uint8_t checksum[2];
+    uint8_t key55;
+    uint8_t keyAA;
+};
+
+/* Initial/Default catalog entry */
+struct default_entry {
+    uint8_t boot_id;
+    uint8_t media_type;
+#define MEDIA_MASK 0x0f
+#define MEDIA_NOEMU 0
+#define MEDIA_1200_FD 1
+#define MEDIA_1440_FD 2
+#define MEDIA_2880_FD 3
+#define MEDIA_HD 4
+    uint8_t load_segment[2];
+    uint8_t system_type;
+    uint8_t reserved;
+    uint8_t sector_count[2];
+    uint8_t start_sector[4];
+    uint8_t reserved_too[20];
+};
+
+/* Find El-Torito boot disk image */
+int open_eltorito_image(int part, unsigned long *offset_p,
+	unsigned long *length_p)
+{
+    struct boot_record boot_record;
+    uint32_t cat_offset;
+    uint8_t catalog[2048];
+    struct validation_entry *ve;
+    int i, sum;
+    struct default_entry *de;
+
+    /* We always use 512-byte "soft sector", but
+     * El-Torito uses 2048-byte CD-ROM sector */
+
+    /* Boot Record is at sector 0x11 */
+    if (!devread(0x11<<2, 0, sizeof boot_record, &boot_record))
+	return 0;
+
+    if (boot_record.ind != 0
+	    || memcmp(boot_record.iso_id, "CD001", 5) != 0
+	    || memcmp(boot_record.boot_id, "EL TORITO SPECIFICATION", 23)
+		!= 0) {
+	debug("No El-Torito signature\n");
+	return PARTITION_UNKNOWN;
+    }
+
+    if (part != 0) {
+	printf("El-Torito entries other than Initial/Default is not supported\n");
+	return 0;
+    }
+
+    cat_offset = get_le32(boot_record.catalog_offset);
+    debug("El-Torito boot catalog at sector %u\n", cat_offset);
+    if (!devread(cat_offset<<2, 0, 2048, catalog))
+	return 0;
+
+    /* Validate the catalog */
+    ve = (void *) catalog;
+    //debug_hexdump(ve, sizeof *ve);
+    if (ve->header_id != 1 || ve->key55 != 0x55 || ve->keyAA != 0xAA) {
+	printf("Invalid El Torito boot catalog\n");
+	return 0;
+    }
+    /* All words must sum up to zero */
+    sum = 0;
+    for (i = 0; i < sizeof(*ve); i += 2)
+	sum += get_le16(&catalog[i]);
+    sum &= 0xffff;
+    if (sum != 0) {
+	printf("El Torito boot catalog verify failed\n");
+	return 0;
+    }
+    debug("id='%.*s'\n", sizeof ve->id, ve->id);
+
+    /* Platform check is warning only, because we won't directly execute
+     * the image. Just mounting it should be safe. */
+    if (ve->platform != ELTORITO_PLATFORM)
+	printf("WARNING: Boot disk for different platform: %d\n", ve->platform);
+
+    /* Just support initial/default entry for now */
+    de = (void *) (ve + 1);
+    if (de->boot_id != 0x88)
+	printf("WARNING: Default boot entry is not bootable\n");
+
+    switch (de->media_type & MEDIA_MASK) {
+    case MEDIA_NOEMU:
+	printf("Disc doesn't use boot disk emulation\n");
+	return 0;
+    case MEDIA_1200_FD:
+	*length_p = 1200*1024/512;
+	break;
+    case MEDIA_1440_FD:
+	*length_p = 1440*1024/512;
+	break;
+    case MEDIA_2880_FD:
+	*length_p = 2880*1024/512;
+	break;
+    case MEDIA_HD:
+	/* FIXME: read partition table and return first partition.
+	 * Spec states emulation HD has only one partition and it must
+	 * be the first partition */
+	printf("Disc uses hard disk emulation - not supported\n");
+	return 0;
+    }
+    *offset_p = get_le32(de->start_sector) << 2;
+    debug("offset=%#lx length=%#lx\n", *offset_p, *length_p);
+
+    return 1;
+}

Added: trunk/filo/fs/fat.h
===================================================================
--- trunk/filo/fs/fat.h	                        (rev 0)
+++ trunk/filo/fs/fat.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,100 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2001  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.
+ */
+
+
+/*
+ *  Defines for the FAT BIOS Parameter Block (embedded in the first block
+ *  of the partition.
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/* Note that some shorts are not aligned, and must therefore
+ * be declared as array of two bytes.
+ */
+struct fat_bpb {
+	__s8	ignored[3];	/* Boot strap short or near jump */
+	__s8	system_id[8];	/* Name - can be used to special case
+				   partition manager volumes */
+	__u8	bytes_per_sect[2];	/* bytes per logical sector */
+	__u8	sects_per_clust;/* sectors/cluster */
+	__u8	reserved_sects[2];	/* reserved sectors */
+	__u8	num_fats;	/* number of FATs */
+	__u8	dir_entries[2];	/* root directory entries */
+	__u8	short_sectors[2];	/* number of sectors */
+	__u8	media;		/* media code (unused) */
+	__u16	fat_length;	/* sectors/FAT */
+	__u16	secs_track;	/* sectors per track */
+	__u16	heads;		/* number of heads */
+	__u32	hidden;		/* hidden sectors (unused) */
+	__u32	long_sectors;	/* number of sectors (if short_sectors == 0) */
+
+	/* The following fields are only used by FAT32 */
+	__u32	fat32_length;	/* sectors/FAT */
+	__u16	flags;		/* bit 8: fat mirroring, low 4: active fat */
+	__u8	version[2];	/* major, minor filesystem version */
+	__u32	root_cluster;	/* first cluster in root directory */
+	__u16	info_sector;	/* filesystem info sector */
+	__u16	backup_boot;	/* backup boot sector */
+	__u16	reserved2[6];	/* Unused */
+};
+
+#define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
+
+/*
+ *  Defines how to differentiate a 12-bit and 16-bit FAT.
+ */
+
+#define FAT_MAX_12BIT_CLUST       4087	/* 4085 + 2 */
+
+/*
+ *  Defines for the file "attribute" byte
+ */
+
+#define FAT_ATTRIB_OK_MASK        0x37
+#define FAT_ATTRIB_NOT_OK_MASK    0xC8
+#define FAT_ATTRIB_DIR            0x10
+#define FAT_ATTRIB_LONGNAME       0x0F
+
+/*
+ *  Defines for FAT directory entries
+ */
+
+#define FAT_DIRENTRY_LENGTH       32
+
+#define FAT_DIRENTRY_ATTRIB(entry) \
+  (*((unsigned char *) (entry+11)))
+#define FAT_DIRENTRY_VALID(entry) \
+  ( ((*((unsigned char *) entry)) != 0) \
+    && ((*((unsigned char *) entry)) != 0xE5) \
+    && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
+#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
+  ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
+#define FAT_DIRENTRY_FILELENGTH(entry) \
+  (*((unsigned long *) (entry+28)))
+
+#define FAT_LONGDIR_ID(entry) \
+  (*((unsigned char *) (entry)))
+#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
+  (*((unsigned char *) (entry+13)))

Added: trunk/filo/fs/filesys.h
===================================================================
--- trunk/filo/fs/filesys.h	                        (rev 0)
+++ trunk/filo/fs/filesys.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,285 @@
+/* GRUB compatibility header */
+
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2003   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 <libpayload.h>
+#include <config.h>
+#include <fs.h>
+
+/* This disables some portion of code */
+#define STAGE1_5 1
+
+#if defined(__i386__)
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+static inline unsigned long ffz (unsigned long word)
+{
+	__asm__ ("bsfl %1,%0"
+			: "=r" (word)
+			: "r" (~word));
+  return word;
+}
+#elif defined(__ppc__)
+static inline unsigned long __ilog2(unsigned long x)
+{
+	unsigned long lz;
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	return 31 - lz;
+}
+
+static inline unsigned long ffz(unsigned long x)
+{       
+	if ((x = ~x) == 0)
+		return 32;
+		        
+	return __ilog2(x & -x);
+}
+#endif
+
+#define log2(n) ffz(~(n))
+
+
+static inline int 
+substring (const char *s1, const char *s2)
+{
+  while (*s1 == *s2)
+    {
+      /* The strings match exactly. */
+      if (! *(s1++))
+	return 0;
+      s2 ++;
+    }
+
+  /* S1 is a substring of S2. */
+  if (*s1 == 0)
+    return -1;
+
+  /* S1 isn't a substring. */
+  return 1;
+}
+
+#define grub_memmove memmove
+
+#define MAXINT 0x7fffffff
+
+/* This is only used by fsys_* to determine if it's hard disk. If it is,
+ * they try to guess filesystem type by partition type. I guess it is 
+ * not necessory, so hardcoded to 0 (first floppy) --ts1 */
+#define current_drive 0
+
+/* Ditto */
+#define current_slice 0
+
+extern unsigned long part_start;
+extern unsigned long part_length;
+extern int filepos;
+extern int filemax;
+extern int fsmax;
+
+/* Error codes (descriptions are in common.c) */
+typedef enum
+{
+  ERR_NONE = 0,
+  ERR_BAD_FILENAME,
+  ERR_BAD_FILETYPE,
+  ERR_BAD_GZIP_DATA,
+  ERR_BAD_GZIP_HEADER,
+  ERR_BAD_PART_TABLE,
+  ERR_BAD_VERSION,
+  ERR_BELOW_1MB,
+  ERR_BOOT_COMMAND,
+  ERR_BOOT_FAILURE,
+  ERR_BOOT_FEATURES,
+  ERR_DEV_FORMAT,
+  ERR_DEV_VALUES,
+  ERR_EXEC_FORMAT,
+  ERR_FILELENGTH,
+  ERR_FILE_NOT_FOUND,
+  ERR_FSYS_CORRUPT,
+  ERR_FSYS_MOUNT,
+  ERR_GEOM,
+  ERR_NEED_LX_KERNEL,
+  ERR_NEED_MB_KERNEL,
+  ERR_NO_DISK,
+  ERR_NO_PART,
+  ERR_NUMBER_PARSING,
+  ERR_OUTSIDE_PART,
+  ERR_READ,
+  ERR_SYMLINK_LOOP,
+  ERR_UNRECOGNIZED,
+  ERR_WONT_FIT,
+  ERR_WRITE,
+  ERR_BAD_ARGUMENT,
+  ERR_UNALIGNED,
+  ERR_PRIVILEGED,
+  ERR_DEV_NEED_INIT,
+  ERR_NO_DISK_SPACE,
+  ERR_NUMBER_OVERFLOW,
+
+  MAX_ERR_NUM
+} grub_error_t;
+
+extern grub_error_t errnum;
+
+#define grub_open file_open
+#define grub_read file_read
+#define grub_seek file_seek
+#define grub_close file_close
+
+/* instrumentation variables */
+/* (Not used in FILO) */
+extern void (*disk_read_hook) (int, int, int);
+extern void (*disk_read_func) (int, int, int);
+
+#define FSYS_BUFLEN 0x8000
+extern char FSYS_BUF[FSYS_BUFLEN];
+
+#define print_possibilities 0
+
+#define SECTOR_SIZE 512
+#define SECTOR_BITS 9
+
+#ifdef CONFIG_FSYS_FAT
+int fat_mount (void);
+int fat_read (char *buf, int len);
+int fat_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_EXT2FS
+int ext2fs_mount (void);
+int ext2fs_read (char *buf, int len);
+int ext2fs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_MINIX
+int minix_mount (void);
+int minix_read (char *buf, int len);
+int minix_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_REISERFS
+int reiserfs_mount (void);
+int reiserfs_read (char *buf, int len);
+int reiserfs_dir (char *dirname);
+int reiserfs_embed (int *start_sector, int needed_sectors);
+#endif
+
+#ifdef CONFIG_FSYS_JFS
+int jfs_mount (void);
+int jfs_read (char *buf, int len);
+int jfs_dir (char *dirname);
+int jfs_embed (int *start_sector, int needed_sectors);
+#endif
+
+#ifdef CONFIG_FSYS_XFS
+int xfs_mount (void);
+int xfs_read (char *buf, int len);
+int xfs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_ISO9660
+int iso9660_mount (void);
+int iso9660_read (char *buf, int len);
+int iso9660_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_CRAMFS
+int cramfs_mount (void);
+int cramfs_read (char *buf, int len);
+int cramfs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_SQUASHFS
+int squashfs_mount (void);
+int squashfs_read (char *buf, int len);
+int squashfs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_ARTEC_BOOT
+int aboot_mount (void);
+int aboot_read (char *buf, int len);
+int aboot_dir (char *dirname);
+#endif
+
+/* This is not a flag actually, but used as if it were a flag.  */
+#define PC_SLICE_TYPE_HIDDEN_FLAG	0x10
+
+#define PC_SLICE_TYPE_NONE         	0
+#define PC_SLICE_TYPE_FAT12        	1
+#define PC_SLICE_TYPE_FAT16_LT32M  	4
+#define PC_SLICE_TYPE_EXTENDED     	5
+#define PC_SLICE_TYPE_FAT16_GT32M  	6
+#define PC_SLICE_TYPE_FAT32		0xb
+#define PC_SLICE_TYPE_FAT32_LBA		0xc
+#define PC_SLICE_TYPE_FAT16_LBA		0xe
+#define PC_SLICE_TYPE_WIN95_EXTENDED	0xf
+#define PC_SLICE_TYPE_EZD        	0x55
+#define PC_SLICE_TYPE_MINIX		0x80
+#define PC_SLICE_TYPE_LINUX_MINIX	0x81
+#define PC_SLICE_TYPE_EXT2FS       	0x83
+#define PC_SLICE_TYPE_LINUX_EXTENDED	0x85
+#define PC_SLICE_TYPE_VSTAFS		0x9e
+#define PC_SLICE_TYPE_DELL_UTIL		0xde
+#define PC_SLICE_TYPE_LINUX_RAID	0xfd
+
+/* For convinience.  */
+/* Check if TYPE is a FAT partition type. Clear the hidden flag before
+   the check, to allow the user to mount a hidden partition in GRUB.  */
+#define IS_PC_SLICE_TYPE_FAT(type)	\
+  ({ int _type = (type) & ~PC_SLICE_TYPE_HIDDEN_FLAG; \
+     _type == PC_SLICE_TYPE_FAT12 \
+     || _type == PC_SLICE_TYPE_FAT16_LT32M \
+     || _type == PC_SLICE_TYPE_FAT16_GT32M \
+     || _type == PC_SLICE_TYPE_FAT16_LBA \
+     || _type == PC_SLICE_TYPE_FAT32 \
+     || _type == PC_SLICE_TYPE_FAT32_LBA \
+     || _type == PC_SLICE_TYPE_DELL_UTIL; })
+
+#define IS_PC_SLICE_TYPE_MINIX(type) \
+  (((type) == PC_SLICE_TYPE_MINIX)	\
+   || ((type) == PC_SLICE_TYPE_LINUX_MINIX))
+
+#define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0
+
+/* possible values for the *BSD-style partition type */
+#define	FS_UNUSED	0	/* unused */
+#define	FS_SWAP		1	/* swap */
+#define	FS_V6		2	/* Sixth Edition */
+#define	FS_V7		3	/* Seventh Edition */
+#define	FS_SYSV		4	/* System V */
+#define	FS_V71K		5	/* V7 with 1K blocks (4.1, 2.9) */
+#define	FS_V8		6	/* Eighth Edition, 4K blocks */
+#define	FS_BSDFFS	7	/* 4.2BSD fast file system */
+#define	FS_MSDOS	8	/* MSDOS file system */
+#define	FS_BSDLFS	9	/* 4.4BSD log-structured file system */
+#define	FS_OTHER	10	/* in use, but unknown/unsupported */
+#define	FS_HPFS		11	/* OS/2 high-performance file system */
+#define	FS_ISO9660	12	/* ISO 9660, normally CD-ROM */
+#define	FS_BOOT		13	/* partition contains bootstrap */
+#define	FS_ADOS		14	/* AmigaDOS fast file system */
+#define	FS_HFS		15	/* Macintosh HFS */
+#define	FS_FILECORE	16	/* Acorn Filecore Filing System */
+#define	FS_EXT2FS	17	/* Linux Extended 2 file system */
+
+#if CONFIG_DEBUG_FSYS_EXT2FS
+#define E2DEBUG 
+#endif

Added: trunk/filo/fs/fsys_aboot.c
===================================================================
--- trunk/filo/fs/fsys_aboot.c	                        (rev 0)
+++ trunk/filo/fs/fsys_aboot.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ *
+ *	FILO Artecboot Virtual File System
+ *
+ *	Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ *	Artec Design LLC http://www.artecdesign.ee
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <fs.h>
+
+#include "artecboot.h"
+#include "shared.h"
+#include "filesys.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_ARTECBOOT
+#include <debug.h>
+
+static ARTECBOOT_HEADER bootHdr;
+static uint32_t fileStart = 0;
+
+// device read helper, calls the block device read function
+// returns number of bytes parsed fthe stream 
+
+int aboot_devread(char* pData, int nSize)
+{
+	char sectorBuf[DEV_SECTOR_SIZE];
+	uint32_t len, total=0;
+	int failCount = 128;
+
+	uint32_t sector = (fileStart + filepos) >> DEV_SECTOR_BITS;
+	uint32_t byteOffset = (fileStart + filepos) & DEV_SECTOR_MASK;
+	
+	debug("file start %x, sector %x, offset %d\n", fileStart, sector, byteOffset);
+
+	if (sector + ((nSize + DEV_SECTOR_MASK) >> DEV_SECTOR_BITS) > part_length)
+	{
+		printf("Error: read outside of device device/partition\n");
+		debug("sector=%lu, partition size=%lu, read length=%lu\n",
+			(unsigned long)sector, 	(unsigned long)part_length, (unsigned long)nSize);
+		return 0;
+    }
+
+    while (nSize > 0)
+	{
+		if (!devread(sector, 0, DEV_SECTOR_SIZE, sectorBuf))
+		{
+			debug("sector 0x%x read failed\n", sector);
+			// do not abort immediately, try some more
+			if((failCount --) == 0) return 0;
+			
+			sector ++;	// try the next sector
+			total += DEV_SECTOR_SIZE;
+			continue;
+		}
+
+		len = SECTOR_SIZE - byteOffset;
+		if (len > nSize)
+			len = nSize;
+		memcpy(pData, sectorBuf + byteOffset, len);
+		
+		sector ++;
+		byteOffset = 0;
+		
+		nSize -= len;
+		pData += len;
+		total += len;
+    }
+
+	// return number of bytes read from the stream
+    return total;
+}
+
+int aboot_mount(void)
+{
+	debug("Mounting Artecboot VFS...\n");
+	// clear the boot header
+	memset(&bootHdr, 0, sizeof(bootHdr));
+	
+	fileStart = 0;
+	filepos = 0;
+	
+	// now read out the boot header
+	if(aboot_devread((char*)&bootHdr, sizeof(ARTECBOOT_HEADER)) < sizeof(ARTECBOOT_HEADER))
+	{
+		debug("Boot error: failed reading the boot image header\n");
+		return 0;
+	}
+
+	// check whether the flash data is valid at all
+	if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC)
+	{
+		debug("No Artecboot signature found, aborting\n");
+		return 0;
+	}
+
+	// check the version number
+	if(bootHdr.bootVersion > CURRENT_VERSION)
+	{
+		debug("Boot error: incompatible version number: %x\n", bootHdr.bootVersion);
+		return 0;
+	}
+
+	// align the partition length to the sector size
+	part_length = ((bootHdr.imageSize - 1) >> DEV_SECTOR_BITS) + 1;
+	return 1;
+}
+
+int aboot_read(char *buf, int len)
+{
+	int read;
+	// sanity check
+	if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) return 0;
+	debug("reading %d bytes to %x...\n", len, (unsigned int)buf);
+
+	read = aboot_devread(buf, len);
+	filepos += read;	// advance current position
+	
+	debug("read %d bytes, pos %x\n", read, filepos);
+	
+	// returned length may be greater than requested size because of skipped bad blocks
+	if(read >= len) return len;
+	return 0;
+}
+
+int aboot_dir(char *dirname)
+{
+	int nRet = 0;
+	// sanity check
+	if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC) return 0;
+	
+	// we can only recognize certain hardcoded filenames
+	if(!strcmp(dirname, ABOOT_FILE_HEADER))
+	{
+		filepos = 0;
+		fileStart = 0;
+		filemax = sizeof(ARTECBOOT_HEADER);
+		nRet = 1;
+	}
+	else if(!strcmp(dirname, ABOOT_FILE_KERNEL))
+	{
+		filepos = 0;
+		fileStart = bootHdr.kernelStart;
+		filemax = bootHdr.kernelSize;
+		nRet = 1;
+	}
+	else if(!strcmp(dirname, ABOOT_FILE_INITRD))
+	{
+		filepos = 0;
+		fileStart = bootHdr.initrdStart;
+		filemax = bootHdr.initrdSize;
+		nRet = 1;
+	}
+	else
+	{
+		// unknown file
+		filepos = 0;
+		filemax = 0;
+		nRet = 0;
+	}
+	
+	debug("open file: %s, size %d, dev start %x\n", dirname, filemax, fileStart);
+	return nRet;
+}
+

Added: trunk/filo/fs/fsys_cramfs.c
===================================================================
--- trunk/filo/fs/fsys_cramfs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_cramfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,464 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002 Russ Dill <address at hidden>
+ *
+ *  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.
+ */
+ 
+/* fsys_minix.c used as a skeleton, cramfs code in kernel used as
+ * documentation and some code */
+
+#include "shared.h"
+#include "filesys.h"
+#include "mini_inflate.h"
+
+#ifdef CONFIG_DEBUG_CRAMFS
+# define debug_cramfs(str, args...) printf(str, ## args)
+#else
+# define debug_cramfs(str, args...) do {;} while(0)
+#endif
+
+#if 0
+/* include/asm-i386/type.h */
+typedef __signed__ char s8;
+typedef unsigned char u8;
+typedef __signed__ short s16;
+typedef unsigned short u16;
+typedef __signed__ int s32;
+typedef unsigned int u32;
+#endif
+
+#define BLOCK_SIZE 	SECTOR_SIZE
+
+#define CRAMFS_MAGIC		0x28cd3d45	/* some random number */
+#define CRAMFS_SIGNATURE	"Compressed ROMFS"
+
+/*
+ * Reasonably terse representation of the inode data.
+ */
+struct cramfs_inode {
+	u32 mode:16, uid:16;
+	/* SIZE for device files is i_rdev */
+	u32 size:24, gid:8;
+	/* NAMELEN is the length of the file name, divided by 4 and
+           rounded up.  (cramfs doesn't support hard links.) */
+	/* OFFSET: For symlinks and non-empty regular files, this
+	   contains the offset (divided by 4) of the file data in
+	   compressed form (starting with an array of block pointers;
+	   see README).  For non-empty directories it is the offset
+	   (divided by 4) of the inode of the first file in that
+	   directory.  For anything else, offset is zero. */
+	u32 namelen:6, offset:26;
+};
+
+/*
+ * Superblock information at the beginning of the FS.
+ */
+struct cramfs_super {
+	u32 magic;		/* 0x28cd3d45 - random number */
+	u32 size;		/* Not used.  mkcramfs currently
+                                   writes a constant 1<<16 here. */
+	u32 flags;		/* 0 */
+	u32 future;		/* 0 */
+	u8 signature[16];	/* "Compressed ROMFS" */
+	u8 fsid[16];		/* random number */
+	u8 name[16];		/* user-defined name */
+	struct cramfs_inode root;	/* Root inode data */
+};
+
+/*
+ * Valid values in super.flags.  Currently we refuse to mount
+ * if (flags & ~CRAMFS_SUPPORTED_FLAGS).  Maybe that should be
+ * changed to test super.future instead.
+ */
+#define CRAMFS_SUPPORTED_FLAGS (0xff)
+
+/* Uncompression interfaces to the underlying zlib */
+int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
+int cramfs_uncompress_init(void);
+int cramfs_uncompress_exit(void);
+
+/* linux/stat.h */
+#define S_IFMT  00170000
+#define S_IFLNK  0120000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
+
+#define PATH_MAX                1024	/* include/linux/limits.h */
+#define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
+
+#define NAMELEN_MAX (((1 << (6 + 1)) - 1) << 2) /* 252 */
+
+#define CRAMFS_BLOCK (4096L)
+#define CRAMFS_MAX_BLOCKS ((1 << 24) / CRAMFS_BLOCK)
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+struct cramfs_buf {
+	struct cramfs_super super;
+	struct cramfs_inode inode;
+	char name[NAMELEN_MAX + 1];
+	u32 block_ptrs[CRAMFS_MAX_BLOCKS];
+	char data[CRAMFS_BLOCK * 2];
+	char temp[CRAMFS_BLOCK];
+	/* menu.lst is read 1 byte at a time, try to aleviate *
+	 * the performance problem */
+	long cached_block;		/* the uncompressed block in cramfs_buf->data */
+	long decompressed_block;	/* the decompressed block in cramfs_buf->temp */
+	long decompressed_size;		/* the size that is got decompressed to */
+};
+
+static struct cramfs_buf *cramfs_buf;
+
+#define CRAMFS_ROOT_INO (sizeof(struct cramfs_super) - sizeof(struct cramfs_inode))
+
+#ifndef STAGE1_5
+#define cramfs_memcmp grub_memcmp
+#define cramfs_strlen grub_strlen
+#else
+int
+cramfs_memcmp (const char *s1, const char *s2, int n)
+{
+  while (n)
+    {
+      if (*s1 < *s2)
+	return -1;
+      else if (*s1 > *s2)
+	return 1;
+      s1++;
+      s2++;
+      n--;
+    }
+
+  return 0;
+}
+
+
+int
+cramfs_strlen (const char *str)
+{
+  int len = 0;
+
+  while (*str++)
+    len++;
+
+  return len;
+}
+
+
+#endif
+/* check filesystem types and read superblock into memory buffer */
+int 
+cramfs_mount(void)
+{	
+	debug_cramfs("attempting to mount a cramfs\n");
+
+	cramfs_buf = (struct cramfs_buf *) FSYS_BUF;
+	if (part_length < sizeof(struct cramfs_super) / BLOCK_SIZE) {
+		debug_cramfs("partition too short\n");
+       		return 0;
+	}
+	  
+	if (!devread(0, 0, sizeof(struct cramfs_super), (char *) &cramfs_buf->super)) {
+		debug_cramfs("cannot read superblock\n");
+		return 0;
+	}
+  
+	if (cramfs_buf->super.magic != CRAMFS_MAGIC) {
+		debug_cramfs("magic does not match\n");
+		return 0;
+	}
+	
+	if (cramfs_memcmp(CRAMFS_SIGNATURE, cramfs_buf->super.signature, 16)) {
+		debug_cramfs("signiture does not match\n");
+		return 0;
+	}
+
+	if (cramfs_buf->super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
+		debug_cramfs("unsupported flags\n");
+		return 0;
+	}
+
+	if (!S_ISDIR(cramfs_buf->super.root.mode)) {
+		debug_cramfs("root is not a directory\n");
+		return 0;
+	}
+	
+	debug_cramfs("cramfs mounted\n");
+	return 1;
+}
+
+/* read from INODE into BUF */
+int
+cramfs_read (char *buf, int len)
+{
+	u32 start;
+	u32 end;
+	int nblocks;
+	int block;
+	int block_len;
+	int ret = 0;
+	long size = 0;
+	long devread_ret;
+
+	nblocks = (cramfs_buf->inode.size - 1) / CRAMFS_BLOCK + 1;
+	block = filepos / CRAMFS_BLOCK;
+
+	if (!devread(0, cramfs_buf->inode.offset << 2, nblocks << 2, (char *) &cramfs_buf->block_ptrs))
+		return 0;
+
+	if (block)
+		start = cramfs_buf->block_ptrs[block - 1];
+	else start = (cramfs_buf->inode.offset + nblocks) << 2;
+	
+	debug_cramfs("reading a file of %d blocks starting at offset %d (block %d)\n", nblocks, start, block);
+	debug_cramfs("filepos is %d\n", filepos);
+
+	while (block < nblocks && len > 0) {
+		end = cramfs_buf->block_ptrs[block];
+		block_len = end - start;
+		
+		debug_cramfs("reading to %d bytes at block %d at offset %d, %d bytes...",
+			len, block, start, block_len);
+		if (cramfs_buf->cached_block != block) {
+			disk_read_func = disk_read_hook;
+			devread_ret = devread(0, start, block_len, cramfs_buf->data);
+			disk_read_func = NULL;
+			cramfs_buf->cached_block = block;
+		} else debug_cramfs("%d was cached...", block);
+		
+		if (!ret && (filepos % CRAMFS_BLOCK)) {
+			/* its the first read, and its not block aligned */
+			debug_cramfs("doing a non-aligned decompression of block %d at offset %d\n", 
+					block, filepos % CRAMFS_BLOCK);
+			if (cramfs_buf->decompressed_block != block) {
+				size = decompress_block(cramfs_buf->temp, cramfs_buf->data + 2, memcpy);
+				cramfs_buf->decompressed_size = size;
+				cramfs_buf->decompressed_block = block;
+			} else size = cramfs_buf->decompressed_size;
+			size -= filepos % CRAMFS_BLOCK;
+			if (size > len) size = len;
+			if (size > 0)
+				memcpy(buf, cramfs_buf->temp + (filepos % CRAMFS_BLOCK), size);		
+		} else  {
+			/* just another full block read */
+			size = decompress_block(buf, cramfs_buf->data + 2, memcpy);
+		}
+		if (size < 0) {
+			debug_cramfs("error in decomp (error %d)\n", size);
+			cramfs_buf->cached_block = -1;
+			cramfs_buf->decompressed_block = -1;
+			return 0;
+		}
+		debug_cramfs("decomp`d %d bytes\n", size);
+		buf += size;
+		len -= size;
+		filepos += size;
+		ret += size;
+
+		block++;
+		start = end;
+	}
+
+	return ret;
+}
+
+/* preconditions: cramfs_mount already executed, therefore supblk in buffer
+     known as SUPERBLOCK
+   returns: 0 if error, nonzero iff we were able to find the file successfully
+   postconditions: on a nonzero return, buffer known as INODE contains the
+     inode of the file we were trying to look up
+   side effects: none yet  */
+int
+cramfs_dir(char *dirname)
+{
+	int str_chk;			     /* used ot hold the results of a string
+					        compare */
+
+	u32 current_ino;  		     /* inode info for current_ino */
+	u32 parent_ino;
+
+	char linkbuf[PATH_MAX];	  	   /* buffer for following sym-links */
+	int link_count = 0;
+	
+	char *rest;
+	char ch;
+	
+	u32 dir_size;			     /* size of this directory */
+	u32 off;			     /* offset of this directory */
+	u32 loc;			     /* location within a directory */
+	
+	int namelen;
+
+  /* loop invariants:
+     current_ino = inode to lookup
+     dirname = pointer to filename component we are cur looking up within
+     the directory known pointed to by current_ino (if any) */
+
+#ifdef CONFIG_DEBUG_CRAMFS
+	printf("\n");
+#endif  
+
+	current_ino = CRAMFS_ROOT_INO;
+	parent_ino = current_ino;
+
+	for (;;) {
+		debug_cramfs("inode offset %d, dirname %s\n", current_ino, dirname);
+
+		if (!devread(0, current_ino, sizeof(struct cramfs_inode), (char *) &cramfs_buf->inode))
+			return 0;
+
+		/* If we've got a symbolic link, then chase it. */
+		if (S_ISLNK(cramfs_buf->inode.mode)) {
+			int len;
+
+			if (++link_count > MAX_LINK_COUNT) {
+				errnum = ERR_SYMLINK_LOOP;
+				return 0;
+			}
+			debug_cramfs("S_ISLNK(%s)\n", dirname);
+
+			/* Find out how long our remaining name is. */
+			len = 0;
+			while (dirname[len] && !isspace(dirname[len]))
+				len++;
+
+			/* Get the symlink size. */
+			filemax = cramfs_buf->inode.size;
+			if (filemax + len > sizeof(linkbuf) - 2) {
+				errnum = ERR_FILELENGTH;
+				return 0;
+			}
+
+			if (len) {
+				/* Copy the remaining name to the end of the symlink data.
+				   Note that DIRNAME and LINKBUF may overlap! */
+				memmove(linkbuf + filemax, dirname, len);
+			}
+			linkbuf[filemax + len] = '\0';
+
+			/* Read the necessary blocks, and reset the file pointer. */
+			len = grub_read(linkbuf, filemax);
+			filepos = 0;
+			if (!len)
+				return 0;
+
+			debug_cramfs("symlink=%s\n", linkbuf);
+
+			dirname = linkbuf;
+			if (*dirname == '/') {
+				/* It's an absolute link, so look it up in root. */
+				current_ino = CRAMFS_ROOT_INO;
+				parent_ino = current_ino;
+			} else {
+				/* Relative, so look it up in our parent directory. */
+				current_ino = parent_ino;
+			}
+
+			/* Try again using the new name. */
+			continue;
+		}
+
+		/* If end of filename, INODE points to the file's inode */
+		if (!*dirname || isspace(*dirname)) {
+			if (!S_ISREG(cramfs_buf->inode.mode)) {
+				errnum = ERR_BAD_FILETYPE;
+				return 0;
+			}
+			filemax = cramfs_buf->inode.size;
+			debug_cramfs("file found, size %d\n", filemax);
+			cramfs_buf->cached_block = -1;
+			cramfs_buf->decompressed_block = -1;
+			return 1;
+		}
+
+		/* else we have to traverse a directory */
+		parent_ino = current_ino;
+
+		/* skip over slashes */
+		while (*dirname == '/') dirname++;
+
+		/* if this isn't a directory of sufficient size to hold our file, 
+		   abort */
+		if (!(cramfs_buf->inode.size) || !S_ISDIR(cramfs_buf->inode.mode)) {
+			errnum = ERR_BAD_FILETYPE;
+			return 0;
+		}
+
+		/* skip to next slash or end of filename (space) */
+		for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++);
+
+		/* look through this directory and find the next filename component */
+		/* invariant: rest points to slash after the next filename component */
+		*rest = 0;
+		loc = 0;
+		off = cramfs_buf->inode.offset << 2;
+		dir_size = cramfs_buf->inode.size;
+
+		do {
+			debug_cramfs("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
+
+			/* if our location/byte offset into the directory exceeds the size,
+			   give up */
+			if (loc >= dir_size) {
+				if (print_possibilities < 0) {
+#if 0
+					putchar ('\n');
+#endif
+				} else {
+					errnum = ERR_FILE_NOT_FOUND;
+					*rest = ch;
+				}
+				return (print_possibilities < 0);
+			}
+			
+			current_ino = off + loc;
+			
+			/* read in this inode */
+			if (!devread(0, current_ino, sizeof(struct cramfs_inode), (char *) &cramfs_buf->inode))
+				return 0;
+			if (!devread(0, current_ino + sizeof(struct cramfs_inode), 
+					cramfs_buf->inode.namelen << 2, cramfs_buf->name))
+				return 0;
+			cramfs_buf->name[cramfs_buf->inode.namelen << 2] = '\0';
+			namelen = cramfs_strlen(cramfs_buf->name);
+			
+			/* advance loc prematurely to next on-disk directory entry  */
+			loc += sizeof(struct cramfs_inode) + (cramfs_buf->inode.namelen << 2);
+
+			debug_cramfs("directory entry index=%d\n", loc + off);
+			debug_cramfs("entry=%s\n", cramfs_buf->name);
+
+			str_chk = substring(dirname, cramfs_buf->name);
+
+#ifndef STAGE1_5
+			if (print_possibilities && ch != '/'
+				&& (!*dirname || str_chk <= 0)) {
+				if (print_possibilities > 0)
+					print_possibilities = -print_possibilities;
+				print_a_completion(cramfs_buf->name);
+			}
+# endif
+
+
+		} while (str_chk || (print_possibilities && ch != '/'));
+
+		*(dirname = rest) = ch;
+	}
+	/* never get here */
+}

Added: trunk/filo/fs/fsys_ext2fs.c
===================================================================
--- trunk/filo/fs/fsys_ext2fs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_ext2fs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,811 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999, 2001, 2003  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 "shared.h"
+#include "filesys.h"
+
+static int mapblock1, mapblock2;
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE 1024		/* initial block size for superblock read */
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/*
+ * Constants relative to the data blocks, from ext2_fs.h
+ */
+#define EXT2_NDIR_BLOCKS                12
+#define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
+
+/* include/linux/ext2_fs.h */
+struct ext2_super_block
+  {
+    __u32 s_inodes_count;	/* Inodes count */
+    __u32 s_blocks_count;	/* Blocks count */
+    __u32 s_r_blocks_count;	/* Reserved blocks count */
+    __u32 s_free_blocks_count;	/* Free blocks count */
+    __u32 s_free_inodes_count;	/* Free inodes count */
+    __u32 s_first_data_block;	/* First Data Block */
+    __u32 s_log_block_size;	/* Block size */
+    __s32 s_log_frag_size;	/* Fragment size */
+    __u32 s_blocks_per_group;	/* # Blocks per group */
+    __u32 s_frags_per_group;	/* # Fragments per group */
+    __u32 s_inodes_per_group;	/* # Inodes per group */
+    __u32 s_mtime;		/* Mount time */
+    __u32 s_wtime;		/* Write time */
+    __u16 s_mnt_count;		/* Mount count */
+    __s16 s_max_mnt_count;	/* Maximal mount count */
+    __u16 s_magic;		/* Magic signature */
+    __u16 s_state;		/* File system state */
+    __u16 s_errors;		/* Behaviour when detecting errors */
+    __u16 s_pad;
+    __u32 s_lastcheck;		/* time of last check */
+    __u32 s_checkinterval;	/* max. time between checks */
+    __u32 s_creator_os;		/* OS */
+    __u32 s_rev_level;		/* Revision level */
+    __u16 s_def_resuid;		/* Default uid for reserved blocks */
+    __u16 s_def_resgid;		/* Default gid for reserved blocks */
+    __u32 s_reserved[235];	/* Padding to the end of the block */
+  };
+
+struct ext2_group_desc
+  {
+    __u32 bg_block_bitmap;	/* Blocks bitmap block */
+    __u32 bg_inode_bitmap;	/* Inodes bitmap block */
+    __u32 bg_inode_table;	/* Inodes table block */
+    __u16 bg_free_blocks_count;	/* Free blocks count */
+    __u16 bg_free_inodes_count;	/* Free inodes count */
+    __u16 bg_used_dirs_count;	/* Directories count */
+    __u16 bg_pad;
+    __u32 bg_reserved[3];
+  };
+
+struct ext2_inode
+  {
+    __u16 i_mode;		/* File mode */
+    __u16 i_uid;		/* Owner Uid */
+    __u32 i_size;		/* 4: Size in bytes */
+    __u32 i_atime;		/* Access time */
+    __u32 i_ctime;		/* 12: Creation time */
+    __u32 i_mtime;		/* Modification time */
+    __u32 i_dtime;		/* 20: Deletion Time */
+    __u16 i_gid;		/* Group Id */
+    __u16 i_links_count;	/* 24: Links count */
+    __u32 i_blocks;		/* Blocks count */
+    __u32 i_flags;		/* 32: File flags */
+    union
+      {
+	struct
+	  {
+	    __u32 l_i_reserved1;
+	  }
+	linux1;
+	struct
+	  {
+	    __u32 h_i_translator;
+	  }
+	hurd1;
+	struct
+	  {
+	    __u32 m_i_reserved1;
+	  }
+	masix1;
+      }
+    osd1;			/* OS dependent 1 */
+    __u32 i_block[EXT2_N_BLOCKS];	/* 40: Pointers to blocks */
+    __u32 i_version;		/* File version (for NFS) */
+    __u32 i_file_acl;		/* File ACL */
+    __u32 i_dir_acl;		/* Directory ACL */
+    __u32 i_faddr;		/* Fragment address */
+    union
+      {
+	struct
+	  {
+	    __u8 l_i_frag;	/* Fragment number */
+	    __u8 l_i_fsize;	/* Fragment size */
+	    __u16 i_pad1;
+	    __u32 l_i_reserved2[2];
+	  }
+	linux2;
+	struct
+	  {
+	    __u8 h_i_frag;	/* Fragment number */
+	    __u8 h_i_fsize;	/* Fragment size */
+	    __u16 h_i_mode_high;
+	    __u16 h_i_uid_high;
+	    __u16 h_i_gid_high;
+	    __u32 h_i_author;
+	  }
+	hurd2;
+	struct
+	  {
+	    __u8 m_i_frag;	/* Fragment number */
+	    __u8 m_i_fsize;	/* Fragment size */
+	    __u16 m_pad1;
+	    __u32 m_i_reserved2[2];
+	  }
+	masix2;
+      }
+    osd2;			/* OS dependent 2 */
+  };
+
+/* linux/limits.h */
+#define NAME_MAX         255	/* # chars in a file name */
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/ext2fs.h */
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry
+  {
+    __u32 inode;		/* Inode number */
+    __u16 rec_len;		/* Directory entry length */
+    __u8 name_len;		/* Name length */
+    __u8 file_type;
+    char name[EXT2_NAME_LEN];	/* File name */
+  };
+
+/* linux/ext2fs.h */
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD                    4
+#define EXT2_DIR_ROUND                  (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
+                                         ~EXT2_DIR_ROUND)
+
+
+/* ext2/super.c */
+#define EXT2_SUPER_MAGIC      0xEF53	/* include/linux/ext2_fs.h */
+#define EXT2_ROOT_INO              2	/* include/linux/ext2_fs.h */
+#define PATH_MAX                1024	/* include/linux/limits.h */
+#define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+    ((struct ext2_super_block *)(FSYS_BUF))
+#define GROUP_DESC \
+    ((struct ext2_group_desc *) \
+     ((char *)SUPERBLOCK + sizeof(struct ext2_super_block)))
+#define INODE \
+    ((struct ext2_inode *)((char *)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+#define DATABLOCK1 \
+    ((char *)((char *)INODE + sizeof(struct ext2_inode)))
+#define DATABLOCK2 \
+    ((char *)((char *)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+
+/* linux/ext2_fs.h */
+#define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_ADDR_PER_BLOCK_BITS(s)	(log2(EXT2_ADDR_PER_BLOCK(s)))
+
+/* linux/ext2_fs.h */
+#define EXT2_BLOCK_SIZE_BITS(s)        (le32_to_cpu((s)->s_log_block_size) + 10)
+/* kind of from ext2/super.c */
+#define EXT2_BLOCK_SIZE(s)	(1 << EXT2_BLOCK_SIZE_BITS(s))
+/* linux/ext2fs.h */
+#define EXT2_DESC_PER_BLOCK(s) \
+     (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+/* linux/stat.h */
+#define S_IFMT  00170000
+#define S_IFLNK  0120000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
+
+#ifdef E2DEBUG
+void
+dump_super(struct ext2_super_block *s)
+{
+    printf(" superblock 0x%x:\n", s);
+    printf("  inodes=%d\n", le32_to_cpu(s->s_inodes_count));
+    printf("  blocks=%d\n", le32_to_cpu(s->s_blocks_count));
+    printf("  reserved=%d\n", le32_to_cpu(s->s_r_blocks_count));
+    printf("  i_free=%d\n", le32_to_cpu(s->s_free_inodes_count));
+    printf("  b_free=%d\n", le32_to_cpu(s->s_free_blocks_count));
+    printf("  first=%d\n", le32_to_cpu(s->s_first_data_block));
+    printf("  log_b_size=%d, b_size=%d\n", le32_to_cpu(s->s_log_block_size), EXT2_BLOCK_SIZE(s));
+    printf("  log_f_size=%d\n", le32_to_cpu(s->s_log_frag_size));
+    printf("  bpg=%d\n", le32_to_cpu(s->s_blocks_per_group));
+    printf("  fpg=%d\n", le32_to_cpu(s->s_frags_per_group));
+    printf("  ipg=%d\n", le32_to_cpu(s->s_inodes_per_group));
+}
+
+void
+dump_group_desc(struct ext2_group_desc *g)
+{
+    printf(" group_desc 0x%x:\n", g);
+    printf("  b_bmap block=%d\n", le32_to_cpu(g->bg_block_bitmap));
+    printf("  i_bmap block=%d\n", le32_to_cpu(g->bg_inode_bitmap));
+    printf("  i_tab block=%d\n", le32_to_cpu(g->bg_inode_table));
+    printf("  free_blks=%d\n", le16_to_cpu(g->bg_free_blocks_count));
+    printf("  free_inodes=%d\n", le16_to_cpu(g->bg_free_inodes_count));
+    printf("  used_dirs=%d\n", le16_to_cpu(g->bg_used_dirs_count));
+}
+
+void
+dump_inode(struct ext2_inode *i)
+{
+    printf(" inode 0x%x:\n", i);
+    printf("  mode=%o\n", le16_to_cpu(i->i_mode));
+    printf("  uid=%d\n", le16_to_cpu(i->i_uid));
+    printf("  gid=%d\n", le16_to_cpu(i->i_gid));
+    printf("  size=%d\n", le32_to_cpu(i->i_size));
+    printf("  atime=%d\n", le32_to_cpu(i->i_atime));
+    printf("  ctime=%d\n", le32_to_cpu(i->i_ctime));
+    printf("  mtime=%d\n", le32_to_cpu(i->i_mtime));
+    printf("  dtime=%d\n", le32_to_cpu(i->i_dtime));
+    printf("  links=%d\n", le16_to_cpu(i->i_links_count));
+    printf("  blocks=%d\n", le32_to_cpu(i->i_blocks));
+    printf("  flags=%d\n", le32_to_cpu(i->i_flags));
+}
+
+void 
+dump_inode_data(unsigned char *inode, int len)
+{
+  static char hexdigit[] = "0123456789abcdef";
+  unsigned char *i;
+  for (i = inode;
+       i < (inode + len);
+       i++)
+    {
+      printf ("%c", hexdigit[*i >> 4]);
+      printf ("%c", hexdigit[*i % 16]);
+      if (!((i + 1 - inode) % 16))
+	{
+	  printf ("\n");
+	}
+      else
+	{
+	  printf (" ");
+	}
+    }
+}
+#endif
+
+/* check filesystem types and read superblock into memory buffer */
+int
+ext2fs_mount (void)
+{
+  int retval = 1;
+
+  if ((((current_drive & 0x80) || (current_slice != 0))
+       && (current_slice != PC_SLICE_TYPE_EXT2FS)
+       && (current_slice != PC_SLICE_TYPE_LINUX_RAID)
+       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
+       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
+      || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE))
+      || !devread (SBLOCK, 0, sizeof (struct ext2_super_block),
+		   (char *) SUPERBLOCK)
+      || le16_to_cpu(SUPERBLOCK->s_magic) != EXT2_SUPER_MAGIC)
+      retval = 0;
+
+  return retval;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+ext2_rdfsb (int fsblock, void * buffer)
+{
+#ifdef E2DEBUG
+  printf ("ext2_rdfsb: fsblock %d, devblock %d, size %d\n", fsblock, 
+	  fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 
+	  EXT2_BLOCK_SIZE (SUPERBLOCK));
+#endif /* E2DEBUG */
+  return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
+		  EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
+}
+
+/* from
+  ext2/inode.c:ext2_bmap()
+*/
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+   a physical block (the location in the file system) via an inode. */
+static int
+ext2fs_block_map (int logical_block)
+{
+
+#ifdef E2DEBUG
+  printf ("ext2fs_block_map(%d)\n", logical_block);
+#endif /* E2DEBUG */
+
+  /* if it is directly pointed to by the inode, return that physical addr */
+  if (logical_block < EXT2_NDIR_BLOCKS)
+    {
+#ifdef E2DEBUG
+      printf ("ext2fs_block_map: returning %d\n", le32_to_cpu(INODE->i_block[logical_block]));
+#endif /* E2DEBUG */
+      return le32_to_cpu(INODE->i_block[logical_block]);
+    }
+  /* else */
+  logical_block -= EXT2_NDIR_BLOCKS;
+  /* try the indirect block */
+  if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+    {
+      if (mapblock1 != 1
+	  && !ext2_rdfsb (le32_to_cpu(INODE->i_block[EXT2_IND_BLOCK]), DATABLOCK1))
+	{
+	  errnum = ERR_FSYS_CORRUPT;
+	  return -1;
+	}
+      mapblock1 = 1;
+      return le32_to_cpu(((__u32 *) DATABLOCK1)[logical_block]);
+    }
+  /* else */
+  logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
+  /* now try the double indirect block */
+  if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
+    {
+      int bnum;
+      if (mapblock1 != 2
+	  && !ext2_rdfsb (le32_to_cpu(INODE->i_block[EXT2_DIND_BLOCK]), DATABLOCK1))
+	{
+	  errnum = ERR_FSYS_CORRUPT;
+	  return -1;
+	}
+      mapblock1 = 2;
+      if ((bnum = le32_to_cpu(((__u32 *) DATABLOCK1)
+		   [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
+	  != mapblock2
+	  && !ext2_rdfsb (bnum, DATABLOCK2))
+	{
+	  errnum = ERR_FSYS_CORRUPT;
+	  return -1;
+	}
+      mapblock2 = bnum;
+      return le32_to_cpu(((__u32 *) DATABLOCK2)
+	[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]);
+    }
+  /* else */
+  mapblock2 = -1;
+  logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
+  if (mapblock1 != 3
+      && !ext2_rdfsb (le32_to_cpu(INODE->i_block[EXT2_TIND_BLOCK]), DATABLOCK1))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  mapblock1 = 3;
+  if (!ext2_rdfsb (le32_to_cpu(((__u32 *) DATABLOCK1)
+		   [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
+				      * 2)]),
+		   DATABLOCK2))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  if (!ext2_rdfsb (le32_to_cpu(((__u32 *) DATABLOCK2)
+		   [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
+		    & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]),
+		   DATABLOCK2))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  return le32_to_cpu(((__u32 *) DATABLOCK2)
+    [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]);
+}
+
+/* preconditions: all preconds of ext2fs_block_map */
+int
+ext2fs_read (char *buf, int len)
+{
+  int logical_block;
+  int offset;
+  int map;
+  int ret = 0;
+  int size = 0;
+
+#ifdef E2DEBUG
+  printf("ext2fs_read(0x%x, %d)\n", buf, len);
+  dump_inode(INODE);
+  dump_inode_data((unsigned char *)INODE, sizeof (struct ext2_inode));
+#endif /* E2DEBUG */
+  while (len > 0)
+    {
+      /* find the (logical) block component of our location */
+      logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+      offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+      map = ext2fs_block_map (logical_block);
+#ifdef E2DEBUG
+      printf ("map=%d\n", map);
+#endif /* E2DEBUG */
+      if (map < 0)
+	break;
+
+      size = EXT2_BLOCK_SIZE (SUPERBLOCK);
+      size -= offset;
+      if (size > len)
+	size = len;
+
+      if (map == 0) {
+        memset ((char *) buf, 0, size);
+      } else {
+        disk_read_func = disk_read_hook;
+
+        devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
+	         offset, size, buf);
+
+        disk_read_func = NULL;
+      }
+
+      buf += size;
+      len -= size;
+      filepos += size;
+      ret += size;
+    }
+
+  if (errnum)
+    ret = 0;
+
+  return ret;
+}
+
+
+/* Based on:
+   def_blk_fops points to
+   blkdev_open, which calls (I think):
+   sys_open()
+   do_open()
+   open_namei()
+   dir_namei() which accesses current->fs->root
+     fs->root was set during original mount:
+     (something)... which calls (I think):
+     ext2_read_super()
+     iget()
+     __iget()
+     read_inode()
+     ext2_read_inode()
+       uses desc_per_block_bits, which is set in ext2_read_super()
+       also uses group descriptors loaded during ext2_read_super()
+   lookup()
+   ext2_lookup()
+   ext2_find_entry()
+   ext2_getblk()
+
+*/
+
+static inline
+int ext2_is_fast_symlink (void)
+{
+  int ea_blocks;
+  ea_blocks = le32_to_cpu(INODE->i_file_acl) ? EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE : 0;
+  return le32_to_cpu(INODE->i_blocks) == ea_blocks;
+}
+
+/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
+ *   known as SUPERBLOCK
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, buffer known as INODE contains the
+ *   inode of the file we were trying to look up
+ * side effects: messes up GROUP_DESC buffer area
+ */
+int
+ext2fs_dir (char *dirname)
+{
+  int current_ino = EXT2_ROOT_INO;	/* start at the root */
+  int updir_ino = current_ino;	/* the parent of the current directory */
+  int group_id;			/* which group the inode is in */
+  int group_desc;		/* fs pointer to that group */
+  int desc;			/* index within that group */
+  int ino_blk;			/* fs pointer of the inode's information */
+  int str_chk = 0;		/* used to hold the results of a string compare */
+  struct ext2_group_desc *gdp;
+  struct ext2_inode *raw_inode;	/* inode info corresponding to current_ino */
+
+  char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
+  int link_count = 0;
+
+  char *rest;
+  char ch;			/* temp char holder */
+
+  int off;			/* offset within block of directory entry (off mod blocksize) */
+  int loc;			/* location within a directory */
+  int blk;			/* which data blk within dir entry (off div blocksize) */
+  long map;			/* fs pointer of a particular block from dir entry */
+  struct ext2_dir_entry *dp;	/* pointer to directory entry */
+
+  /* loop invariants:
+     current_ino = inode to lookup
+     dirname = pointer to filename component we are cur looking up within
+     the directory known pointed to by current_ino (if any)
+   */
+
+#ifdef E2DEBUG
+  printf("****** ext2fs_dir(%s)\n", dirname);
+  dump_super(SUPERBLOCK);
+#endif /* E2DEBUG */
+
+  while (1)
+    {
+#ifdef E2DEBUG
+      printf ("ext2fs_dir: inode %d\n", current_ino);
+      printf ("ext2fs_dir: dirname=%s\n", dirname);
+#endif /* E2DEBUG */
+
+      /* look up an inode */
+      group_id = (current_ino - 1) / le32_to_cpu(SUPERBLOCK->s_inodes_per_group);
+      group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+      desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
+#ifdef E2DEBUG
+      printf ("ext2fs_dir: ipg=%d, dpb=%d\n", le32_to_cpu(SUPERBLOCK->s_inodes_per_group),
+	      EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+      printf ("ext2fs_dir: group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
+#endif /* E2DEBUG */
+      if (!ext2_rdfsb (
+			(WHICH_SUPER + group_desc + le32_to_cpu(SUPERBLOCK->s_first_data_block)),
+			(char*) GROUP_DESC))
+	{
+	  return 0;
+	}
+
+#ifdef E2DEBUG
+      dump_group_desc(GROUP_DESC);
+#endif /* E2DEBUG */	
+
+      gdp = GROUP_DESC;
+      ino_blk = le32_to_cpu(gdp[desc].bg_inode_table) +
+	(((current_ino - 1) % le32_to_cpu(SUPERBLOCK->s_inodes_per_group))
+	 >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+#ifdef E2DEBUG
+      printf ("ext2fs_dir: itab_blk=%d, i_in_grp=%d, log2=%d\n", 
+	 le32_to_cpu(gdp[desc].bg_inode_table),
+	 ((current_ino - 1) % le32_to_cpu(SUPERBLOCK->s_inodes_per_group)),
+	 log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+      printf ("ext2fs_dir: inode table fsblock=%d\n", ino_blk);
+#endif /* E2DEBUG */
+      if (!ext2_rdfsb (ino_blk, INODE))
+	{
+	  return 0;
+	}
+
+      /* reset indirect blocks! */
+      mapblock2 = mapblock1 = -1;
+
+      raw_inode = INODE +
+	((current_ino - 1)
+	 & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
+#ifdef E2DEBUG
+      printf ("ext2fs_dir: ipb=%d, sizeof(inode)=%d\n",
+	      (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
+	      sizeof (struct ext2_inode));
+      printf ("ext2fs_dir: inode=%x, raw_inode=%x\n", INODE, raw_inode);
+      printf ("ext2fs_dir: offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
+      dump_inode(raw_inode);
+      dump_inode_data((unsigned char *)INODE, EXT2_BLOCK_SIZE(SUPERBLOCK));
+      printf ("ext2fs_dir: first word=%x\n", *((int *) raw_inode));
+#endif /* E2DEBUG */
+
+      /* copy inode to fixed location */
+      memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
+
+#ifdef E2DEBUG
+      dump_inode(INODE);
+      printf ("ext2fs_dir: first word=%x\n", *((int *) INODE));
+#endif /* E2DEBUG */
+
+      /* If we've got a symbolic link, then chase it. */
+      if (S_ISLNK (le16_to_cpu(INODE->i_mode)))
+	{
+	  int len;
+	  if (++link_count > MAX_LINK_COUNT)
+	    {
+	      errnum = ERR_SYMLINK_LOOP;
+	      return 0;
+	    }
+
+	  /* Find out how long our remaining name is. */
+	  len = 0;
+	  while (dirname[len] && !isspace (dirname[len]))
+	    len++;
+
+	  /* Get the symlink size. */
+	  filemax = le32_to_cpu(INODE->i_size);
+	  if (filemax + len > sizeof (linkbuf) - 2)
+	    {
+	      errnum = ERR_FILELENGTH;
+	      return 0;
+	    }
+
+	  if (len)
+	    {
+	      /* Copy the remaining name to the end of the symlink data.
+	         Note that DIRNAME and LINKBUF may overlap! */
+	      memmove (linkbuf + filemax, dirname, len);
+	    }
+	  linkbuf[filemax + len] = '\0';
+
+	  /* Read the symlink data. */
+	  if (! ext2_is_fast_symlink ())
+	    {
+	      /* Read the necessary blocks, and reset the file pointer. */
+	      len = file_read (linkbuf, filemax);
+	      filepos = 0;
+	      if (!len)
+		return 0;
+	    }
+	  else
+	    {
+	      /* Copy the data directly from the inode. */
+	      len = filemax;
+	      memmove (linkbuf, (char *) INODE->i_block, len);
+	    }
+
+#ifdef E2DEBUG
+	  printf ("ext2fs_dir: symlink=%s\n", linkbuf);
+#endif
+
+	  dirname = linkbuf;
+	  if (*dirname == '/')
+	    {
+	      /* It's an absolute link, so look it up in root. */
+	      current_ino = EXT2_ROOT_INO;
+	      updir_ino = current_ino;
+	    }
+	  else
+	    {
+	      /* Relative, so look it up in our parent directory. */
+	      current_ino = updir_ino;
+	    }
+
+	  /* Try again using the new name. */
+	  continue;
+	}
+
+      /* if end of filename, INODE points to the file's inode */
+      if (!*dirname || isspace (*dirname))
+	{
+	  if (!S_ISREG (le16_to_cpu(INODE->i_mode)))
+	    {
+	      errnum = ERR_BAD_FILETYPE;
+	      return 0;
+	    }
+
+	  filemax = le32_to_cpu(INODE->i_size);
+	  return 1;
+	}
+
+      /* else we have to traverse a directory */
+      updir_ino = current_ino;
+
+      /* skip over slashes */
+      while (*dirname == '/')
+	dirname++;
+
+      /* if this isn't a directory of sufficient size to hold our file, abort */
+      if (!(le32_to_cpu(INODE->i_size)) || !S_ISDIR (le16_to_cpu(INODE->i_mode)))
+	{
+	  errnum = ERR_BAD_FILETYPE;
+	  return 0;
+	}
+
+      /* skip to next slash or end of filename (space) */
+      for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+	   rest++);
+
+      /* look through this directory and find the next filename component */
+      /* invariant: rest points to slash after the next filename component */
+      *rest = 0;
+      loc = 0;
+
+      do
+	{
+
+#ifdef E2DEBUG
+	  printf ("ext2fs_dir: dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
+#endif /* E2DEBUG */
+
+	  /* if our location/byte offset into the directory exceeds the size,
+	     give up */
+	  if (loc >= le32_to_cpu(INODE->i_size))
+	    {
+	      if (print_possibilities < 0)
+		{
+# if 0
+		  putchar ('\n');
+# endif
+		}
+	      else
+		{
+		  errnum = ERR_FILE_NOT_FOUND;
+		  *rest = ch;
+		}
+	      return (print_possibilities < 0);
+	    }
+
+	  /* else, find the (logical) block component of our location */
+	  blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+
+	  /* we know which logical block of the directory entry we are looking
+	     for, now we have to translate that to the physical (fs) block on
+	     the disk */
+	  map = ext2fs_block_map (blk);
+#ifdef E2DEBUG
+	  printf ("ext2fs_dir: fs block=%d\n", map);
+#endif /* E2DEBUG */
+	  mapblock2 = -1;
+	  if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
+	    {
+	      errnum = ERR_FSYS_CORRUPT;
+	      *rest = ch;
+	      return 0;
+	    }
+	  off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+	  dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
+	  /* advance loc prematurely to next on-disk directory entry  */
+	  loc += le16_to_cpu(dp->rec_len);
+
+	  /* NOTE: ext2fs filenames are NOT null-terminated */
+
+#ifdef E2DEBUG
+	  printf ("ext2fs_dir: directory entry ino=%d\n", le32_to_cpu(dp->inode));
+	  if (le32_to_cpu(dp->inode))
+	    printf ("entry=%s\n", dp->name);
+#endif /* E2DEBUG */
+
+	  if (le32_to_cpu(dp->inode))
+	    {
+	      int saved_c = dp->name[dp->name_len];
+
+	      dp->name[dp->name_len] = 0;
+	      str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+	      if (print_possibilities && ch != '/'
+		  && (!*dirname || str_chk <= 0))
+		{
+		  if (print_possibilities > 0)
+		    print_possibilities = -print_possibilities;
+		  print_a_completion (dp->name);
+		}
+# endif
+
+	      dp->name[dp->name_len] = saved_c;
+	    }
+
+	}
+      while (!le32_to_cpu(dp->inode) || (str_chk || (print_possibilities && ch != '/')));
+
+      current_ino = le32_to_cpu(dp->inode);
+      *(dirname = rest) = ch;
+    }
+  /* never get here */
+}
+

Added: trunk/filo/fs/fsys_fat.c
===================================================================
--- trunk/filo/fs/fsys_fat.c	                        (rev 0)
+++ trunk/filo/fs/fsys_fat.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,476 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2005   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 "shared.h"
+#include "filesys.h"
+#include "fat.h"
+
+struct fat_superblock 
+{
+  int fat_offset;
+  int fat_length;
+  int fat_size;
+  int root_offset;
+  int root_max;
+  int data_offset;
+  
+  int num_sectors;
+  int num_clust;
+  int clust_eof_marker;
+  int sects_per_clust;
+  int sectsize_bits;
+  int clustsize_bits;
+  int root_cluster;
+  
+  int cached_fat;
+  int file_cluster;
+  int current_cluster_num;
+  int current_cluster;
+};
+
+/* pointer(s) into filesystem info buffer for DOS stuff */
+#define FAT_SUPER ( (struct fat_superblock *) \
+ 		    ( FSYS_BUF + 32256) )/* 512 bytes long */
+#define FAT_BUF   ( FSYS_BUF + 30208 )	/* 4 sector FAT buffer */
+#define NAME_BUF  ( FSYS_BUF + 29184 )	/* Filename buffer (833 bytes) */
+
+#define FAT_CACHE_SIZE 2048
+
+int
+fat_mount (void)
+{
+  struct fat_bpb bpb;
+  __u32 magic, first_fat;
+  
+  /* Check partition type for harddisk */
+  if (((current_drive & 0x80) || (current_slice != 0))
+      && ! IS_PC_SLICE_TYPE_FAT (current_slice)
+      && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
+    return 0;
+  
+  /* Read bpb */
+  if (! devread (0, 0, sizeof (bpb), (char *) &bpb))
+    return 0;
+
+  /* Check if the number of sectors per cluster is zero here, to avoid
+     zero division.  */
+  if (bpb.sects_per_clust == 0)
+    return 0;
+  
+  FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect));
+  FAT_SUPER->clustsize_bits
+    = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
+  
+  /* Fill in info about super block */
+  FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors) 
+    ? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors;
+  
+  /* FAT offset and length */
+  FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects);
+  FAT_SUPER->fat_length = 
+    bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
+  
+  /* Rootdir offset and length for FAT12/16 */
+  FAT_SUPER->root_offset = 
+    FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
+  FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
+  
+  /* Data offset and number of clusters */
+  FAT_SUPER->data_offset = 
+    FAT_SUPER->root_offset
+    + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
+  FAT_SUPER->num_clust = 
+    2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset) 
+	 / bpb.sects_per_clust);
+  FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
+  
+  if (!bpb.fat_length)
+    {
+      /* This is a FAT32 */
+      if (FAT_CVT_U16(bpb.dir_entries))
+ 	return 0;
+      
+      if (bpb.flags & 0x0080)
+	{
+	  /* FAT mirroring is disabled, get active FAT */
+	  int active_fat = bpb.flags & 0x000f;
+	  if (active_fat >= bpb.num_fats)
+	    return 0;
+	  FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
+	}
+      
+      FAT_SUPER->fat_size = 8;
+      FAT_SUPER->root_cluster = bpb.root_cluster;
+
+      /* Yes the following is correct.  FAT32 should be called FAT28 :) */
+      FAT_SUPER->clust_eof_marker = 0xffffff8;
+    } 
+  else 
+    {
+      if (!FAT_SUPER->root_max)
+ 	return 0;
+      
+      FAT_SUPER->root_cluster = -1;
+      if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST) 
+	{
+	  FAT_SUPER->fat_size = 4;
+	  FAT_SUPER->clust_eof_marker = 0xfff8;
+	} 
+      else
+	{
+	  FAT_SUPER->fat_size = 3;
+	  FAT_SUPER->clust_eof_marker = 0xff8;
+	}
+    }
+
+  /* Now do some sanity checks */
+  
+  if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
+      || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
+      || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
+ 				       - FAT_SUPER->sectsize_bits))
+      || FAT_SUPER->num_clust <= 2
+      || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
+ 	  > FAT_SUPER->fat_length))
+    return 0;
+  
+  /* kbs: Media check on first FAT entry [ported from PUPA] */
+
+  if (!devread(FAT_SUPER->fat_offset, 0,
+               sizeof(first_fat), (char *)&first_fat))
+    return 0;
+
+  if (FAT_SUPER->fat_size == 8)
+    {
+      first_fat &= 0x0fffffff;
+      magic = 0x0fffff00;
+    }
+  else if (FAT_SUPER->fat_size == 4)
+    {
+      first_fat &= 0x0000ffff;
+      magic = 0xff00;
+    }
+  else
+    {
+      first_fat &= 0x00000fff;
+      magic = 0x0f00;
+    }
+
+  /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
+     descriptor, even if it is a so-called superfloppy (e.g. an USB key).
+     The check may be too strict for this kind of stupid BIOSes, as
+     they overwrite the media descriptor.  */
+  if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
+    return 0;
+
+  FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
+  return 1;
+}
+
+int
+fat_read (char *buf, int len)
+{
+  int logical_clust;
+  int offset;
+  int ret = 0;
+  int size;
+  
+  if (FAT_SUPER->file_cluster < 0)
+    {
+      /* root directory for fat16 */
+      size = FAT_SUPER->root_max - filepos;
+      if (size > len)
+ 	size = len;
+      if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
+ 	return 0;
+      filepos += size;
+      return size;
+    }
+  
+  logical_clust = filepos >> FAT_SUPER->clustsize_bits;
+  offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
+  if (logical_clust < FAT_SUPER->current_cluster_num)
+    {
+      FAT_SUPER->current_cluster_num = 0;
+      FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
+    }
+  
+  while (len > 0)
+    {
+      int sector;
+      while (logical_clust > FAT_SUPER->current_cluster_num)
+	{
+	  /* calculate next cluster */
+	  int fat_entry = 
+	    FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
+	  int next_cluster;
+	  int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
+	  
+	  if (cached_pos < 0 || 
+	      (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
+	    {
+	      FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
+	      cached_pos = (fat_entry - FAT_SUPER->cached_fat);
+	      sector = FAT_SUPER->fat_offset
+		+ FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
+	      if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
+		return 0;
+	    }
+	  next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
+	  if (FAT_SUPER->fat_size == 3)
+	    {
+	      if (cached_pos & 1)
+		next_cluster >>= 4;
+	      next_cluster &= 0xFFF;
+	    }
+	  else if (FAT_SUPER->fat_size == 4)
+	    next_cluster &= 0xFFFF;
+	  
+	  if (next_cluster >= FAT_SUPER->clust_eof_marker)
+	    return ret;
+	  if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
+	    {
+	      errnum = ERR_FSYS_CORRUPT;
+	      return 0;
+	    }
+	  
+	  FAT_SUPER->current_cluster = next_cluster;
+	  FAT_SUPER->current_cluster_num++;
+	}
+      
+      sector = FAT_SUPER->data_offset +
+	((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
+ 					      - FAT_SUPER->sectsize_bits));
+      size = (1 << FAT_SUPER->clustsize_bits) - offset;
+      if (size > len)
+	size = len;
+      
+      disk_read_func = disk_read_hook;
+      
+      devread(sector, offset, size, buf);
+      
+      disk_read_func = NULL;
+      
+      len -= size;
+      buf += size;
+      ret += size;
+      filepos += size;
+      logical_clust++;
+      offset = 0;
+    }
+  return errnum ? 0 : ret;
+}
+
+int
+fat_dir (char *dirname)
+{
+  char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
+  char *filename = (char *) NAME_BUF;
+  int attrib = FAT_ATTRIB_DIR;
+#ifndef STAGE1_5
+  int do_possibilities = 0;
+#endif
+  
+  /* XXX I18N:
+   * the positions 2,4,6 etc are high bytes of a 16 bit unicode char 
+   */
+  static unsigned char longdir_pos[] = 
+  { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
+  int slot = -2;
+  int alias_checksum = -1;
+  
+  FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
+  filepos = 0;
+  FAT_SUPER->current_cluster_num = MAXINT;
+  
+  /* main loop to find desired directory entry */
+ loop:
+  
+  /* if we have a real file (and we're not just printing possibilities),
+     then this is where we want to exit */
+  
+  if (!*dirname || isspace (*dirname))
+    {
+      if (attrib & FAT_ATTRIB_DIR)
+	{
+	  errnum = ERR_BAD_FILETYPE;
+	  return 0;
+	}
+      
+      return 1;
+    }
+  
+  /* continue with the file/directory name interpretation */
+  
+  while (*dirname == '/')
+    dirname++;
+  
+  if (!(attrib & FAT_ATTRIB_DIR))
+    {
+      errnum = ERR_BAD_FILETYPE;
+      return 0;
+    }
+  /* Directories don't have a file size */
+  filemax = MAXINT;
+  
+  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+  
+  *rest = 0;
+  
+# ifndef STAGE1_5
+  if (print_possibilities && ch != '/')
+    do_possibilities = 1;
+# endif
+  
+  while (1)
+    {
+      if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
+	  || dir_buf[0] == 0)
+	{
+	  if (!errnum)
+	    {
+# ifndef STAGE1_5
+	      if (print_possibilities < 0)
+		{
+#if 0
+		  putchar ('\n');
+#endif
+		  return 1;
+		}
+# endif /* STAGE1_5 */
+	      
+	      errnum = ERR_FILE_NOT_FOUND;
+	      *rest = ch;
+	    }
+	  
+	  return 0;
+	}
+      
+      if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
+	{
+	  /* This is a long filename.  The filename is build from back
+	   * to front and may span multiple entries.  To bind these
+	   * entries together they all contain the same checksum over
+	   * the short alias.
+	   *
+	   * The id field tells if this is the first entry (the last
+	   * part) of the long filename, and also at which offset this
+	   * belongs.
+	   *
+	   * We just write the part of the long filename this entry
+	   * describes and continue with the next dir entry.
+	   */
+	  int i, offset;
+	  unsigned char id = FAT_LONGDIR_ID(dir_buf);
+	  
+	  if ((id & 0x40)) 
+	    {
+	      id &= 0x3f;
+	      slot = id;
+	      filename[slot * 13] = 0;
+	      alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
+	    } 
+	  
+	  if (id != slot || slot == 0
+	      || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
+	    {
+	      alias_checksum = -1;
+	      continue;
+	    }
+	  
+	  slot--;
+	  offset = slot * 13;
+	  
+	  for (i=0; i < 13; i++)
+	    filename[offset+i] = dir_buf[longdir_pos[i]];
+	  continue;
+	}
+      
+      if (!FAT_DIRENTRY_VALID (dir_buf))
+	continue;
+      
+      if (alias_checksum != -1 && slot == 0)
+	{
+	  int i;
+	  unsigned char sum;
+	  
+	  slot = -2;
+	  for (sum = 0, i = 0; i< 11; i++)
+	    sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
+	  
+	  if (sum == alias_checksum)
+	    {
+# ifndef STAGE1_5
+	      if (do_possibilities)
+		goto print_filename;
+# endif /* STAGE1_5 */
+	      
+	      if (substring (dirname, filename) == 0)
+		break;
+	    }
+	}
+      
+      /* XXX convert to 8.3 filename format here */
+      {
+	int i, j, c;
+	
+	for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
+	       && !isspace (c); i++);
+	
+	filename[i++] = '.';
+	
+	for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
+	       && !isspace (c); j++);
+	
+	if (j == 0)
+	  i--;
+	
+	filename[i + j] = 0;
+      }
+      
+# ifndef STAGE1_5
+      if (do_possibilities)
+	{
+	print_filename:
+	  if (substring (dirname, filename) <= 0)
+	    {
+	      if (print_possibilities > 0)
+		print_possibilities = -print_possibilities;
+	      print_a_completion (filename);
+	    }
+	  continue;
+	}
+# endif /* STAGE1_5 */
+      
+      if (substring (dirname, filename) == 0)
+	break;
+    }
+  
+  *(dirname = rest) = ch;
+  
+  attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
+  filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
+  filepos = 0;
+  FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
+  FAT_SUPER->current_cluster_num = MAXINT;
+  
+  /* go back to main loop at top of function */
+  goto loop;
+}
+

Added: trunk/filo/fs/fsys_iso9660.c
===================================================================
--- trunk/filo/fs/fsys_iso9660.c	                        (rev 0)
+++ trunk/filo/fs/fsys_iso9660.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,332 @@
+/*
+ *  ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
+ *  including Rock Ridge Extensions support
+ *
+ *  Copyright (C) 1998, 1999  Kousuke Takai  <tak at kmc.kyoto-u.ac.jp>
+ *
+ *  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.
+ */
+/*
+ *  References:
+ *	linux/fs/isofs/rock.[ch]
+ *	mkisofs-1.11.1/diag/isoinfo.c
+ *	mkisofs-1.11.1/iso9660.h
+ *		(all are written by Eric Youngdale)
+ *
+ *  Modifications by:
+ *	Leonid Lisovskiy   <lly at pisem.net>	2003
+ */
+
+/*
+ * Modified to make it work with FILO
+ * 2003-10 by SONE Takeshi
+ */
+
+#include "shared.h"
+#include "filesys.h"
+#include "iso9660.h"
+#define DEBUG_THIS CONFIG_DEBUG_ISO9660
+#include <debug.h>
+
+struct iso_superblock {
+    unsigned long vol_sector;
+
+    unsigned long file_start;
+};
+
+#define ISO_SUPER	((struct iso_superblock *)(FSYS_BUF))
+#define PRIMDESC        ((struct iso_primary_descriptor *)(FSYS_BUF + 2048))
+#define DIRREC          ((struct iso_directory_record *)(FSYS_BUF + 4096))
+#define RRCONT_BUF      ((unsigned char *)(FSYS_BUF + 6144))
+#define NAME_BUF        ((unsigned char *)(FSYS_BUF + 8192))
+
+static int
+iso9660_devread (int sector, int byte_offset, int byte_len, char *buf)
+{
+  /* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte
+   * CD-ROM sector */
+  return devread(sector<<2, byte_offset, byte_len, buf);
+}
+
+int
+iso9660_mount (void)
+{
+  unsigned int sector;
+
+  /*
+   *  Because there is no defined slice type ID for ISO-9660 filesystem,
+   *  this test will pass only either (1) if entire disk is used, or
+   *  (2) if current partition is BSD style sub-partition whose ID is
+   *  ISO-9660.
+   */
+  /*if ((current_partition != 0xFFFFFF)
+      && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660))
+    return 0;*/
+
+  /*
+   *  Currently, only FIRST session of MultiSession disks are supported !!!
+   */
+  for (sector = 16 ; sector < 32 ; sector++)
+    {
+      if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC)) 
+	break;
+      /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */
+      if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0')
+	  && CHECK2(PRIMDESC->id + 3, '0', '1'))
+	{
+	  ISO_SUPER->vol_sector = sector;
+	  ISO_SUPER->file_start = 0;
+	  fsmax = PRIMDESC->volume_space_size.l;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+int
+iso9660_dir (char *dirname)
+{
+  struct iso_directory_record *idr;
+  RR_ptr_t rr_ptr;
+  struct rock_ridge *ce_ptr;
+  unsigned int pathlen;
+  int size;
+  unsigned int extent;
+  unsigned int rr_len;
+  unsigned char file_type;
+  unsigned char rr_flag;
+
+  idr = &PRIMDESC->root_directory_record;
+  ISO_SUPER->file_start = 0;
+
+  do
+  {
+      while (*dirname == '/')	/* skip leading slashes */
+	  dirname++;
+      /* pathlen = strcspn(dirname, "/\n\t "); */
+      for (pathlen = 0 ;
+	  dirname[pathlen]
+	     && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ;
+	  pathlen++)
+	;
+
+      size = idr->size.l;
+      extent = idr->extent.l;
+
+      while (size > 0)
+      {
+	  if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC))
+	  {
+	      errnum = ERR_FSYS_CORRUPT;
+	      return 0;
+	  }
+	  extent++;
+
+	  idr = (struct iso_directory_record *)DIRREC;
+	  for (; idr->length.l > 0;
+		 idr = (struct iso_directory_record *)((char *)idr + idr->length.l) )
+	  {
+	      const unsigned char *name = idr->name;
+	      unsigned int name_len = idr->name_len.l;
+
+	      file_type = (idr->flags.l & 2) ? ISO_DIRECTORY : ISO_REGULAR;
+	      if (name_len == 1)
+	      {
+		  if ((name[0] == 0) ||	/* self */
+		      (name[0] == 1)) 	/* parent */
+		    continue;
+	      }
+	      if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1'))
+	      {
+		  name_len -= 2;	/* truncate trailing file version */
+		  if (name_len > 1 && name[name_len - 1] == '.')
+		    name_len--;		/* truncate trailing dot */
+	      }
+
+	      /*
+	       *  Parse Rock-Ridge extension
+	       */
+	      rr_len = (idr->length.l - idr->name_len.l
+			- (unsigned char)sizeof(struct iso_directory_record)
+			+ (unsigned char)sizeof(idr->name));
+	      rr_ptr.ptr = ((unsigned char *)idr + idr->name_len.l
+			    + sizeof(struct iso_directory_record)
+			    - sizeof(idr->name));
+	      if (rr_ptr.i & 1)
+		rr_ptr.i++, rr_len--;
+	      ce_ptr = NULL;
+	      rr_flag = RR_FLAG_NM | RR_FLAG_PX;
+
+	      while (rr_len >= 4)
+	      {
+		  if (rr_ptr.rr->version != 1)
+		  {
+#ifndef STAGE1_5
+		    if (debug)
+		      printf(
+			    "Non-supported version (%d) RockRidge chunk "
+			    "`%c%c'\n", rr_ptr.rr->version,
+			    rr_ptr.rr->signature & 0xFF,
+			    rr_ptr.rr->signature >> 8);
+#endif
+		  }
+		  else if (rr_ptr.rr->signature == RRMAGIC('R', 'R')
+			   && rr_ptr.rr->len >= 5)
+		    rr_flag &= rr_ptr.rr->u.rr.flags.l;
+		  else if (rr_ptr.rr->signature == RRMAGIC('N', 'M'))
+		  {
+		      name = rr_ptr.rr->u.nm.name;
+		      name_len = rr_ptr.rr->len - 5;
+		      rr_flag &= ~RR_FLAG_NM;
+		  }
+		  else if (rr_ptr.rr->signature == RRMAGIC('P', 'X')
+			   && rr_ptr.rr->len >= 36)
+		  {
+		      file_type = ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT)
+				   == POSIX_S_IFREG
+				   ? ISO_REGULAR
+				   : ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT)
+				      == POSIX_S_IFDIR
+				      ? ISO_DIRECTORY : ISO_OTHER));
+		      rr_flag &= ~RR_FLAG_PX;
+		  }
+		  else if (rr_ptr.rr->signature == RRMAGIC('C', 'E')
+			   && rr_ptr.rr->len >= 28)
+		    ce_ptr = rr_ptr.rr;
+		  if (!rr_flag)
+		    /*
+		     * There is no more extension we expects...
+		     */
+		    break;
+		  rr_len -= rr_ptr.rr->len;
+		  rr_ptr.ptr += rr_ptr.rr->len;
+		  if (rr_len < 4 && ce_ptr != NULL)
+		  {
+		      /* preserve name before loading new extent. */
+		      if( RRCONT_BUF <= (unsigned char *)name
+			  && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE )
+		      {
+			  memcpy(NAME_BUF, name, name_len);
+			  name = NAME_BUF;
+		      }
+		      rr_ptr.ptr = RRCONT_BUF + ce_ptr->u.ce.offset.l;
+		      rr_len = ce_ptr->u.ce.size.l;
+		      if (!iso9660_devread(ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, (char *)RRCONT_BUF))
+		      {
+			  errnum = 0;	/* this is not fatal. */
+			  break;
+		      }
+		      ce_ptr = NULL;
+		   }
+	      } /* rr_len >= 4 */
+
+	      filemax = MAXINT;
+	      if (name_len >= pathlen
+		  && !__builtin_memcmp(name, dirname, pathlen))
+	      {
+                if (dirname[pathlen] == '/' || !print_possibilities)
+		{
+		  /*
+		   *  DIRNAME is directory component of pathname,
+		   *  or we are to open a file.
+		   */
+		  if (pathlen == name_len)
+		  {
+		      if (dirname[pathlen] == '/')
+		      {
+		          if (file_type != ISO_DIRECTORY)
+		          {
+			      errnum = ERR_BAD_FILETYPE;
+			      return 0;
+			  }
+                          goto next_dir_level;
+		      }
+		      if (file_type != ISO_REGULAR)
+		      {
+		          errnum = ERR_BAD_FILETYPE;
+		          return 0;
+		      }
+		      ISO_SUPER->file_start = idr->extent.l;
+		      filepos = 0;
+		      filemax = idr->size.l;
+		      return 1;
+		  }
+		}
+	        else	/* Completion */
+	        {
+#ifndef STAGE1_5
+ 		  if (print_possibilities > 0)
+		      print_possibilities = -print_possibilities;
+		  memcpy(NAME_BUF, name, name_len);
+		  NAME_BUF[name_len] = '\0';
+            	  print_a_completion (NAME_BUF);
+#endif
+	        }
+	      }
+	  } /* for */
+
+	  size -= ISO_SECTOR_SIZE;
+      } /* size>0 */
+
+      if (dirname[pathlen] == '/' || print_possibilities >= 0)
+      {
+	  errnum = ERR_FILE_NOT_FOUND;
+	  return 0;
+      }
+
+next_dir_level:
+      dirname += pathlen;
+
+  } while (*dirname == '/');
+
+  return 1;
+}
+
+int
+iso9660_read (char *buf, int len)
+{
+  int sector, blkoffset, size, ret;
+
+  if (ISO_SUPER->file_start == 0)
+    return 0;
+
+  ret = 0;
+  blkoffset = filepos & (ISO_SECTOR_SIZE - 1);
+  sector = filepos >> ISO_SECTOR_BITS;
+  while (len > 0)
+  {
+    size = ISO_SECTOR_SIZE - blkoffset;
+    if (size > len)
+        size = len;
+
+    disk_read_func = disk_read_hook;
+
+    if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf))
+	return 0;
+
+    disk_read_func = NULL;
+
+    len -= size;
+    buf += size;
+    ret += size;
+    filepos += size;
+    sector++;
+    blkoffset = 0;
+  }
+
+  return ret;
+}
+

Added: trunk/filo/fs/fsys_jfs.c
===================================================================
--- trunk/filo/fs/fsys_jfs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_jfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,400 @@
+/* fsys_jfs.c - an implementation for the IBM JFS file system */
+/*  
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2001,2002  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 "shared.h"
+#include "filesys.h"
+#include "jfs.h"
+
+#define MAX_LINK_COUNT	8
+
+#define DTTYPE_INLINE	0
+#define DTTYPE_PAGE	1
+
+struct jfs_info
+{
+	int bsize;
+	int l2bsize;
+	int bdlog;
+	int xindex;
+	int xlastindex;
+	int sindex;
+	int slastindex;
+	int de_index;
+	int dttype;
+	xad_t *xad;
+	ldtentry_t *de;
+};
+
+static struct jfs_info jfs;
+
+#define xtpage		((xtpage_t *)FSYS_BUF)
+#define dtpage		((dtpage_t *)((char *)FSYS_BUF + 4096))
+#define fileset		((dinode_t *)((char *)FSYS_BUF + 8192))
+#define inode		((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t)))
+#define dtroot		((dtroot_t *)(&inode->di_btroot))
+
+static ldtentry_t de_always[2] = {
+	{1, -1, 2, {'.', '.'}},
+	{1, -1, 1, {'.'}}
+};
+
+static int
+isinxt (s64 key, s64 offset, s64 len)
+{
+	return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
+}
+
+static xad_t *
+first_extent (dinode_t *di)
+{
+	xtpage_t *xtp;
+
+	jfs.xindex = 2;
+	xtp = (xtpage_t *)&di->di_btroot;
+	jfs.xad = &xtp->xad[2];
+	if (xtp->header.flag & BT_LEAF) {
+	    	jfs.xlastindex = xtp->header.nextindex;
+	} else {
+		do {
+			devread (addressXAD (jfs.xad) << jfs.bdlog, 0,
+				 sizeof(xtpage_t), (char *)xtpage);
+			jfs.xad = &xtpage->xad[2];
+		} while (!(xtpage->header.flag & BT_LEAF));
+		jfs.xlastindex = xtpage->header.nextindex;
+	}
+
+	return jfs.xad;
+}
+
+static xad_t *
+next_extent (void)
+{
+	if (++jfs.xindex < jfs.xlastindex) {
+	} else if (xtpage->header.next) {
+		devread (xtpage->header.next << jfs.bdlog, 0,
+			 sizeof(xtpage_t), (char *)xtpage);
+		jfs.xlastindex = xtpage->header.nextindex;
+		jfs.xindex = XTENTRYSTART;
+		jfs.xad = &xtpage->xad[XTENTRYSTART];
+	} else {
+		return NULL;
+	}
+	return ++jfs.xad;
+}
+
+
+static void
+di_read (u32 inum, dinode_t *di)
+{
+	s64 key;
+	u32 xd, ioffset;
+	s64 offset;
+	xad_t *xad;
+	pxd_t pxd;
+
+	key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize;
+	xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT;
+	ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE;
+	xad = first_extent (fileset);
+	do {
+		offset = offsetXAD (xad);
+		if (isinxt (key, offset, lengthXAD (xad))) {
+			devread ((addressXAD (xad) + key - offset) << jfs.bdlog,
+				 3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd);
+			devread (addressPXD (&pxd) << jfs.bdlog,
+				 ioffset, DISIZE, (char *)di);
+			break;
+		}
+	} while ((xad = next_extent ()));
+}
+
+static ldtentry_t *
+next_dentry (void)
+{
+	ldtentry_t *de;
+	s8 *stbl;
+
+	if (jfs.dttype == DTTYPE_INLINE) {
+		if (jfs.sindex < jfs.slastindex) {
+			return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]];
+		}
+	} else {
+		de = (ldtentry_t *)dtpage->slot;
+		stbl = (s8 *)&de[(int)dtpage->header.stblindex];
+		if (jfs.sindex < jfs.slastindex) {
+			return &de[(int)stbl[jfs.sindex++]];
+		} else if (dtpage->header.next) {
+			devread (dtpage->header.next << jfs.bdlog, 0,
+				 sizeof(dtpage_t), (char *)dtpage);
+			jfs.slastindex = dtpage->header.nextindex;
+			jfs.sindex = 1;
+			return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]];
+		}
+	}
+
+	return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL;
+}
+
+static ldtentry_t *
+first_dentry (void)
+{
+	dtroot_t *dtr;
+	pxd_t *xd;
+	idtentry_t *de;
+
+	dtr = (dtroot_t *)&inode->di_btroot;
+	jfs.sindex = 0;
+	jfs.de_index = 0;
+
+	de_always[0].inumber = inode->di_parent;
+	de_always[1].inumber = inode->di_number;
+	if (dtr->header.flag & BT_LEAF) {
+		jfs.dttype = DTTYPE_INLINE;
+		jfs.slastindex = dtr->header.nextindex;
+	} else {
+		de = (idtentry_t *)dtpage->slot;
+		jfs.dttype = DTTYPE_PAGE;
+		xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd;
+		for (;;) {
+			devread (addressPXD (xd) << jfs.bdlog, 0,
+				 sizeof(dtpage_t), (char *)dtpage);
+			if (dtpage->header.flag & BT_LEAF)
+				break;
+			xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd;
+		}
+		jfs.slastindex = dtpage->header.nextindex;
+	}
+
+	return next_dentry ();
+}
+
+
+static dtslot_t *
+next_dslot (int next)
+{
+	return (jfs.dttype == DTTYPE_INLINE)
+		? (dtslot_t *)&dtroot->slot[next]
+		: &((dtslot_t *)dtpage->slot)[next];
+}
+
+static void
+uni2ansi (UniChar *uni, char *ansi, int len)
+{
+	for (; len; len--, uni++)
+		*ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni;
+}
+
+int
+jfs_mount (void)
+{
+	struct jfs_superblock super;
+
+	if (part_length < MINJFS >> SECTOR_BITS
+	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
+			 sizeof(struct jfs_superblock), (char *)&super)
+	    || (super.s_magic != JFS_MAGIC)
+	    || !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I,
+			 0, DISIZE, (char*)fileset)) {
+		return 0;
+	}
+
+	jfs.bsize = super.s_bsize;
+	jfs.l2bsize = super.s_l2bsize;
+	jfs.bdlog = jfs.l2bsize - SECTOR_BITS;
+
+	return 1;
+}
+
+int
+jfs_read (char *buf, int len)
+{
+	xad_t *xad;
+	s64 endofprev, endofcur;
+	s64 offset, xadlen;
+	int toread, startpos, endpos;
+
+	startpos = filepos;
+	endpos = filepos + len;
+	endofprev = (1ULL << 62) - 1;
+	xad = first_extent (inode);
+	do {
+		offset = offsetXAD (xad);
+		xadlen = lengthXAD (xad);
+		if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) {
+			endofcur = (offset + xadlen) << jfs.l2bsize; 
+			toread = (endofcur >= endpos)
+				  ? len : (endofcur - filepos);
+
+			disk_read_func = disk_read_hook;
+			devread (addressXAD (xad) << jfs.bdlog,
+				 filepos - (offset << jfs.l2bsize), toread, buf);
+			disk_read_func = NULL;
+
+			buf += toread;
+			len -= toread;
+			filepos += toread;
+		} else if (offset > endofprev) {
+			toread = ((offset << jfs.l2bsize) >= endpos)
+				  ? len : ((offset - endofprev) << jfs.l2bsize);
+			len -= toread;
+			filepos += toread;
+			for (; toread; toread--) {
+				*buf++ = 0;
+			}
+			continue;
+		}
+		endofprev = offset + xadlen; 
+		xad = next_extent ();
+	} while (len > 0 && xad);
+
+	return filepos - startpos;
+}
+
+int
+jfs_dir (char *dirname)
+{
+	char *ptr, *rest, ch;
+	ldtentry_t *de;
+	dtslot_t *ds;
+	u32 inum, parent_inum;
+	s64 di_size;
+	u32 di_mode;
+	int namlen, cmp, n, link_count;
+	char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX];
+
+	parent_inum = inum = ROOT_I;
+	link_count = 0;
+	for (;;) {
+		di_read (inum, inode);
+		di_size = inode->di_size;
+		di_mode = inode->di_mode;
+
+		if ((di_mode & IFMT) == IFLNK) {
+			if (++link_count > MAX_LINK_COUNT) {
+				errnum = ERR_SYMLINK_LOOP;
+				return 0;
+			}
+			if (di_size < (di_mode & INLINEEA ? 256 : 128)) {
+				grub_memmove (linkbuf, inode->di_fastsymlink, di_size);
+				n = di_size;
+			} else if (di_size < JFS_PATH_MAX - 1) {
+				filepos = 0;
+				filemax = di_size;
+				n = jfs_read (linkbuf, filemax);
+			} else {
+				errnum = ERR_FILELENGTH;
+				return 0;
+			}
+
+			inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum;
+			while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++));
+			linkbuf[n] = 0;
+			dirname = linkbuf;
+			continue;
+		}
+
+		if (!*dirname || isspace (*dirname)) {
+			if ((di_mode & IFMT) != IFREG) {
+				errnum = ERR_BAD_FILETYPE;
+				return 0;
+			}
+			filepos = 0;
+			filemax = di_size;
+			return 1;
+		}
+
+		if ((di_mode & IFMT) != IFDIR) {
+			errnum = ERR_BAD_FILETYPE;
+			return 0;
+		}
+
+		for (; *dirname == '/'; dirname++);
+
+		for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+		*rest = 0;
+
+		de = first_dentry ();
+		for (;;) {
+			namlen = de->namlen;
+			if (de->next == -1) {
+				uni2ansi (de->name, namebuf, namlen);
+				namebuf[namlen] = 0;
+			} else {
+				uni2ansi (de->name, namebuf, DTLHDRDATALEN);
+				ptr = namebuf;
+				ptr += DTLHDRDATALEN;
+				namlen -= DTLHDRDATALEN;
+				ds = next_dslot (de->next);
+				while (ds->next != -1) {
+					uni2ansi (ds->name, ptr, DTSLOTDATALEN);
+					ptr += DTSLOTDATALEN;
+					namlen -= DTSLOTDATALEN;
+					ds = next_dslot (ds->next);
+				}
+				uni2ansi (ds->name, ptr, namlen);
+				ptr += namlen;
+				*ptr = 0;
+			}
+
+			cmp = (!*dirname) ? -1 : substring (dirname, namebuf);
+#ifndef STAGE1_5
+			if (print_possibilities && ch != '/'
+			    && cmp <= 0) {
+				if (print_possibilities > 0)
+					print_possibilities = -print_possibilities;
+				print_a_completion (namebuf);
+			} else
+#endif
+			if (cmp == 0) {
+				parent_inum = inum;
+				inum = de->inumber;
+		        	*(dirname = rest) = ch;
+				break;
+			}
+			de = next_dentry ();
+			if (de == NULL) {
+				if (print_possibilities < 0)
+					return 1;
+
+				errnum = ERR_FILE_NOT_FOUND;
+				*rest = ch;
+				return 0;
+			}
+		}
+	}
+}
+
+int
+jfs_embed (int *start_sector, int needed_sectors)
+{
+	struct jfs_superblock super;
+
+	if (needed_sectors > 63
+	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
+			 sizeof (struct jfs_superblock),
+			 (char *)&super)
+	    || (super.s_magic != JFS_MAGIC)) {
+		return 0;
+	}
+
+	*start_sector = 1;
+	return 1;
+}
+

Added: trunk/filo/fs/fsys_minix.c
===================================================================
--- trunk/filo/fs/fsys_minix.c	                        (rev 0)
+++ trunk/filo/fs/fsys_minix.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,531 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002  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.
+ */
+
+/* Restrictions:
+   This is MINIX V1 only (yet)
+   Disk creation is like:
+   mkfs.minix -c DEVICE 
+*/
+
+#include "shared.h"
+#include "filesys.h"
+
+#define DEBUG_MINIX CONFIG_DEBUG_MINIX
+
+/* indirect blocks */
+static int mapblock1, mapblock2, namelen;
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE 	(1<<BLOCK_SIZE_BITS)
+
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c (is OK for minix) */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */
+
+/* include/asm-i386/type.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/* include/linux/minix_fs.h */
+#define MINIX_ROOT_INO 1
+
+/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
+#define MINIX_LINK_MAX  250
+#define MINIX2_LINK_MAX 65530
+
+#define MINIX_I_MAP_SLOTS       8
+#define MINIX_Z_MAP_SLOTS       64
+#define MINIX_SUPER_MAGIC       0x137F          /* original minix fs */
+#define MINIX_SUPER_MAGIC2      0x138F          /* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC      0x2468          /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2     0x2478          /* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS          0x0001          /* Clean fs. */
+#define MINIX_ERROR_FS          0x0002          /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+#define MINIX_V1                0x0001          /* original minix fs */
+#define MINIX_V2                0x0002          /* minix V2 fs */
+
+/* originally this is : 
+#define INODE_VERSION(inode)    inode->i_sb->u.minix_sb.s_version
+   here we have */
+#define INODE_VERSION(inode)	(SUPERBLOCK->s_version)
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+	__u16 i_mode;
+	__u16 i_uid;
+	__u32 i_size;
+	__u32 i_time;
+	__u8  i_gid;
+	__u8  i_nlinks;
+	__u16 i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+	__u16 i_mode;
+	__u16 i_nlinks;
+	__u16 i_uid;
+	__u16 i_gid;
+	__u32 i_size;
+	__u32 i_atime;
+	__u32 i_mtime;
+	__u32 i_ctime;
+	__u32 i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+        __u16 s_ninodes;
+        __u16 s_nzones;
+        __u16 s_imap_blocks;
+        __u16 s_zmap_blocks;
+        __u16 s_firstdatazone;
+        __u16 s_log_zone_size;
+        __u32 s_max_size;
+        __u16 s_magic;
+        __u16 s_state;
+        __u32 s_zones;
+};
+
+struct minix_dir_entry {
+        __u16 inode;
+        char name[0];
+};
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+    ((struct minix_super_block *)(FSYS_BUF))
+#define INODE \
+    ((struct minix_inode *)((int) SUPERBLOCK + BLOCK_SIZE))
+#define DATABLOCK1 \
+    ((int)((int)INODE + sizeof(struct minix_inode)))
+#define DATABLOCK2 \
+    ((int)((int)DATABLOCK1 + BLOCK_SIZE))
+
+/* linux/stat.h */
+#define S_IFMT  00170000
+#define S_IFLNK  0120000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
+
+#define PATH_MAX                1024	/* include/linux/limits.h */
+#define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
+
+/* check filesystem types and read superblock into memory buffer */
+int
+minix_mount (void)
+{
+  if (((current_drive & 0x80) || current_slice != 0)
+      && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
+      && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
+    return 0;			/* The partition is not of MINIX type */
+  
+  if (part_length < (SBLOCK +
+		     (sizeof (struct minix_super_block) / DEV_BSIZE)))
+    return 0;			/* The partition is too short */
+  
+  if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
+		(char *) SUPERBLOCK))
+    return 0;			/* Cannot read superblock */
+  
+  switch (SUPERBLOCK->s_magic)
+    {
+    case MINIX_SUPER_MAGIC:
+      namelen = 14;
+      break;
+    case MINIX_SUPER_MAGIC2:
+      namelen = 30;
+      break;
+    default:
+      return 0;			/* Unsupported type */
+    }
+
+  return 1;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+minix_rdfsb (int fsblock, int buffer)
+{
+  return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
+		  BLOCK_SIZE, (char *) buffer);
+}
+
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+   a physical block (the location in the file system) via an inode. */
+static int
+minix_block_map (int logical_block)
+{
+  int i;
+
+  if (logical_block < 7)
+    return INODE->i_zone[logical_block];
+
+  logical_block -= 7;
+  if (logical_block < 512)
+    {
+      i = INODE->i_zone[7];
+      
+      if (!i || ((mapblock1 != 1)
+		 && !minix_rdfsb (i, DATABLOCK1)))
+	{
+	  errnum = ERR_FSYS_CORRUPT;
+	  return -1;
+	}
+      mapblock1 = 1;
+      return ((__u16 *) DATABLOCK1) [logical_block];
+    }
+
+  logical_block -= 512;
+  i = INODE->i_zone[8];
+  if (!i || ((mapblock1 != 2)
+	     && !minix_rdfsb (i, DATABLOCK1)))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  mapblock1 = 2;
+  i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
+  if (!i || ((mapblock2 != i)
+	     && !minix_rdfsb (i, DATABLOCK2)))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  mapblock2 = i;
+  return ((__u16 *) DATABLOCK2)[logical_block & 511];
+}
+
+/* read from INODE into BUF */
+int
+minix_read (char *buf, int len)
+{
+  int logical_block;
+  int offset;
+  int map;
+  int ret = 0;
+  int size = 0;
+
+  while (len > 0)
+    {
+      /* find the (logical) block component of our location */
+      logical_block = filepos >> BLOCK_SIZE_BITS;
+      offset = filepos & (BLOCK_SIZE - 1);
+      map = minix_block_map (logical_block);
+#ifdef DEBUG_MINIX
+      printf ("map=%d\n", map);
+#endif
+      if (map < 0)
+	break;
+
+      size = BLOCK_SIZE;
+      size -= offset;
+      if (size > len)
+	size = len;
+
+      disk_read_func = disk_read_hook;
+
+      devread (map * (BLOCK_SIZE / DEV_BSIZE),
+	       offset, size, buf);
+
+      disk_read_func = NULL;
+
+      buf += size;
+      len -= size;
+      filepos += size;
+      ret += size;
+    }
+
+  if (errnum)
+    ret = 0;
+
+  return ret;
+}
+
+/* preconditions: minix_mount already executed, therefore supblk in buffer
+     known as SUPERBLOCK
+   returns: 0 if error, nonzero iff we were able to find the file successfully
+   postconditions: on a nonzero return, buffer known as INODE contains the
+     inode of the file we were trying to look up
+   side effects: none yet  */
+int
+minix_dir (char *dirname)
+{
+  int current_ino = MINIX_ROOT_INO;  /* start at the root */
+  int updir_ino = current_ino;	     /* the parent of the current directory */
+  int ino_blk;			     /* fs pointer of the inode's info */
+
+  int str_chk = 0;		     /* used ot hold the results of a string
+				        compare */
+
+  struct minix_inode * raw_inode;    /* inode info for current_ino */
+
+  char linkbuf[PATH_MAX];	     /* buffer for following sym-links */
+  int link_count = 0;
+
+  char * rest;
+  char ch;
+
+  int off;			     /* offset within block of directory 
+					entry */
+  int loc;			     /* location within a directory */
+  int blk;			     /* which data blk within dir entry */
+  long map;			     /* fs pointer of a particular block from
+					dir entry */
+  struct minix_dir_entry * dp;	     /* pointer to directory entry */
+
+  /* loop invariants:
+     current_ino = inode to lookup
+     dirname = pointer to filename component we are cur looking up within
+     the directory known pointed to by current_ino (if any) */
+
+#ifdef DEBUG_MINIX
+  printf ("\n");
+#endif  
+
+  while (1)
+    {
+#ifdef DEBUG_MINIX
+      printf ("inode %d, dirname %s\n", current_ino, dirname);
+#endif
+
+      ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
+		 + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
+      if (! minix_rdfsb (ino_blk, (int) INODE))
+	return 0;
+
+      /* reset indirect blocks! */
+      mapblock2 = mapblock1 = -1;
+
+      raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
+
+      /* copy inode to fixed location */
+      memmove ((void *) INODE, (void *) raw_inode, 
+	       sizeof (struct minix_inode));
+
+      /* If we've got a symbolic link, then chase it. */
+      if (S_ISLNK (INODE->i_mode))
+	{
+	  int len;
+
+	  if (++link_count > MAX_LINK_COUNT)
+	    {
+	      errnum = ERR_SYMLINK_LOOP;
+	      return 0;
+	    }
+#ifdef DEBUG_MINIX
+	  printf ("S_ISLNK (%s)\n", dirname);
+#endif
+
+	  /* Find out how long our remaining name is. */
+	  len = 0;
+	  while (dirname[len] && !isspace (dirname[len]))
+	    len++;
+
+	  /* Get the symlink size. */
+	  filemax = (INODE->i_size);
+	  if (filemax + len > sizeof (linkbuf) - 2)
+	    {
+	      errnum = ERR_FILELENGTH;
+	      return 0;
+	    }
+
+	  if (len)
+	    {
+	      /* Copy the remaining name to the end of the symlink data.
+	         Note that DIRNAME and LINKBUF may overlap! */
+	      memmove (linkbuf + filemax, dirname, len);
+	    }
+	  linkbuf[filemax + len] = '\0';
+
+	  /* Read the necessary blocks, and reset the file pointer. */
+	  len = grub_read (linkbuf, filemax);
+	  filepos = 0;
+	  if (!len)
+	    return 0;
+
+#ifdef DEBUG_MINIX
+	  printf ("symlink=%s\n", linkbuf);
+#endif
+
+	  dirname = linkbuf;
+	  if (*dirname == '/')
+	    {
+	      /* It's an absolute link, so look it up in root. */
+	      current_ino = MINIX_ROOT_INO;
+	      updir_ino = current_ino;
+	    }
+	  else
+	    {
+	      /* Relative, so look it up in our parent directory. */
+	      current_ino = updir_ino;
+	    }
+
+	  /* Try again using the new name. */
+	  continue;
+	}
+
+      /* If end of filename, INODE points to the file's inode */
+      if (!*dirname || isspace (*dirname))
+	{
+	  if (!S_ISREG (INODE->i_mode))
+	    {
+	      errnum = ERR_BAD_FILETYPE;
+	      return 0;
+	    }
+
+	  filemax = (INODE->i_size);
+	  return 1;
+	}
+
+      /* else we have to traverse a directory */
+      updir_ino = current_ino;
+
+      /* skip over slashes */
+      while (*dirname == '/')
+	dirname++;
+
+      /* if this isn't a directory of sufficient size to hold our file, 
+	 abort */
+      if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
+	{
+	  errnum = ERR_BAD_FILETYPE;
+	  return 0;
+	}
+
+      /* skip to next slash or end of filename (space) */
+      for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+	   rest++);
+
+      /* look through this directory and find the next filename component */
+      /* invariant: rest points to slash after the next filename component */
+      *rest = 0;
+      loc = 0;
+
+      do
+	{
+#ifdef DEBUG_MINIX
+	  printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
+#endif
+
+	  /* if our location/byte offset into the directory exceeds the size,
+	     give up */
+	  if (loc >= INODE->i_size)
+	    {
+	      if (print_possibilities < 0)
+		{
+#if 0
+		  putchar ('\n');
+#endif
+		}
+	      else
+		{
+		  errnum = ERR_FILE_NOT_FOUND;
+		  *rest = ch;
+		}
+	      return (print_possibilities < 0);
+	    }
+
+	  /* else, find the (logical) block component of our location */
+	  blk = loc >> BLOCK_SIZE_BITS;
+
+	  /* we know which logical block of the directory entry we are looking
+	     for, now we have to translate that to the physical (fs) block on
+	     the disk */
+	  map = minix_block_map (blk);
+#ifdef DEBUG_MINIX
+	  printf ("fs block=%d\n", map);
+#endif
+	  mapblock2 = -1;
+	  if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
+	    {
+	      errnum = ERR_FSYS_CORRUPT;
+	      *rest = ch;
+	      return 0;
+	    }
+	  off = loc & (BLOCK_SIZE - 1);
+	  dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
+	  /* advance loc prematurely to next on-disk directory entry  */
+	  loc += sizeof (dp->inode) + namelen;
+
+	  /* NOTE: minix filenames are NULL terminated if < NAMELEN
+	     else exact */
+
+#ifdef DEBUG_MINIX
+	  printf ("directory entry ino=%d\n", dp->inode);
+	  if (dp->inode)
+	    printf ("entry=%s\n", dp->name);
+#endif
+
+	  if (dp->inode)
+	    {
+	      int saved_c = dp->name[namelen];
+
+	      dp->name[namelen] = 0;
+	      str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+	      if (print_possibilities && ch != '/'
+		  && (!*dirname || str_chk <= 0))
+		{
+		  if (print_possibilities > 0)
+		    print_possibilities = -print_possibilities;
+		  print_a_completion (dp->name);
+		}
+# endif
+
+	      dp->name[namelen] = saved_c;
+	    }
+
+	}
+      while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
+
+      current_ino = dp->inode;
+      *(dirname = rest) = ch;
+    }
+  /* never get here */
+}
+

Added: trunk/filo/fs/fsys_reiserfs.c
===================================================================
--- trunk/filo/fs/fsys_reiserfs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_reiserfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1227 @@
+/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000, 2001  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 "shared.h"
+#include "filesys.h"
+
+#undef REISERDEBUG
+
+/* Some parts of this code (mainly the structures and defines) are
+ * from the original reiser fs code, as found in the linux kernel.
+ */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef unsigned long long __u64;
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/little_endian.h */
+#define __cpu_to_le64(x) ((__u64) (x))
+#define __le64_to_cpu(x) ((__u64) (x))
+#define __cpu_to_le32(x) ((__u32) (x))
+#define __le32_to_cpu(x) ((__u32) (x))
+#define __cpu_to_le16(x) ((__u16) (x))
+#define __le16_to_cpu(x) ((__u16) (x))
+
+/* include/linux/reiser_fs.h */
+/* This is the new super block of a journaling reiserfs system */
+struct reiserfs_super_block
+{
+  __u32 s_block_count;			/* blocks count         */
+  __u32 s_free_blocks;                  /* free blocks count    */
+  __u32 s_root_block;           	/* root block number    */
+  __u32 s_journal_block;           	/* journal block number    */
+  __u32 s_journal_dev;           	/* journal device number  */
+  __u32 s_journal_size; 		/* size of the journal on FS creation.  used to make sure they don't overflow it */
+  __u32 s_journal_trans_max;            /* max number of blocks in a transaction.  */
+  __u32 s_journal_magic;                /* random value made on fs creation */
+  __u32 s_journal_max_batch;            /* max number of blocks to batch into a trans */
+  __u32 s_journal_max_commit_age;       /* in seconds, how old can an async commit be */
+  __u32 s_journal_max_trans_age;        /* in seconds, how old can a transaction be */
+  __u16 s_blocksize;                   	/* block size           */
+  __u16 s_oid_maxsize;			/* max size of object id array  */
+  __u16 s_oid_cursize;			/* current size of object id array */
+  __u16 s_state;                       	/* valid or error       */
+  char s_magic[16];                     /* reiserfs magic string indicates that file system is reiserfs */
+  __u16 s_tree_height;                  /* height of disk tree */
+  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
+  __u16 s_version;
+  char s_unused[128];			/* zero filled by mkreiserfs */
+};
+
+#define REISERFS_MAX_SUPPORTED_VERSION 2
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+#define MAX_HEIGHT 7
+
+/* must be correct to keep the desc and commit structs at 4k */
+#define JOURNAL_TRANS_HALF 1018
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+  __u32 j_trans_id;			/* id of commit */
+  __u32 j_len;				/* length of commit. len +1 is the commit block */
+  __u32 j_mount_id;			/* mount id of this trans*/
+  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */
+  char j_magic[12];
+};
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+  __u32 j_trans_id;			/* must match j_trans_id from the desc block */
+  __u32 j_len;			/* ditto */
+  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */
+  char j_digest[16];			/* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
+};
+
+/* this header block gets written whenever a transaction is considered
+   fully flushed, and is more recent than the last fully flushed
+   transaction.  
+   fully flushed means all the log blocks and all the real blocks are
+   on disk, and this transaction does not need to be replayed.  
+*/
+struct reiserfs_journal_header {
+  /* id of last fully flushed transaction */
+  __u32 j_last_flush_trans_id;
+  /* offset in the log of where to start replay after a crash */
+  __u32 j_first_unflushed_offset;
+  /* mount id to detect very old transactions */
+  __u32 j_mount_id;
+};
+
+/* magic string to find desc blocks in the journal */
+#define JOURNAL_DESC_MAGIC "ReIsErLB" 
+
+
+/*
+ * directories use this key as well as old files
+ */
+struct offset_v1
+{
+  /*
+   * for regular files this is the offset to the first byte of the
+   * body, contained in the object-item, as measured from the start of
+   * the entire body of the object.
+   *
+   * for directory entries, k_offset consists of hash derived from
+   * hashing the name and using few bits (23 or more) of the resulting
+   * hash, and generation number that allows distinguishing names with
+   * hash collisions. If number of collisions overflows generation
+   * number, we return EEXIST.  High order bit is 0 always 
+   */
+  __u32 k_offset;
+  __u32 k_uniqueness;
+};
+
+struct offset_v2
+{
+  /*
+   * for regular files this is the offset to the first byte of the
+   * body, contained in the object-item, as measured from the start of
+   * the entire body of the object.
+   *
+   * for directory entries, k_offset consists of hash derived from
+   * hashing the name and using few bits (23 or more) of the resulting
+   * hash, and generation number that allows distinguishing names with
+   * hash collisions. If number of collisions overflows generation
+   * number, we return EEXIST.  High order bit is 0 always 
+   */
+  __u64 k_offset:60;
+  __u64 k_type: 4;
+};
+
+
+struct key
+{
+  /* packing locality: by default parent directory object id */
+  __u32 k_dir_id;
+  /* object identifier */
+  __u32 k_objectid;
+  /* the offset and node type (old and new form) */
+  union
+  {
+    struct offset_v1 v1;
+    struct offset_v2 v2;
+  }
+  u;
+};
+
+#define KEY_SIZE (sizeof (struct key))
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head
+{       
+  __u16 blk_level;        /* Level of a block in the tree. */
+  __u16 blk_nr_item;      /* Number of keys/items in a block. */
+  __u16 blk_free_space;   /* Block free space in bytes. */
+  struct key  blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes
+				      only) */
+};
+#define BLKH_SIZE (sizeof (struct block_head))
+#define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.                       */
+
+struct item_head
+{
+  struct key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/
+  
+  union
+  {
+    __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this
+			    is an indirect item.  This equals 0xFFFF iff this is a direct item or
+			    stat data item. Note that the key, not this field, is used to determine
+			    the item type, and thus which field this union contains. */
+    __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
+			     entries in the directory item. */
+  }
+  u;
+  __u16 ih_item_len;           /* total size of the item body                  */
+  __u16 ih_item_location;      /* an offset to the item body within the block  */
+  __u16 ih_version;	       /* ITEM_VERSION_1 for all old items, 
+				  ITEM_VERSION_2 for new ones. 
+				  Highest bit is set by fsck
+                                  temporary, cleaned after all done */
+};
+/* size of item header     */
+#define IH_SIZE (sizeof (struct item_head))
+
+#define ITEM_VERSION_1 0
+#define ITEM_VERSION_2 1
+#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \
+			   ? (ih)->ih_key.u.v1.k_offset \
+			   : (ih)->ih_key.u.v2.k_offset)
+
+#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \
+				 ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \
+				 : (ih)->ih_key.u.v2.k_type == V2_##type)
+
+struct disk_child
+{
+  unsigned long       dc_block_number;              /* Disk child's block number. */
+  unsigned short      dc_size;		            /* Disk child's used space.   */
+};
+
+#define DC_SIZE (sizeof (struct disk_child))
+
+/* Stat Data on disk.
+ *
+ * Note that reiserfs has two different forms of stat data.  Luckily
+ * the fields needed by grub are at the same position.
+ */
+struct stat_data
+{
+  __u16 sd_mode;	/* file type, permissions */
+  __u16 sd_notused1[3]; /* fields not needed by reiserfs */
+  __u32 sd_size;	/* file size */
+  __u32 sd_size_hi;	/* file size high 32 bits (since version 2) */
+};
+
+struct reiserfs_de_head
+{
+  __u32 deh_offset;  /* third component of the directory entry key */
+  __u32 deh_dir_id;  /* objectid of the parent directory of the
+			object, that is referenced by directory entry */
+  __u32 deh_objectid;/* objectid of the object, that is referenced by
+                        directory entry */
+  __u16 deh_location;/* offset of name in the whole item */
+  __u16 deh_state;   /* whether 1) entry contains stat data (for
+			future), and 2) whether entry is hidden
+			(unlinked) */
+};
+
+#define DEH_SIZE (sizeof (struct reiserfs_de_head))
+
+#define DEH_Statdata (1 << 0)			/* not used now */
+#define DEH_Visible  (1 << 2)
+
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+#define V1_TYPE_STAT_DATA 0x0
+#define V1_TYPE_DIRECT 0xffffffff
+#define V1_TYPE_INDIRECT 0xfffffffe
+#define V1_TYPE_DIRECTORY_MAX 0xfffffffd
+#define V2_TYPE_STAT_DATA 0
+#define V2_TYPE_INDIRECT 1
+#define V2_TYPE_DIRECT 2
+#define V2_TYPE_DIRENTRY 3 
+
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+#define REISERFS_OLD_BLOCKSIZE 4096
+
+#define S_ISREG(mode) (((mode) & 0170000) == 0100000)
+#define S_ISDIR(mode) (((mode) & 0170000) == 0040000)
+#define S_ISLNK(mode) (((mode) & 0170000) == 0120000)
+
+#define PATH_MAX       1024	/* include/linux/limits.h */
+#define MAX_LINK_COUNT    5	/* number of symbolic links to follow */
+
+/* The size of the node cache */
+#define FSYSREISER_CACHE_SIZE 24*1024
+#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE
+#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3
+
+/* Info about currently opened file */
+struct fsys_reiser_fileinfo
+{
+  __u32 k_dir_id;
+  __u32 k_objectid;
+};
+
+/* In memory info about the currently mounted filesystem */
+struct fsys_reiser_info
+{
+  /* The last read item head */
+  struct item_head *current_ih;
+  /* The last read item */
+  char *current_item;
+  /* The information for the currently opened file */
+  struct fsys_reiser_fileinfo fileinfo;
+  /* The start of the journal */
+  __u32 journal_block;
+  /* The size of the journal */
+  __u32 journal_block_count;
+  /* The first valid descriptor block in journal
+     (relative to journal_block) */
+  __u32 journal_first_desc;
+
+  /* The ReiserFS version. */
+  __u16 version;
+  /* The current depth of the reiser tree. */
+  __u16 tree_depth;
+  /* SECTOR_SIZE << blocksize_shift == blocksize. */
+  __u8  blocksize_shift;
+  /* 1 << full_blocksize_shift == blocksize. */
+  __u8  fullblocksize_shift;
+  /* The reiserfs block size  (must be a power of 2) */
+  __u16 blocksize;
+  /* The number of cached tree nodes */
+  __u16 cached_slots;
+  /* The number of valid transactions in journal */
+  __u16 journal_transactions;
+  
+  unsigned int blocks[MAX_HEIGHT];
+  unsigned int next_key_nr[MAX_HEIGHT];
+};
+
+/* The cached s+tree blocks in FSYS_BUF,  see below
+ * for a more detailed description.
+ */
+#define ROOT     ((char *) ((int) FSYS_BUF))
+#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift))
+#define LEAF     CACHE (DISK_LEAF_NODE_LEVEL)
+
+#define BLOCKHEAD(cache) ((struct block_head *) cache)
+#define ITEMHEAD         ((struct item_head  *) ((int) LEAF + BLKH_SIZE))
+#define KEY(cache)       ((struct key        *) ((int) cache + BLKH_SIZE))
+#define DC(cache)        ((struct disk_child *) \
+			  ((int) cache + BLKH_SIZE + KEY_SIZE * nr_item))
+/* The fsys_reiser_info block.
+ */
+#define INFO \
+    ((struct fsys_reiser_info *) ((int) FSYS_BUF + FSYSREISER_CACHE_SIZE))
+/* 
+ * The journal cache.  For each transaction it contains the number of
+ * blocks followed by the real block numbers of this transaction.  
+ *
+ * If the block numbers of some transaction won't fit in this space,
+ * this list is stopped with a 0xffffffff marker and the remaining
+ * uncommitted transactions aren't cached.  
+ */
+#define JOURNAL_START    ((__u32 *) (INFO + 1))
+#define JOURNAL_END      ((__u32 *) (FSYS_BUF + FSYS_BUFLEN))
+
+static __inline__ int
+is_power_of_two (unsigned long word)
+{
+  return (word & -word) == word;
+}
+
+static int 
+journal_read (int block, int len, char *buffer) 
+{
+  return devread ((INFO->journal_block + block) << INFO->blocksize_shift, 
+		  0, len, buffer);
+}
+
+/* Read a block from ReiserFS file system, taking the journal into
+ * account.  If the block nr is in the journal, the block from the
+ * journal taken.  
+ */
+static int
+block_read (int blockNr, int start, int len, char *buffer)
+{
+  int transactions = INFO->journal_transactions;
+  int desc_block = INFO->journal_first_desc;
+  int journal_mask = INFO->journal_block_count - 1;
+  int translatedNr = blockNr;
+  __u32 *journal_table = JOURNAL_START;
+  while (transactions-- > 0) 
+    {
+      int i = 0;
+      int j_len;
+      if (*journal_table != 0xffffffff)
+	{
+	  /* Search for the blockNr in cached journal */
+	  j_len = *journal_table++;
+	  while (i++ < j_len)
+	    {
+	      if (*journal_table++ == blockNr)
+		{
+		  journal_table += j_len - i;
+		  goto found;
+		}
+	    }
+	}
+      else
+	{
+	  /* This is the end of cached journal marker.  The remaining
+	   * transactions are still on disk.
+	   */
+	  struct reiserfs_journal_desc   desc;
+	  struct reiserfs_journal_commit commit;
+
+	  if (! journal_read (desc_block, sizeof (desc), (char *) &desc))
+	    return 0;
+
+	  j_len = desc.j_len;
+	  while (i < j_len && i < JOURNAL_TRANS_HALF)
+	    if (desc.j_realblock[i++] == blockNr)
+	      goto found;
+	  
+	  if (j_len >= JOURNAL_TRANS_HALF)
+	    {
+	      int commit_block = (desc_block + 1 + j_len) & journal_mask;
+	      if (! journal_read (commit_block, 
+				  sizeof (commit), (char *) &commit))
+		return 0;
+	      while (i < j_len)
+		if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr)
+		  goto found;
+	    }
+	}
+      goto not_found;
+      
+    found:
+      translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask);
+#ifdef REISERDEBUG
+      printf ("block_read: block %d is mapped to journal block %d.\n", 
+	      blockNr, translatedNr - INFO->journal_block);
+#endif
+      /* We must continue the search, as this block may be overwritten
+       * in later transactions.
+       */
+    not_found:
+      desc_block = (desc_block + 2 + j_len) & journal_mask;
+    }
+  return devread (translatedNr << INFO->blocksize_shift, start, len, buffer);
+}
+
+/* Init the journal data structure.  We try to cache as much as
+ * possible in the JOURNAL_START-JOURNAL_END space, but if it is full
+ * we can still read the rest from the disk on demand.
+ *
+ * The first number of valid transactions and the descriptor block of the
+ * first valid transaction are held in INFO.  The transactions are all 
+ * adjacent, but we must take care of the journal wrap around. 
+ */
+static int
+journal_init (void)
+{
+  unsigned int block_count = INFO->journal_block_count;
+  unsigned int desc_block;
+  unsigned int commit_block;
+  unsigned int next_trans_id;
+  struct reiserfs_journal_header header;
+  struct reiserfs_journal_desc   desc;
+  struct reiserfs_journal_commit commit;
+  __u32 *journal_table = JOURNAL_START;
+
+  journal_read (block_count, sizeof (header), (char *) &header);
+  desc_block = header.j_first_unflushed_offset;
+  if (desc_block >= block_count)
+    return 0;
+
+  INFO->journal_first_desc = desc_block;
+  next_trans_id = header.j_last_flush_trans_id + 1;
+
+#ifdef REISERDEBUG
+  printf ("journal_init: last flushed %d\n", 
+	  header.j_last_flush_trans_id);
+#endif
+
+  while (1) 
+    {
+      journal_read (desc_block, sizeof (desc), (char *) &desc);
+      if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0
+	  || desc.j_trans_id != next_trans_id
+	  || desc.j_mount_id != header.j_mount_id)
+	/* no more valid transactions */
+	break;
+      
+      commit_block = (desc_block + desc.j_len + 1) & (block_count - 1);
+      journal_read (commit_block, sizeof (commit), (char *) &commit);
+      if (desc.j_trans_id != commit.j_trans_id
+	  || desc.j_len != commit.j_len)
+	/* no more valid transactions */
+	break;
+      
+#ifdef REISERDEBUG
+      printf ("Found valid transaction %d/%d at %d.\n", 
+	      desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+      next_trans_id++;
+      if (journal_table < JOURNAL_END)
+	{
+	  if ((journal_table + 1 + desc.j_len) >= JOURNAL_END)
+	    {
+	      /* The table is almost full; mark the end of the cached
+	       * journal.*/
+	      *journal_table = 0xffffffff;
+	      journal_table = JOURNAL_END;
+	    }
+	  else
+	    {
+	      int i;
+	      /* Cache the length and the realblock numbers in the table.
+	       * The block number of descriptor can easily be computed.
+	       * and need not to be stored here.
+	       */
+	      *journal_table++ = desc.j_len;
+	      for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++)
+		{
+		  *journal_table++ = desc.j_realblock[i];
+#ifdef REISERDEBUG
+		  printf ("block %d is in journal %d.\n", 
+			  desc.j_realblock[i], desc_block);
+#endif
+		}
+	      for (     ; i < desc.j_len; i++)
+		{
+		  *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF];
+#ifdef REISERDEBUG
+		  printf ("block %d is in journal %d.\n", 
+			  commit.j_realblock[i-JOURNAL_TRANS_HALF], 
+			  desc_block);
+#endif
+		}
+	    }
+	}
+      desc_block = (commit_block + 1) & (block_count - 1);
+    }
+#ifdef REISERDEBUG
+  printf ("Transaction %d/%d at %d isn't valid.\n", 
+	  desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+  INFO->journal_transactions
+    = next_trans_id - header.j_last_flush_trans_id - 1;
+  return errnum == 0;
+}
+
+/* check filesystem types and read superblock into memory buffer */
+int
+reiserfs_mount (void)
+{
+  struct reiserfs_super_block super;
+  int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+
+  if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+      || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), 
+		(char *) &super)
+      || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+	  && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+      || (/* check that this is not a copy inside the journal log */
+	  super.s_journal_block * super.s_blocksize
+	  <= REISERFS_DISK_OFFSET_IN_BYTES))
+    {
+      /* Try old super block position */
+      superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+      if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+	  || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), 
+			(char *) &super))
+	return 0;
+
+      if (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+	  && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+	{
+	  /* pre journaling super block ? */
+	  if (substring (REISERFS_SUPER_MAGIC_STRING, 
+			 (char*) ((int) &super + 20)) > 0)
+	    return 0;
+	  
+	  super.s_blocksize = REISERFS_OLD_BLOCKSIZE;
+	  super.s_journal_block = 0;
+	  super.s_version = 0;
+	}
+    }
+
+  /* check the version number.  */
+  if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION)
+    return 0;
+  
+  INFO->version = super.s_version;
+  INFO->blocksize = super.s_blocksize;
+  INFO->fullblocksize_shift = log2 (super.s_blocksize);
+  INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS;
+  INFO->cached_slots = 
+    (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1;
+
+#ifdef REISERDEBUG
+  printf ("reiserfs_mount: version=%d, blocksize=%d\n", 
+	  INFO->version, INFO->blocksize);
+#endif /* REISERDEBUG */
+
+  /* Clear node cache. */
+  memset (INFO->blocks, 0, sizeof (INFO->blocks));
+
+  if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE
+      || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE
+      || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize)
+    return 0;
+
+  /* Initialize journal code.  If something fails we end with zero
+   * journal_transactions, so we don't access the journal at all.  
+   */
+  INFO->journal_transactions = 0;
+  if (super.s_journal_block != 0 && super.s_journal_dev == 0)
+    {
+      INFO->journal_block = super.s_journal_block;
+      INFO->journal_block_count = super.s_journal_size;
+      if (is_power_of_two (INFO->journal_block_count))
+	journal_init ();
+
+      /* Read in super block again, maybe it is in the journal */
+      block_read (superblock >> INFO->blocksize_shift, 
+		  0, sizeof (struct reiserfs_super_block), (char *) &super);
+    }
+
+  if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT))
+    return 0;
+  
+  INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level;
+  
+#ifdef REISERDEBUG
+  printf ("root read_in: block=%d, depth=%d\n", 
+	  super.s_root_block, INFO->tree_depth);
+#endif /* REISERDEBUG */
+
+  if (INFO->tree_depth >= MAX_HEIGHT)
+    return 0;
+  if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL)
+    {
+      /* There is only one node in the whole filesystem, 
+       * which is simultanously leaf and root */
+      memcpy (LEAF, ROOT, INFO->blocksize);
+    }
+  return 1;
+}
+
+/***************** TREE ACCESSING METHODS *****************************/
+
+/* I assume you are familiar with the ReiserFS tree, if not go to
+ * http://www.namesys.com/content_table.html
+ *
+ * My tree node cache is organized as following
+ *   0   ROOT node
+ *   1   LEAF node  (if the ROOT is also a LEAF it is copied here
+ *   2-n other nodes on current path from bottom to top.  
+ *       if there is not enough space in the cache, the top most are
+ *       omitted.
+ *
+ * I have only two methods to find a key in the tree:
+ *   search_stat(dir_id, objectid) searches for the stat entry (always
+ *       the first entry) of an object.
+ *   next_key() gets the next key in tree order.
+ *
+ * This means, that I can only sequential reads of files are
+ * efficient, but this really doesn't hurt for grub.  
+ */
+
+/* Read in the node at the current path and depth into the node cache.
+ * You must set INFO->blocks[depth] before.
+ */
+static char *
+read_tree_node (unsigned int blockNr, int depth)
+{
+  char* cache = CACHE(depth);
+  int num_cached = INFO->cached_slots;
+  if (depth < num_cached)
+    {
+      /* This is the cached part of the path.  Check if same block is
+       * needed.  
+       */
+      if (blockNr == INFO->blocks[depth])
+	return cache;
+    }
+  else
+    cache = CACHE(num_cached);
+
+#ifdef REISERDEBUG
+  printf ("  next read_in: block=%d (depth=%d)\n",
+	  blockNr, depth);
+#endif /* REISERDEBUG */
+  if (! block_read (blockNr, 0, INFO->blocksize, cache))
+    return 0;
+  /* Make sure it has the right node level */
+  if (BLOCKHEAD (cache)->blk_level != depth)
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return 0;
+    }
+
+  INFO->blocks[depth] = blockNr;
+  return cache;
+}
+
+/* Get the next key, i.e. the key following the last retrieved key in
+ * tree order.  INFO->current_ih and 
+ * INFO->current_info are adapted accordingly.  */
+static int
+next_key (void)
+{
+  int depth;
+  struct item_head *ih = INFO->current_ih + 1;
+  char *cache;
+  
+#ifdef REISERDEBUG
+  printf ("next_key:\n  old ih: key %d:%d:%d:%d version:%d\n", 
+	  INFO->current_ih->ih_key.k_dir_id, 
+	  INFO->current_ih->ih_key.k_objectid, 
+	  INFO->current_ih->ih_key.u.v1.k_offset,
+	  INFO->current_ih->ih_key.u.v1.k_uniqueness,
+	  INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+  
+  if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item])
+    {
+      depth = DISK_LEAF_NODE_LEVEL;
+      /* The last item, was the last in the leaf node.  
+       * Read in the next block 
+       */
+      do
+	{
+	  if (depth == INFO->tree_depth)
+	    {
+	      /* There are no more keys at all.
+	       * Return a dummy item with MAX_KEY */
+	      ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key;
+	      goto found;
+	    }
+	  depth++;
+#ifdef REISERDEBUG
+	  printf ("  depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]);
+#endif /* REISERDEBUG */
+	}
+      while (INFO->next_key_nr[depth] == 0);
+      
+      if (depth == INFO->tree_depth)
+	cache = ROOT;
+      else if (depth <= INFO->cached_slots)
+	cache = CACHE (depth);
+      else 
+	{
+	  cache = read_tree_node (INFO->blocks[depth], depth);
+	  if (! cache)
+	    return 0;
+	}
+      
+      do
+	{
+	  int nr_item = BLOCKHEAD (cache)->blk_nr_item;
+	  int key_nr = INFO->next_key_nr[depth]++;
+#ifdef REISERDEBUG
+	  printf ("  depth=%d, i=%d/%d\n", depth, key_nr, nr_item);
+#endif /* REISERDEBUG */
+	  if (key_nr == nr_item)
+	    /* This is the last item in this block, set the next_key_nr to 0 */
+	    INFO->next_key_nr[depth] = 0;
+
+	  cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth);
+	  if (! cache)
+	    return 0;
+	}
+      while (depth > DISK_LEAF_NODE_LEVEL);
+      
+      ih = ITEMHEAD;
+    }
+ found:
+  INFO->current_ih   = ih;
+  INFO->current_item = &LEAF[ih->ih_item_location];
+#ifdef REISERDEBUG
+  printf ("  new ih: key %d:%d:%d:%d version:%d\n", 
+	  INFO->current_ih->ih_key.k_dir_id, 
+	  INFO->current_ih->ih_key.k_objectid, 
+	  INFO->current_ih->ih_key.u.v1.k_offset,
+	  INFO->current_ih->ih_key.u.v1.k_uniqueness,
+	  INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+  return 1;
+}
+
+/* preconditions: reiserfs_mount already executed, therefore 
+ *   INFO block is valid
+ * returns: 0 if error (errnum is set), 
+ *   nonzero iff we were able to find the key successfully.
+ * postconditions: on a nonzero return, the current_ih and 
+ *   current_item fields describe the key that equals the
+ *   searched key.  INFO->next_key contains the next key after
+ *   the searched key.
+ * side effects: messes around with the cache.
+ */
+static int
+search_stat (__u32 dir_id, __u32 objectid) 
+{
+  char *cache;
+  int depth;
+  int nr_item;
+  int i;
+  struct item_head *ih;
+#ifdef REISERDEBUG
+  printf ("search_stat:\n  key %d:%d:0:0\n", dir_id, objectid);
+#endif /* REISERDEBUG */
+  
+  depth = INFO->tree_depth;
+  cache = ROOT;
+  
+  while (depth > DISK_LEAF_NODE_LEVEL)
+    {
+      struct key *key;
+      nr_item = BLOCKHEAD (cache)->blk_nr_item;
+      
+      key = KEY (cache);
+      
+      for (i = 0; i < nr_item; i++) 
+	{
+	  if (key->k_dir_id > dir_id
+	      || (key->k_dir_id == dir_id 
+		  && (key->k_objectid > objectid
+		      || (key->k_objectid == objectid
+			  && (key->u.v1.k_offset
+			      | key->u.v1.k_uniqueness) > 0))))
+	    break;
+	  key++;
+	}
+      
+#ifdef REISERDEBUG
+      printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+      INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1;
+      cache = read_tree_node (DC (cache)[i].dc_block_number, --depth);
+      if (! cache)
+	return 0;
+    }
+  
+  /* cache == LEAF */
+  nr_item = BLOCKHEAD (LEAF)->blk_nr_item;
+  ih = ITEMHEAD;
+  for (i = 0; i < nr_item; i++) 
+    {
+      if (ih->ih_key.k_dir_id == dir_id 
+	  && ih->ih_key.k_objectid == objectid
+	  && ih->ih_key.u.v1.k_offset == 0
+	  && ih->ih_key.u.v1.k_uniqueness == 0)
+	{
+#ifdef REISERDEBUG
+	  printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+	  INFO->current_ih   = ih;
+	  INFO->current_item = &LEAF[ih->ih_item_location];
+	  return 1;
+	}
+      ih++;
+    }
+  errnum = ERR_FSYS_CORRUPT;
+  return 0;
+}
+
+int
+reiserfs_read (char *buf, int len)
+{
+  unsigned int blocksize;
+  unsigned int offset;
+  unsigned int to_read;
+  char *prev_buf = buf;
+  
+#ifdef REISERDEBUG
+  printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n",
+	  filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1);
+#endif /* REISERDEBUG */
+  
+  if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid
+      || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1)
+    {
+      search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid);
+      goto get_next_key;
+    }
+  
+  while (! errnum)
+    {
+      if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid)
+	break;
+      
+      offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1;
+      blocksize = INFO->current_ih->ih_item_len;
+      
+#ifdef REISERDEBUG
+      printf ("  loop: filepos=%d len=%d, offset=%d blocksize=%d\n",
+	      filepos, len, offset, blocksize);
+#endif /* REISERDEBUG */
+      
+      if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT)
+	  && offset < blocksize)
+	{
+#ifdef REISERDEBUG
+	  printf ("direct_read: offset=%d, blocksize=%d\n",
+		  offset, blocksize);
+#endif /* REISERDEBUG */
+	  to_read = blocksize - offset;
+	  if (to_read > len)
+	    to_read = len;
+	  
+	  if (disk_read_hook != NULL)
+	    {
+	      disk_read_func = disk_read_hook;
+	      
+	      block_read (INFO->blocks[DISK_LEAF_NODE_LEVEL],
+			  (INFO->current_item - LEAF + offset), to_read, buf);
+	      
+	      disk_read_func = NULL;
+	    }
+	  else
+	    memcpy (buf, INFO->current_item + offset, to_read);
+	  goto update_buf_len;
+	}
+      else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT))
+	{
+	  blocksize = (blocksize >> 2) << INFO->fullblocksize_shift;
+#ifdef REISERDEBUG
+	  printf ("indirect_read: offset=%d, blocksize=%d\n",
+		  offset, blocksize);
+#endif /* REISERDEBUG */
+	  
+	  while (offset < blocksize)
+	    {
+	      __u32 blocknr = ((__u32 *) INFO->current_item)
+		[offset >> INFO->fullblocksize_shift];
+	      int blk_offset = offset & (INFO->blocksize-1);
+	      
+	      to_read = INFO->blocksize - blk_offset;
+	      if (to_read > len)
+		to_read = len;
+	      
+	      disk_read_func = disk_read_hook;
+	      
+	      /* Journal is only for meta data.  Data blocks can be read
+	       * directly without using block_read
+	       */
+	      devread (blocknr << INFO->blocksize_shift,
+		       blk_offset, to_read, buf);
+	      
+	      disk_read_func = NULL;
+	    update_buf_len:
+	      len -= to_read;
+	      buf += to_read;
+	      offset += to_read;
+	      filepos += to_read;
+	      if (len == 0)
+		goto done;
+	    }
+	}
+    get_next_key:
+      next_key ();
+    }
+ done:
+  return errnum ? 0 : buf - prev_buf;
+}
+
+
+/* preconditions: reiserfs_mount already executed, therefore 
+ *   INFO block is valid
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, INFO->fileinfo contains the info
+ *   of the file we were trying to look up, filepos is 0 and filemax is 
+ *   the size of the file.
+ */
+int
+reiserfs_dir (char *dirname)
+{
+  struct reiserfs_de_head *de_head;
+  char *rest, ch;
+  __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;
+#ifndef STAGE1_5
+  int do_possibilities = 0;
+#endif /* ! STAGE1_5 */
+  char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
+  int link_count = 0;
+  int mode;
+
+  dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+  objectid = REISERFS_ROOT_OBJECTID;
+  
+  while (1)
+    {
+#ifdef REISERDEBUG
+      printf ("dirname=%s\n", dirname);
+#endif /* REISERDEBUG */
+      
+      /* Search for the stat info first. */
+      if (! search_stat (dir_id, objectid))
+	return 0;
+      
+#ifdef REISERDEBUG
+      printf ("sd_mode=%x sd_size=%d\n", 
+	      ((struct stat_data *) INFO->current_item)->sd_mode,
+	      ((struct stat_data *) INFO->current_item)->sd_size);
+#endif /* REISERDEBUG */
+      
+      mode = ((struct stat_data *) INFO->current_item)->sd_mode;
+
+      /* If we've got a symbolic link, then chase it. */
+      if (S_ISLNK (mode))
+	{
+	  int len;
+	  if (++link_count > MAX_LINK_COUNT)
+	    {
+	      errnum = ERR_SYMLINK_LOOP;
+	      return 0;
+	    }
+
+	  /* Get the symlink size. */
+	  filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+	  /* Find out how long our remaining name is. */
+	  len = 0;
+	  while (dirname[len] && !isspace (dirname[len]))
+	    len++;
+
+	  if (filemax + len > sizeof (linkbuf) - 1)
+	    {
+	      errnum = ERR_FILELENGTH;
+	      return 0;
+	    }
+ 	  
+	  /* Copy the remaining name to the end of the symlink data.
+	     Note that DIRNAME and LINKBUF may overlap! */
+	  grub_memmove (linkbuf + filemax, dirname, len+1);
+
+	  INFO->fileinfo.k_dir_id = dir_id;
+	  INFO->fileinfo.k_objectid = objectid;
+  	  filepos = 0;
+	  if (! next_key ()
+	      || reiserfs_read (linkbuf, filemax) != filemax)
+	    {
+	      if (! errnum)
+		errnum = ERR_FSYS_CORRUPT;
+	      return 0;
+	    }
+
+#ifdef REISERDEBUG
+	  printf ("symlink=%s\n", linkbuf);
+#endif /* REISERDEBUG */
+
+	  dirname = linkbuf;
+	  if (*dirname == '/')
+	    {
+	      /* It's an absolute link, so look it up in root. */
+	      dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+	      objectid = REISERFS_ROOT_OBJECTID;
+	    }
+	  else
+	    {
+	      /* Relative, so look it up in our parent directory. */
+	      dir_id   = parent_dir_id;
+	      objectid = parent_objectid;
+	    }
+
+	  /* Now lookup the new name. */
+	  continue;
+	}
+
+      /* if we have a real file (and we're not just printing possibilities),
+	 then this is where we want to exit */
+      
+      if (! *dirname || isspace (*dirname))
+	{
+	  if (! S_ISREG (mode))
+	    {
+	      errnum = ERR_BAD_FILETYPE;
+	      return 0;
+	    }
+	  
+	  filepos = 0;
+	  filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+	  
+	  /* If this is a new stat data and size is > 4GB set filemax to 
+	   * maximum
+	   */
+	  if (INFO->current_ih->ih_version == ITEM_VERSION_2
+	      && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0)
+	    filemax = 0xffffffff;
+	  
+	  INFO->fileinfo.k_dir_id = dir_id;
+	  INFO->fileinfo.k_objectid = objectid;
+	  return next_key ();
+	}
+      
+      /* continue with the file/directory name interpretation */
+      while (*dirname == '/')
+	dirname++;
+      if (! S_ISDIR (mode))
+	{
+	  errnum = ERR_BAD_FILETYPE;
+	  return 0;
+	}
+      for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++);
+      *rest = 0;
+      
+# ifndef STAGE1_5
+      if (print_possibilities && ch != '/')
+	do_possibilities = 1;
+# endif /* ! STAGE1_5 */
+      
+      while (1)
+	{
+	  char *name_end;
+	  int num_entries;
+	  
+	  if (! next_key ())
+	    return 0;
+#ifdef REISERDEBUG
+	  printf ("ih: key %d:%d:%d:%d version:%d\n", 
+		  INFO->current_ih->ih_key.k_dir_id, 
+		  INFO->current_ih->ih_key.k_objectid, 
+		  INFO->current_ih->ih_key.u.v1.k_offset,
+		  INFO->current_ih->ih_key.u.v1.k_uniqueness,
+		  INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+	  
+	  if (INFO->current_ih->ih_key.k_objectid != objectid)
+	    break;
+	  
+	  name_end = INFO->current_item + INFO->current_ih->ih_item_len;
+	  de_head = (struct reiserfs_de_head *) INFO->current_item;
+	  num_entries = INFO->current_ih->u.ih_entry_count;
+	  while (num_entries > 0)
+	    {
+	      char *filename = INFO->current_item + de_head->deh_location;
+	      char  tmp = *name_end;
+	      if ((de_head->deh_state & DEH_Visible))
+		{
+		  int cmp;
+		  /* Directory names in ReiserFS are not null
+		   * terminated.  We write a temporary 0 behind it.
+		   * NOTE: that this may overwrite the first block in
+		   * the tree cache.  That doesn't hurt as long as we
+		   * don't call next_key () in between.  
+		   */
+		  *name_end = 0;
+		  cmp = substring (dirname, filename);
+		  *name_end = tmp;
+# ifndef STAGE1_5
+		  if (do_possibilities)
+		    {
+		      if (cmp <= 0)
+			{
+			  if (print_possibilities > 0)
+			    print_possibilities = -print_possibilities;
+			  *name_end = 0;
+			  print_a_completion (filename);
+			  *name_end = tmp;
+			}
+		    }
+		  else
+# endif /* ! STAGE1_5 */
+		    if (cmp == 0)
+		      goto found;
+		}
+	      /* The beginning of this name marks the end of the next name.
+	       */
+	      name_end = filename;
+	      de_head++;
+	      num_entries--;
+	    }
+	}
+      
+# ifndef STAGE1_5
+      if (print_possibilities < 0)
+	return 1;
+# endif /* ! STAGE1_5 */
+      
+      errnum = ERR_FILE_NOT_FOUND;
+      *rest = ch;
+      return 0;
+      
+    found:
+      
+      *rest = ch;
+      dirname = rest;
+
+      parent_dir_id = dir_id;
+      parent_objectid = objectid;
+      dir_id = de_head->deh_dir_id;
+      objectid = de_head->deh_objectid;
+    }
+}
+
+int
+reiserfs_embed (int *start_sector, int needed_sectors)
+{
+  struct reiserfs_super_block super;
+  int num_sectors;
+  
+  if (! devread (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0, 
+		 sizeof (struct reiserfs_super_block), (char *) &super))
+    return 0;
+  
+  *start_sector = 1; /* reserve first sector for stage1 */
+  if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+       || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+       || substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) <= 0)
+      && (/* check that this is not a super block copy inside
+	   * the journal log */
+	  super.s_journal_block * super.s_blocksize 
+	  > REISERFS_DISK_OFFSET_IN_BYTES))
+    num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+  else
+    num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+  
+  return (needed_sectors <= num_sectors);
+}
+

Added: trunk/filo/fs/fsys_squashfs.c
===================================================================
--- trunk/filo/fs/fsys_squashfs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_squashfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1102 @@
+/*
+ *  Squashfs filesystem backend for GRUB (GRand Unified Bootloader)
+ *
+ *  Copyright (C) 2006  Luc Saillard  <luc at saillard.org>
+ *
+ *  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 "shared.h"
+#include "filesys.h"
+#include "squashfs_fs.h"
+#include "squashfs_zlib.h"
+
+#define SUPERBLOCK ((struct squashfs_super_block *) (FSYS_BUF))
+#define INODE_DATA ((union squashfs_inode_header *)\
+    			((int)SUPERBLOCK + (((sizeof(struct squashfs_super_block)>>5)+1)*32)))
+/* 
+ * We need to allocate two buffers of SQUASHFS_FILE_MAX_SIZE.
+ * One will be used to lad the compressed data (that can be as large as
+ * SQUASHFS_FILE_MAX_SIZE) and one that store the uncompressed data.  Our
+ * current gunzip implementation doesn't support uncompress in place.
+ *
+ * Force a value in the array, to force gcc to allocate the buffer into the
+ * data section, and not in bss section. Else grub will not allocate the
+ * memory.
+ */
+static unsigned char cbuf_data[SQUASHFS_FILE_MAX_SIZE] = {1};
+static unsigned char file_data[SQUASHFS_FILE_MAX_SIZE] = {1};
+
+#define CBUF_DATA ((unsigned char *)cbuf_data)
+#define FILE_DATA ((unsigned char *)file_data)
+
+/* Use to cache the block data that is in FILE_DATA */
+static int squashfs_old_block = -1;
+
+
+#undef SQUASHFS_TRACE
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...) \
+  do { printf("squashfs: <%s> "s, __PRETTY_FUNCTION__, ## args); } while(0)
+static const char *get_type(int type);
+#else
+#define TRACE(s, args...)
+#endif
+
+static void dump_memory(const void *buffer, int len);
+static void inode_print(union squashfs_inode_header *inode);
+static int inode_read(unsigned int inode_block, unsigned int inode_offset);
+
+
+/*
+ * Read a raw block at @address, length @len and put data in @output_data
+ *
+ * @arg address:
+ * @arg len:
+ * @arg output_data:
+ *
+ * @return the number of bytes read
+ */
+static int read_bytes(long long address, unsigned int len, void *output_data)
+{
+  unsigned int block_number, offset;
+  int ret;
+
+  block_number = address >> SECTOR_BITS;
+  offset = address - (block_number);
+
+  TRACE("reading from position 0x%x, bytes %d\n", (int)address, len);
+  disk_read_func = disk_read_hook;
+  ret = devread(0, (int)address, len, output_data);
+  disk_read_func = NULL;
+  return ret;
+}
+
+
+/*
+ * Read a block located at @start and uncompress it into @output_data
+ *
+ * @arg start: block to read in the filesystem
+ * @arg compressed_size: store in this pointer, the size of the compressed
+ *                       block. So you can find the next compressed block using
+ *                       @start+ at compressed_size.
+ * @arg output_data: must an array of at least SQUASHFS_METADATA_SIZE which is the
+ *                   maximum size.
+ *
+ * @return the size of the decompressed block. If an error occur, 0 is returned.
+ */
+static int read_block(long long start, int *compressed_size, void *output_data)
+{
+  unsigned short int c_byte;
+  int offset = 2;
+
+  if (! read_bytes(start, sizeof(c_byte), &c_byte))
+   {
+     TRACE("read_block: Failed to read c_byte\n");
+     return 0;
+   }
+
+  TRACE("read_block: block @0x%x, %d %s bytes\n",
+        (int)start,
+	SQUASHFS_COMPRESSED_SIZE(c_byte),
+	SQUASHFS_COMPRESSED(c_byte) ? "compressed\0" : "uncompressed\0");
+
+  if (SQUASHFS_CHECK_DATA(SUPERBLOCK->flags))
+    offset = 3;
+
+  if (SQUASHFS_COMPRESSED(c_byte))
+   {
+     unsigned int bytes = SQUASHFS_METADATA_SIZE;
+     int res;
+
+     c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+     if (! read_bytes(start + offset, c_byte, CBUF_DATA))
+      {
+	TRACE("Failed to read at offset %x, size %d\n", (int)(start + offset), c_byte);
+	return 0;
+      }
+
+     res = squashfs_uncompress(output_data, &bytes, CBUF_DATA, c_byte);
+     dump_memory(output_data, 48);
+
+     if (res != Z_OK)
+      {
+	if (res == Z_MEM_ERROR)
+	  TRACE("zlib::uncompress failed, not enough memory\n");
+	else if (res == Z_BUF_ERROR)
+	  TRACE("zlib::uncompress failed, not enough room in output buffer\n");
+	else
+	  TRACE("zlib::uncompress failed, unknown error %d\n", res);
+	return 0;
+      }
+
+     if (compressed_size)
+       *compressed_size = offset + c_byte;
+     return bytes;
+   }
+  else
+   {
+     c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+
+     if (! read_bytes(start + offset, c_byte, output_data))
+      {
+	TRACE("Failed to read at offset %x, size %d\n", (int)(start + offset), c_byte);
+	return 0;
+      }
+
+     if (compressed_size)
+       *compressed_size = offset + c_byte;
+
+     return c_byte;
+   }
+}
+
+/*
+ * Read a data block located at @start and uncompress it into @block.
+ * The size of a data block is known in advance and is large of SQUASHFS_FILE_MAX_SIZE.
+ *
+ * @arg start: block to read in the filesystem
+ * @arg size: size of the block. The block can be compressed so it will be
+ *            uncompressed automatically.
+ * @arg output_data: must an array of at least SQUASHFS_METADATA_SIZE which is the
+ *             maximum size.
+ * @return the size of the decompressed block. If an error occur, 0 is returned.
+ */
+static int read_data_block(long long start, unsigned int size, void *output_data)
+{
+  int res;
+  unsigned int bytes = SUPERBLOCK->block_size;
+  int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
+
+  TRACE("block @0x%x, %d %s bytes\n",
+        (int)start,
+	SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte),
+	SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed");
+
+  if (SQUASHFS_COMPRESSED_BLOCK(size))
+   {
+     if (! read_bytes(start, c_byte, CBUF_DATA))
+       return 0;
+
+     res = squashfs_uncompress(output_data, &bytes, CBUF_DATA, c_byte);
+     dump_memory(CBUF_DATA, 48);
+
+     if (res != Z_OK)
+      {
+	if (res == Z_MEM_ERROR)
+	  TRACE("zlib::uncompress failed, not enough memory\n");
+	else if (res == Z_BUF_ERROR)
+	  TRACE("zlib::uncompress failed, not enough room in output buffer\n");
+	else
+	  TRACE("zlib::uncompress failed, unknown error %d\n", res);
+	return 0;
+      }
+
+     return bytes;
+   }
+  else
+   {
+     if (! read_bytes(start, c_byte, output_data))
+       return 0;
+
+     return c_byte;
+   }
+}
+
+
+/*
+ * Parse one directory header, and the return the corresponding inode for entry
+ * named @entry_name.
+ *
+ * @param dir_header: struct of a dir_header + a list of dir_entry
+ * @param entry_name: entry to find (ended by a nul character)
+ *
+ * @param result_inode_block: if the entry is present, return in this variable,
+ *                            the inode_block number in the inode_table
+ * @param result_inode_offset: if the entry is present, return in this variable,
+ *                            the offset position in the block_inode_table.
+ *
+ * @return 0 if the entry is found, (@result_inode_offset and @result_inode_offset is valid)
+ *        >0 the number of bytes read to parse the directory header, so this go to the next
+ *           directory_header.
+ *
+ * a directory is represented by a list of squashfs_dir_entry, and a squashfs_dir_header.
+ *
+ *   .-----------------------------------.
+ *   | squashfs_dir_header               |
+ *   |   --> count (number of dir_entry) |
+ *   |-----------------------------------|
+ *   |  squashfs_dir_entry(0)            |
+ *   |  ---------------------            |
+ *   |  name of squashfs_dir_entry(0)    |
+ *   |-----------------------------------|
+ *   |  squashfs_dir_entry(...)          |
+ *   |  -----------------------          |
+ *   |  name of squashfs_dir_entry(...)  |
+ *   |-----------------------------------|
+ *   |  squashfs_dir_entry(n)            |
+ *   |  ---------------------            |
+ *   |  name of squashfs_dir_entry(n)    |
+ *   |-----------------------------------|
+  */
+static int directory_lookup_1(const struct squashfs_dir_header *dir_header,
+    			      const char   *entry_name,
+			      unsigned int *result_inode_block,
+			      unsigned int *result_inode_offset)
+{
+  const unsigned char *data;
+  const struct squashfs_dir_entry *dir_entry;
+  int dir_count, i, offset;
+#ifdef SQUASHFS_TRACE
+  char temp_name[SQUASHFS_NAME_LEN+1];
+#endif
+
+  data = (const unsigned char *)dir_header;
+  offset = sizeof(struct squashfs_dir_header);
+  dir_count = dir_header->count + 1;
+  TRACE("Searching for %s in this directory (entries:%d inode:%d)\n",
+        entry_name, dir_count, dir_header->inode_number);
+
+  while (dir_count--)
+   {
+     dir_entry = (const struct squashfs_dir_entry *)(data + offset);
+     offset += sizeof(struct squashfs_dir_entry);
+
+#ifdef SQUASHFS_TRACE
+     memcpy(temp_name, data+offset, dir_entry->size+1);
+     temp_name[dir_entry->size+1] = 0;
+
+     TRACE("directory entry [%s]: offset:%d  type:%s  size:%d  inode_number:%x\n",
+	   temp_name, dir_entry->offset, get_type(dir_entry->type), dir_entry->size+1,
+	   dir_entry->inode_number);
+#endif
+
+     /* Do a strcmp between the current entry and the entry_name */
+     for (i=0; i<dir_entry->size+1; i++)
+      {
+	if (data[offset+i] != entry_name[i])
+	  break;
+      }
+     if (i == dir_entry->size+1 && entry_name[i] == 0)
+      {
+	*result_inode_block = dir_header->start_block;
+	*result_inode_offset = dir_entry->offset;
+	return 0;
+      }
+
+     offset += dir_entry->size+1;
+   }
+
+  return offset;
+}
+
+/*
+ * Lookup for entry @entry_name in the directory located at @@@inode_block:@inode_offset
+ * If the entry is present, return the inode block of the entry into
+ * @result_inode_block:@result_inode_offset.
+ *
+ * @param inode_block: inode block location of the directory
+ * @param inode_offset: inode offset location of the direcotry
+ * @param dir_size: the directory size. We need this inforamtion because a
+ *                  directory can be composed of a list of directory_header
+ * @param entryname: entry to find (ended by a nul character)
+ * @param result_inode_block: if the entry is present, return in this variable,
+ *                            the inode_block number in the inode_table
+ * @param result_inode_offset: if the entry is present, return in this variable,
+ *                            the offset position in the block_inode_table.
+ *
+ * @result: 0 if the entry was not found
+ *          1 if the entry is found, and fill @result_inode_block, @result_inode_offset
+ *
+ *
+ *  , @inode_block
+ *  |
+ *  |  .............
+ *  |  .............
+ *  |  ...       ...         ____ .------------------------.
+ *  \> .-----------.      __/     | directory_header(0)    | }
+ *     |           | ____/        |   ....                 |  }
+ *     |------------/             | directory_header(xxx)  |   }
+ *  -> |                          |   ...                  |    } dir_size
+ *  |  |------------\____         | directory_header(n)    |   }
+ *  |  |           |     \__      |   ...                  |  }
+ *  |  .           .        \___  |________________________| }
+ *  |  .___________.
+ *  |  ...       ...
+ *  |  .............
+ *  |  .............
+ *  |
+ *  \-- @inode_offset
+ *
+ */
+static int directory_lookup(unsigned int  inode_block,
+                            unsigned int  inode_offset,
+			    unsigned int  dir_size,
+			    const char   *entryname,
+			    unsigned int *result_inode_block,
+			    unsigned int *result_inode_offset)
+{
+  int offset = 0, res, compressed_size, bytes;
+  long long start = SUPERBLOCK->directory_table_start;
+  long long end = SUPERBLOCK->fragment_table_start;
+
+  TRACE("start=0x%x  end=0x%x (len=%d/0x%x)\n", (int)start, (int)end, (int)(end-start));
+
+  while (start < end)
+   {
+     TRACE("reading block 0x%x (offset=0x%x)\n", (int)start, offset);
+     res = read_block(start, &compressed_size, FILE_DATA);
+     if (res == 0)
+      {
+	TRACE("failed to read block\n");
+	return 0;
+      }
+
+     if (inode_block == offset)
+       break;
+     start += compressed_size;
+     offset += compressed_size;
+   }
+
+  if (inode_block != offset)
+   {
+     TRACE("directory block (0x%x:0x%x) was not found\n", inode_block, inode_offset);
+     return 0;
+   }
+
+  TRACE("inode block found at @0x%x\n", (int)start);
+
+  /* A block can be composed of several directory header */
+  bytes = 0;
+  while (bytes < dir_size)
+   {
+     struct squashfs_dir_header *dir_header;
+
+     dir_header = (struct squashfs_dir_header *)
+        		(FILE_DATA+inode_offset+bytes);
+     res = directory_lookup_1(dir_header,
+			      entryname,
+			      result_inode_block,
+			      result_inode_offset);
+     if (res == 0)
+       return 1;
+     bytes += res;
+   }
+  TRACE("entry %s not found in current directory\n", entryname);
+  return 0;
+}
+
+/*
+ * Search in this inode for entry named @entryname. If the entry was found
+ * @result_inode_block and @result_inode_offset is filled.
+ *
+ * INODE_DATA is modified
+ *
+ * If the inode is not a directory, then return 0.
+ *
+ * @param inode_block: inode block location of the directory
+ * @param inode_offset: inode offset location of the direcotry
+ * @param entryname: entry to find (ended by a nul character)
+ * @param result_inode_block: if the entry is present, return in this variable,
+ *                            the inode_block number in the inode_table
+ * @param result_inode_offset: if the entry is present, return in this variable,
+ *                            the offset position in the block_inode_table.
+ *
+ * @return 0 the entry was not found or an error occured
+ *         1 the entry is found, and @result_inode_block, @result_inode_offset is filled
+ *
+ */
+static int squashfs_lookup_directory(int inode_block,
+    				     int inode_offset,
+    				     const char *entryname,
+				     int *result_inode_block,
+				     int *result_inode_offset)
+{
+  int dir_start_block, dir_offset, dir_size;
+  unsigned int entry_start_block = 0, entry_offset = 0;
+
+  TRACE("Lookup in inode %d:%d for %s\n", inode_block, inode_offset, entryname);
+
+  if (! inode_read(inode_block, inode_offset))
+    return 0;
+
+  inode_print(INODE_DATA);
+
+  /* We only support type dir */
+  switch (INODE_DATA->base.inode_type)
+   {
+    case SQUASHFS_DIR_TYPE:
+      dir_start_block = INODE_DATA->dir.start_block;
+      dir_offset = INODE_DATA->dir.offset;
+      dir_size = INODE_DATA->dir.file_size - 3;
+      break;
+
+    case SQUASHFS_LDIR_TYPE:
+      dir_start_block = INODE_DATA->ldir.start_block;
+      dir_offset = INODE_DATA->ldir.offset;
+      dir_size = INODE_DATA->ldir.file_size - 3;
+      break;
+
+    default:
+      TRACE("This inode is not a directory\n");
+      errnum = ERR_BAD_FILETYPE;
+      return 0;
+   }
+
+  if (dir_size > SQUASHFS_METADATA_SIZE)
+   {
+     TRACE("Dir size is too large for our algorithm 0x23I29\n");
+     return 0;
+   }
+
+  /* Get the current directory header */
+  if (! directory_lookup(dir_start_block, dir_offset, dir_size, entryname, &entry_start_block, &entry_offset))
+   {
+     errnum = ERR_FILE_NOT_FOUND;
+     return 0;
+   }
+
+  TRACE("Found %s located at %x:%x\n", entryname, entry_start_block, entry_offset);
+
+  *result_inode_block = entry_start_block;
+  *result_inode_offset = entry_offset;
+
+  return 1;
+}
+
+
+/*
+ * Read the given inode (inode_block:inode_offset) and write the inode data
+ * into INODE_DATA.
+ *
+ * Description of the Squashfs inode table
+ *
+ * r---------- @inode_table_start
+ * |
+ * |
+ * |
+ * |
+ * -> .-----------------.                   array of squashfs_inode_entry
+ *    | inode block 1   |                    .---------------------------.
+ *    |_________________|                   /| @0                        |
+ *    | inode block 2   |                  / |---------------------------|
+ *    |_________________|                 /  |                           |
+ *    |                 |                /   |                           |
+ *    |                 |               /    |---------------------------|
+ *    |                 |@inode_block  /     | @inode_offset             |
+ *    |_________________|/____________/      |---------------------------|
+ *    |                 |                    |                           |
+ *    |                 |                    |                           |
+ *    |_________________|_____________       |                           |
+ *    |                 |             \      |                           |
+ *    |                 |              \     |                           |
+ *    |                 |               \----|___________________________|
+ *    |_________________|
+ *  
+ * an inode block is compressed, so the size length of the block is not known
+ * in advance, but an inode block always contains SQUASHFS_METADATA_SIZE length
+ * bytes.
+ *
+ * So we need to uncompressed all inode block to known the offset of the next
+ * block.
+ *
+ * Each inode doesn't have the same size, so we can't known in advance (without
+ * looking the type of the inode) which data to copy. So we copy all data until
+ * the end of the block.
+ *
+ */
+static int inode_read(unsigned int inode_block, unsigned int inode_offset)
+{
+  int offset = 0, res, compressed_size;
+  long long start = SUPERBLOCK->inode_table_start;
+  long long end = SUPERBLOCK->directory_table_start;
+
+  TRACE("start=0x%x  end=0x%x (len=%d/0x%x)   inode_wanted:%d:%d (0x%x:0x%x)\n",
+        (int)start, (int)end, (int)(end-start), (int)(end-start),
+	inode_block, inode_offset, inode_block, inode_offset);
+
+  while (start < end)
+   {
+     TRACE("reading block 0x%x (offset=0x%x  inode=0x%x:0x%x)\n", (int)start, offset, inode_block, inode_offset);
+     res = read_block(start, &compressed_size, INODE_DATA);
+     if (res == 0)
+      {
+	TRACE("uncompress_directory_table: failed to read block\n");
+	return 0;
+      }
+
+     if (inode_block == offset)
+      {
+	TRACE("Inode %d found @0x%x\n", (int)start);
+	if (inode_offset)
+	  memmove(INODE_DATA, (unsigned char *)INODE_DATA+inode_offset, SQUASHFS_METADATA_SIZE-inode_offset);
+	return 1;
+      }
+
+     start += compressed_size;
+     offset += compressed_size;
+   }
+  TRACE("Inode %d not found\n");
+  return 0;
+}
+
+/*
+ * Return the data block for the current @fragment_index.
+ *
+ * This function read each time the fragment_table so this can be slow to read
+ * all fragment_table in severall calls.
+ *
+ * @param fragment_index: the fragment data block.
+ * @param fragment_data: where to ouput the data. Need to be SQUASHFS_FILE_MAX_SIZE long.
+ *
+ * @return 0 if an error occured, or the fragment_block was not found
+ *        >0 the size of the fragment_data block
+ *
+ *
+ * Description of the Squashfs fragments table
+ *
+ * r---------- @fragment_table_start
+ * |
+ * |
+ * |
+ * |
+ * -> .-----------.     fragment_table(xxx)
+ *    |           |   -> .-------------.
+ *    |___________|__/   |_____________|
+ * -> | (xxx/yyy) | /    |             |       fragment_data(nnn)
+ * |  |___________|/     |_____________|       .-----------------.
+ * |  |           |   -->|   (nnn)      ====>  |                 |
+ * |  |           |   |  |-------------|       |                 |
+ * |  |           |   |  |             |       |                 |
+ * |  |           |   |  |             |       |                 |
+ * |  |___________|   |  |_____________|       |                 |
+ * |                  |                        |-----------------|
+ * |                  |
+ * fragment_index     @offset: yyy
+ *
+ *
+ * fragment_table(xxx) is compressed and contains severall @squashfs_fragment_entry.
+ * fragment_data(nnn) can be compressed and is shared between severall files.
+ *
+ */
+static int fragment_read(unsigned int fragment_index, void *fragment_data)
+{
+  int offset, i, indexes;
+  long long fragment_address;
+  struct squashfs_fragment_entry *fragment_entry;
+  unsigned char *fragments_table = FILE_DATA;
+
+  indexes = SQUASHFS_FRAGMENT_INDEXES(SUPERBLOCK->fragments);
+
+  TRACE("Reading fragment %d/%d  (%d fragments table that start @0x%x)\n",
+      INODE_DATA->reg.fragment, SUPERBLOCK->fragments,
+      indexes,
+      (int)SUPERBLOCK->fragment_table_start);
+
+  for (i=0; i<indexes; i++)
+   {
+     long long current_fragment_location;
+     int length;
+
+     fragment_address = SUPERBLOCK->fragment_table_start + i*sizeof(long long);
+     read_bytes(fragment_address, sizeof(long long), &current_fragment_location);
+
+     TRACE("Block fragment %d is located at @%x\n", i, (int)current_fragment_location);
+
+     length = read_block(current_fragment_location, NULL, fragments_table);
+     if (length == 0)
+       return 0;
+
+     TRACE("Read fragment block %d, length=%d\n", i, length);
+
+     if (SQUASHFS_FRAGMENT_INDEX(fragment_index) == i)
+       break;
+   }
+
+  if (i == indexes)
+   {
+     TRACE("Fragment %d not found\n", fragment_index);
+     return 0;
+   }
+
+  offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment_index);
+
+  fragment_entry = (struct squashfs_fragment_entry *)(fragments_table + offset);
+  TRACE("fragment %d: start_block=0x%x size=%d pending=%d\n",
+        fragment_index, (int)fragment_entry->start_block,
+	fragment_entry->size, fragment_entry->pending);
+
+
+  i = read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data);
+  if (i == 0)
+   {
+     TRACE("failed to read fragment %d\n", fragment_index);
+     return i;
+   }
+  return i;
+}
+
+/*
+ *
+ * Read one block from a inode file.
+ *
+ * The block_number is position in the list block.
+ * This function is not designed to be speedup, but accurate, and allocate the least memory.
+ *
+ * @arg file_inode: global inode header
+ * @arg SUPERBLOCK: description of the superblock
+ */
+static int squashfs_read_file_one_block(int block_number)
+{
+  long long start;
+  int fragment_size;
+  int blocks;
+  int i;
+
+  if (INODE_DATA->reg.fragment == SQUASHFS_INVALID_FRAG)
+   {
+     fragment_size = 0;
+     blocks = (INODE_DATA->reg.file_size + SUPERBLOCK->block_size - 1) >> SUPERBLOCK->block_log;
+   }
+  else
+   {
+     fragment_size = INODE_DATA->reg.file_size % SUPERBLOCK->block_size;
+     blocks = INODE_DATA->reg.file_size >> SUPERBLOCK->block_log;
+   }
+
+  TRACE("block_number=%d  fragment_size=%d  blocks=%d\n", block_number, fragment_size, blocks);
+
+  /* Only decompress block when the block_number is lesser than the total number of blocks */
+  if (block_number < blocks)
+   {
+     /*
+      * List of blocks to read is after the inode. When copying data, we have also
+      * copied a part of this data
+      */
+     start = INODE_DATA->reg.start_block;
+     for (i=0; i<blocks; i++)
+      {
+	int bytes;
+	unsigned int *c_block_list = (unsigned int *)((struct squashfs_reg_inode_header *)INODE_DATA+1);
+
+	if (i == block_number)
+	 {
+	   TRACE("Reading block %d\n", i);
+	   bytes = read_data_block(start, c_block_list[i], FILE_DATA);
+	   if (bytes == 0)
+	    {
+	      TRACE("failed to read data block at 0x%x\n", (int)start);
+	      return 0;
+	    }
+	   TRACE("Data block:\n");
+	   dump_memory(FILE_DATA, 48);
+	   TRACE("read %d bytes\n", bytes);
+	   return bytes;
+	 }
+	start += SQUASHFS_COMPRESSED_SIZE_BLOCK(c_block_list[i]);
+      }
+   }
+
+  if (fragment_size)
+   {
+     int bytes;
+
+     bytes = fragment_read(INODE_DATA->reg.fragment, FILE_DATA);
+     if (bytes == 0)
+       return 0;
+     /* data begins at FILE_DATA+INODE_DATA->reg.offset */
+     if (INODE_DATA->reg.offset)
+       memmove(FILE_DATA, FILE_DATA+INODE_DATA->reg.offset, INODE_DATA->reg.file_size);
+     TRACE("Data block:\n");
+     dump_memory(FILE_DATA, 48);
+     return INODE_DATA->reg.file_size;
+   }
+
+  return 0;
+}
+
+
+/*
+ *
+ *
+ */
+int
+squashfs_mount (void)
+{
+  TRACE("squashfs_mount()\n");
+
+  /* Check partition type for harddisk */
+  if (((current_drive & 0x80) || (current_slice != 0))
+      && current_slice != PC_SLICE_TYPE_EXT2FS
+      && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)))
+    return 0;
+
+  /* Read bpb */
+  if (! devread(SQUASHFS_START, 0, sizeof(struct squashfs_super_block), (char *) SUPERBLOCK))
+    return 0;
+
+  if (SUPERBLOCK->s_magic != SQUASHFS_MAGIC)
+   {
+     if (SUPERBLOCK->s_magic != SQUASHFS_MAGIC_SWAP)
+       return 0;
+
+     TRACE("Reading a different endian SQUASHFS filesystem\n");
+     TRACE("Not supported\n");
+     errnum = ERR_FSYS_MOUNT;
+     return 0;
+   }
+
+  /* Check the MAJOR & MINOR versions */
+  if (   SUPERBLOCK->s_major != SQUASHFS_MAJOR
+      || SUPERBLOCK->s_minor > SQUASHFS_MINOR)
+   {
+     TRACE("Major/Minor mismatch, filesystem is (%d:%d)\n",
+	 SUPERBLOCK->s_major, SUPERBLOCK->s_minor);
+     printf("I only support Squashfs 3.0 filesystems!\n");
+     errnum = ERR_FSYS_MOUNT;
+     return 0;
+   }
+
+  if (SUPERBLOCK->block_size > SQUASHFS_FILE_MAX_SIZE)
+   {
+     TRACE("Bad squashfs partition, block size is greater than SQUASHFS_FILE_MAX_SIZE\n");
+     errnum = ERR_FSYS_MOUNT;
+     return 0;
+   }
+
+  TRACE("Found a SQUASHFS partition\n");
+  TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(SUPERBLOCK->flags) ? "un" : "");
+  TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(SUPERBLOCK->flags) ? "un" : "");
+  TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(SUPERBLOCK->flags) ? "un" : "");
+  TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(SUPERBLOCK->flags) ? "" : "not");
+  TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(SUPERBLOCK->flags) ? "not" : "");
+  TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(SUPERBLOCK->flags) ? "" : "not");
+  TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(SUPERBLOCK->flags) ? "" : "not");
+  TRACE("\tFilesystem size %d Kbytes (%d Mbytes)\n", (unsigned long long)SUPERBLOCK->bytes_used >> 10, (unsigned long long)SUPERBLOCK->bytes_used >> 20);
+  TRACE("\tBlock size %d\n", SUPERBLOCK->block_size);
+  TRACE("\tNumber of fragments %d\n", SUPERBLOCK->fragments);
+  TRACE("\tNumber of inodes %d\n", SUPERBLOCK->inodes);
+  TRACE("\tNumber of uids %d\n", SUPERBLOCK->no_uids);
+  TRACE("\tNumber of gids %d\n", SUPERBLOCK->no_guids);
+  TRACE("SUPERBLOCK->inode_table_start 0x%x\n", SUPERBLOCK->inode_table_start);
+  TRACE("SUPERBLOCK->directory_table_start 0x%x\n", SUPERBLOCK->directory_table_start);
+  TRACE("SUPERBLOCK->uid_start 0x%x\n", SUPERBLOCK->uid_start);
+  TRACE("SUPERBLOCK->fragment_table_start 0x%x\n\n", SUPERBLOCK->fragment_table_start);
+
+  return 1;
+}
+
+/*
+ *
+ *
+ */
+int
+squashfs_dir (char *dirname)
+{
+  char *filename;
+  int d_inode_start_block;
+  int d_inode_offset;
+  int res;
+  int found_last_part = 0;
+
+  TRACE("squashfs_dir(%s)\n", dirname);
+
+  d_inode_start_block = SQUASHFS_INODE_BLK(SUPERBLOCK->root_inode);
+  d_inode_offset = SQUASHFS_INODE_OFFSET(SUPERBLOCK->root_inode);
+
+  while (found_last_part == 0)
+   {
+     /* Skip all concatened / */
+     while (*dirname == '/')
+       dirname++;
+
+     /* Keep only the filename */
+     filename = dirname;
+     while (*dirname && *dirname != '/' && *dirname != ' ')
+       dirname++;
+
+     /*
+      * No more / ? so this is the last part of the path, leave the while at the
+      * end. Grub give use the full command line kernel /xxxx toto=azeaze ....
+      * So stop after the first space too.
+      */
+     if (*dirname == 0 || *dirname == ' ')
+      {
+	*dirname = 0;
+	found_last_part = 1;
+      }
+     else
+      {
+	/* filename point to the current entry, make then terminated by \0 */
+	*dirname++ = 0;
+      }
+
+     res = squashfs_lookup_directory(d_inode_start_block, d_inode_offset,
+				     filename,
+				     &d_inode_start_block, &d_inode_offset);
+     if (res == 0)
+      {
+	TRACE("Path %s component not found\n", filename);
+	return 0;
+      }
+   }
+
+  TRACE("Nearly finish we just look for %s\n", filename);
+  TRACE("inode for %s is %d:%d\n", filename, d_inode_start_block, d_inode_offset);
+
+  if (! inode_read(d_inode_start_block, d_inode_offset))
+    return 0;
+
+  inode_print(INODE_DATA);
+
+  switch (INODE_DATA->base.inode_type)
+   {
+    case SQUASHFS_FILE_TYPE:
+      filemax = INODE_DATA->reg.file_size;
+      break;
+
+    case SQUASHFS_LREG_TYPE:
+      filemax = INODE_DATA->lreg.file_size;
+      break;
+
+    default:
+      errnum = ERR_BAD_FILETYPE;
+      return 0;
+   }
+
+  filepos = 0;
+  squashfs_old_block = -1;
+
+  TRACE("Size of %s is %d\n", filename, filemax);
+  return 1;
+}
+
+
+/*
+ *
+ *
+ */
+int
+squashfs_read(char *buf, int len)
+{
+  int bytes, size, block, ret, offset;
+
+  TRACE("buf=0x%x, len=%d, position=%d\n", (unsigned long)buf, len, filepos);
+
+  bytes = 0;
+  while (len > 0)
+   {
+     /* Calculate the block number to read for the current position */
+     block = filepos >> SUPERBLOCK->block_log;
+     offset = filepos % SUPERBLOCK->block_size;
+
+     if (block != squashfs_old_block)
+      {
+	ret = squashfs_read_file_one_block(block);
+	if (ret == 0)
+	  return 0;
+	squashfs_old_block = block;
+      }
+
+     size = SUPERBLOCK->block_size - offset;
+     if (size > len)
+       size = len;
+
+     TRACE("Copying into buffer at @0x%x, %d bytes, position=%d (offset=%d)\n", (unsigned long) buf, size, filepos, offset);
+     memmove(buf, FILE_DATA+offset, size);
+     dump_memory(buf, size);
+
+     filepos += size;
+     len -= size;
+     bytes += size;
+     buf += size;
+   }
+
+  return bytes;
+}
+
+
+
+/*
+ *
+ *
+ *
+ *
+ *
+ */
+
+#ifdef SQUASHFS_TRACE
+
+static int __isalnum(int c)
+{
+  if (c>=0x20 && c<=0x7e)
+    return 1;
+  else
+    return 0;
+}
+
+static char tohex(char c)
+{
+  return c>=10?c-10+'a':c+'0';
+}
+
+static unsigned int fmt_xlong(char *dest, unsigned long i, int precision)
+{
+  register unsigned long len,tmp;
+  /* first count the number of bytes needed */
+  for (len=1, tmp=i; tmp>15; ++len)
+    tmp>>=4;
+
+  if (precision)
+   {
+     int x = 0;
+     for (x=0; x<(precision-len); x++)
+       *dest++='0';
+   }
+
+  tmp = i;
+  dest+=len;
+  *dest = 0;
+  while (1)
+   {
+     *--dest = tohex(tmp&15);
+     if (!(tmp>>=4)) break;
+   }
+  return len;
+}
+
+static void print_fmt_xlong(int i, int precision)
+{
+  char temp[48];
+  fmt_xlong(temp, i, precision);
+  printf("%s", temp);
+}
+
+static void dump_memory(const void *data, int len)
+{
+  int i, address, count;
+  const unsigned char *buffer = data;
+
+  return;
+  address = 0;
+  while (address < len )
+   {
+     print_fmt_xlong(address, 8);
+     for(count=i=0; address+i < len && i<16; count++,i++)
+      {
+	printf(" ");
+	print_fmt_xlong(buffer[address+i], 2);
+      }
+     for(;count<=16;count++)
+       printf("   ");
+     for(i=0; address < len && i<16; i++,address++)
+       printf("%c", __isalnum(buffer[address]) ? buffer[address] : '.');
+     printf("\n");
+   }
+}
+
+static const char *get_type(int type)
+{
+  switch (type)
+   {
+    case SQUASHFS_DIR_TYPE:
+      return "directory";
+    case SQUASHFS_FILE_TYPE:
+      return "file";
+    case SQUASHFS_SYMLINK_TYPE:
+      return "symlink";
+    case SQUASHFS_BLKDEV_TYPE:
+      return "block device";
+    case SQUASHFS_CHRDEV_TYPE:
+      return "char device";
+    case SQUASHFS_FIFO_TYPE:
+      return "fifo";
+    case SQUASHFS_SOCKET_TYPE:
+      return "socket";
+    case SQUASHFS_LDIR_TYPE:
+      return "ldir";
+    case SQUASHFS_LREG_TYPE:
+      return "lreg";
+    default:
+      return "unknown";
+   }
+}
+
+static void print_inode_directory(struct squashfs_dir_inode_header *inode)
+{
+  TRACE("inode DIR: inode_number=%d nlink=%d file_size=%d start_block=%d\n",
+        inode->inode_number,
+	inode->nlink,
+	inode->file_size,
+	inode->start_block);
+
+  dump_memory(inode, sizeof(struct squashfs_dir_inode_header));
+}
+
+static void print_inode_file(struct squashfs_reg_inode_header *inode)
+{
+  TRACE("inode FILE: inode_number=%d mode=%d uid=%d gid=%d file_size=%d ",
+        inode->inode_number,
+	inode->mode,
+	inode->uid,
+	inode->guid,
+	inode->file_size
+      );
+
+  if (inode->fragment == SQUASHFS_INVALID_FRAG)
+   {
+     TRACE("fragment_bytes=0 location=%d:%d blocks=%d\n",
+	   inode->start_block, inode->offset,
+	   (inode->file_size + SUPERBLOCK->block_size - 1) >> SUPERBLOCK->block_log);
+   }
+  else
+   {
+     TRACE("fragment_bytes=%d location=%d:%d blocks=%d\n",
+	   inode->file_size % SUPERBLOCK->block_size,
+	   (int)inode->start_block, inode->offset,
+	   inode->file_size >> SUPERBLOCK->block_log);
+   }
+}
+
+
+
+static void inode_print(union squashfs_inode_header *inode)
+{
+  switch (inode->base.inode_type)
+   {
+    case SQUASHFS_DIR_TYPE:
+      print_inode_directory(&inode->dir);
+      break;
+    case SQUASHFS_FILE_TYPE:
+      print_inode_file(&inode->reg);
+    default:
+      TRACE("inode %s\n", get_type(inode->base.inode_type));
+      break;
+   }
+}
+
+#else
+
+static void inode_print(union squashfs_inode_header *inode)
+{
+}
+
+static void dump_memory(const void *data, int len)
+{
+}
+
+#endif
+

Added: trunk/filo/fs/fsys_xfs.c
===================================================================
--- trunk/filo/fs/fsys_xfs.c	                        (rev 0)
+++ trunk/filo/fs/fsys_xfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,621 @@
+/* fsys_xfs.c - an implementation for the SGI XFS file system */
+/*  
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2001,2002  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 "shared.h"
+#include "filesys.h"
+#include "xfs.h"
+
+#define MAX_LINK_COUNT	8
+
+typedef struct xad {
+	xfs_fileoff_t offset;
+	xfs_fsblock_t start;
+	xfs_filblks_t len;
+} xad_t;
+
+struct xfs_info {
+	int bsize;
+	int dirbsize;
+	int isize;
+	unsigned int agblocks;
+	int bdlog;
+	int blklog;
+	int inopblog;
+	int agblklog;
+	int agnolog;
+	unsigned int nextents;
+	xfs_daddr_t next;
+	xfs_daddr_t daddr;
+	xfs_dablk_t forw;
+	xfs_dablk_t dablk;
+	xfs_bmbt_rec_32_t *xt;
+	xfs_bmbt_ptr_t ptr0;
+	int btnode_ptr0_off;
+	int i8param;
+	int dirpos;
+	int dirmax;
+	int blkoff;
+	int fpos;
+	xfs_ino_t rootino;
+};
+
+static struct xfs_info xfs;
+
+#define dirbuf		((char *)FSYS_BUF)
+#define filebuf		((char *)FSYS_BUF + 4096)
+#define inode		((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
+#define icore		(inode->di_core)
+
+#define	mask32lo(n)	(((__uint32_t)1 << (n)) - 1)
+
+#define	XFS_INO_MASK(k)		((__uint32_t)((1ULL << (k)) - 1))
+#define	XFS_INO_OFFSET_BITS	xfs.inopblog
+#define	XFS_INO_AGBNO_BITS	xfs.agblklog
+#define	XFS_INO_AGINO_BITS	(xfs.agblklog + xfs.inopblog)
+#define	XFS_INO_AGNO_BITS	xfs.agnolog
+
+static inline xfs_agblock_t
+agino2agbno (xfs_agino_t agino)
+{
+	return agino >> XFS_INO_OFFSET_BITS;
+}
+
+static inline xfs_agnumber_t
+ino2agno (xfs_ino_t ino)
+{
+	return ino >> XFS_INO_AGINO_BITS;
+}
+
+static inline xfs_agino_t
+ino2agino (xfs_ino_t ino)
+{
+	return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
+}
+
+static inline int
+ino2offset (xfs_ino_t ino)
+{
+	return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
+}
+
+static inline __const__ __uint16_t
+le16 (__uint16_t x)
+{
+	__asm__("xchgb %b0,%h0"	\
+		: "=q" (x) \
+		:  "0" (x)); \
+		return x;
+}
+
+static inline __const__ __uint32_t
+le32 (__uint32_t x)
+{
+#if 0
+        /* 386 doesn't have bswap.  */
+	__asm__("bswap %0" : "=r" (x) : "0" (x));
+#else
+	/* This is slower but this works on all x86 architectures.  */
+	__asm__("xchgb %b0, %h0" \
+		"\n\troll $16, %0" \
+		"\n\txchgb %b0, %h0" \
+		: "=q" (x) : "0" (x));
+#endif
+	return x;
+}
+
+static inline __const__ __uint64_t
+le64 (__uint64_t x)
+{
+	__uint32_t h = x >> 32;
+        __uint32_t l = x & ((1ULL<<32)-1);
+        return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h)));
+}
+
+
+static xfs_fsblock_t
+xt_start (xfs_bmbt_rec_32_t *r)
+{
+	return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) | 
+	       (((xfs_fsblock_t)le32 (r->l2)) << 11) |
+	       (((xfs_fsblock_t)le32 (r->l3)) >> 21);
+}
+
+static xfs_fileoff_t
+xt_offset (xfs_bmbt_rec_32_t *r)
+{
+	return (((xfs_fileoff_t)le32 (r->l0) &
+		mask32lo(31)) << 23) |
+		(((xfs_fileoff_t)le32 (r->l1)) >> 9);
+}
+
+static xfs_filblks_t
+xt_len (xfs_bmbt_rec_32_t *r)
+{
+	return le32(r->l3) & mask32lo(21);
+}
+
+static inline int
+xfs_highbit32(__uint32_t v)
+{
+	int i;
+
+	if (--v) {
+		for (i = 0; i < 31; i++, v >>= 1) {
+			if (v == 0)
+				return i;
+		}
+	}
+	return 0;
+}
+
+static int
+isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
+{
+	return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
+}
+
+static xfs_daddr_t
+agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
+{
+	return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
+}
+
+static xfs_daddr_t
+fsb2daddr (xfs_fsblock_t fsbno)
+{
+	return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
+			 (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
+}
+
+#undef offsetof
+#define offsetof(t,m)	((int)&(((t *)0)->m))
+
+static inline int
+btroot_maxrecs (void)
+{
+	int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
+
+	return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
+		(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
+}
+
+static int
+di_read (xfs_ino_t ino)
+{
+	xfs_agino_t agino;
+	xfs_agnumber_t agno;
+	xfs_agblock_t agbno;
+	xfs_daddr_t daddr;
+	int offset;
+
+	agno = ino2agno (ino);
+	agino = ino2agino (ino);
+	agbno = agino2agbno (agino);
+	offset = ino2offset (ino);
+	daddr = agb2daddr (agno, agbno);
+
+	devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
+
+	xfs.ptr0 = *(xfs_bmbt_ptr_t *)
+		    (inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
+		    + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
+
+	return 1;
+}
+
+static void
+init_extents (void)
+{
+	xfs_bmbt_ptr_t ptr0;
+	xfs_btree_lblock_t h;
+
+	switch (icore.di_format) {
+	case XFS_DINODE_FMT_EXTENTS:
+		xfs.xt = inode->di_u.di_bmx;
+		xfs.nextents = le32 (icore.di_nextents);
+		break;
+	case XFS_DINODE_FMT_BTREE:
+		ptr0 = xfs.ptr0;
+		for (;;) {
+			xfs.daddr = fsb2daddr (le64(ptr0));
+			devread (xfs.daddr, 0,
+				 sizeof(xfs_btree_lblock_t), (char *)&h);
+			if (!h.bb_level) {
+				xfs.nextents = le16(h.bb_numrecs);
+				xfs.next = fsb2daddr (le64(h.bb_rightsib));
+				xfs.fpos = sizeof(xfs_btree_block_t);
+				return;
+			}
+			devread (xfs.daddr, xfs.btnode_ptr0_off,
+				 sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
+		}
+	}
+}
+
+static xad_t *
+next_extent (void)
+{
+	static xad_t xad;
+
+	switch (icore.di_format) {
+	case XFS_DINODE_FMT_EXTENTS:
+		if (xfs.nextents == 0)
+			return NULL;
+		break;
+	case XFS_DINODE_FMT_BTREE:
+		if (xfs.nextents == 0) {
+			xfs_btree_lblock_t h;
+			if (xfs.next == 0)
+				return NULL;
+			xfs.daddr = xfs.next;
+			devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
+			xfs.nextents = le16(h.bb_numrecs);
+			xfs.next = fsb2daddr (le64(h.bb_rightsib));
+			xfs.fpos = sizeof(xfs_btree_block_t);
+		}
+		/* Yeah, I know that's slow, but I really don't care */
+		devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
+		xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
+		xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
+	}
+	xad.offset = xt_offset (xfs.xt);
+	xad.start = xt_start (xfs.xt);
+	xad.len = xt_len (xfs.xt);
+	++xfs.xt;
+	--xfs.nextents;
+
+	return &xad;
+}
+
+/*
+ * Name lies - the function reads only first 100 bytes
+ */
+static void
+xfs_dabread (void)
+{
+	xad_t *xad;
+	xfs_fileoff_t offset;;
+
+	init_extents ();
+	while ((xad = next_extent ())) {
+		offset = xad->offset;
+		if (isinxt (xfs.dablk, offset, xad->len)) {
+			devread (fsb2daddr (xad->start + xfs.dablk - offset),
+				 0, 100, dirbuf);
+			break;
+		}
+	}
+}
+
+static inline xfs_ino_t
+sf_ino (char *sfe, int namelen)
+{
+	void *p = sfe + namelen + 3;
+
+	return (xfs.i8param == 0)
+		? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p);
+}
+
+static inline xfs_ino_t
+sf_parent_ino (void)
+{
+	return (xfs.i8param == 0)
+		? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
+		: le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
+}
+
+static inline int
+roundup8 (int n)
+{
+	return ((n+7)&~7);
+}
+
+static char *
+next_dentry (xfs_ino_t *ino)
+{
+	int namelen = 1;
+	int toread;
+	static char *usual[2] = {".", ".."};
+	static xfs_dir2_sf_entry_t *sfe;
+	char *name = usual[0];
+
+	if (xfs.dirpos >= xfs.dirmax) {
+		if (xfs.forw == 0)
+			return NULL;
+		xfs.dablk = xfs.forw;
+		xfs_dabread ();
+#define h	((xfs_dir2_leaf_hdr_t *)dirbuf)
+		xfs.dirmax = le16 (h->count) - le16 (h->stale);
+		xfs.forw = le32 (h->info.forw);
+#undef h
+		xfs.dirpos = 0;
+	}
+
+	switch (icore.di_format) {
+	case XFS_DINODE_FMT_LOCAL:
+		switch (xfs.dirpos) {
+		case -2:
+			*ino = 0;
+			break;
+		case -1:
+			*ino = sf_parent_ino ();
+			++name;
+			++namelen;
+			sfe = (xfs_dir2_sf_entry_t *)
+				(inode->di_u.di_c 
+				 + sizeof(xfs_dir2_sf_hdr_t)
+				 - xfs.i8param);
+			break;
+		default:
+			namelen = sfe->namelen;
+			*ino = sf_ino ((char *)sfe, namelen);
+			name = sfe->name;
+			sfe = (xfs_dir2_sf_entry_t *)
+				  ((char *)sfe + namelen + 11 - xfs.i8param);
+		}
+		break;
+	case XFS_DINODE_FMT_BTREE:
+	case XFS_DINODE_FMT_EXTENTS:
+#define dau	((xfs_dir2_data_union_t *)dirbuf)
+		for (;;) {
+			if (xfs.blkoff >= xfs.dirbsize) {
+				xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
+				filepos &= ~(xfs.dirbsize - 1);
+				filepos |= xfs.blkoff;
+			}
+			xfs_read (dirbuf, 4);
+			xfs.blkoff += 4;
+			if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
+				toread = roundup8 (le16(dau->unused.length)) - 4;
+				xfs.blkoff += toread;
+				filepos += toread;
+				continue;
+			}
+			break;
+		}
+		xfs_read ((char *)dirbuf + 4, 5);
+		*ino = le64 (dau->entry.inumber);
+		namelen = dau->entry.namelen;
+#undef dau
+		toread = roundup8 (namelen + 11) - 9;
+		xfs_read (dirbuf, toread);
+		name = (char *)dirbuf;
+		xfs.blkoff += toread + 5;
+	}
+	++xfs.dirpos;
+	name[namelen] = 0;
+
+	return name;
+}
+
+static char *
+first_dentry (xfs_ino_t *ino)
+{
+	xfs.forw = 0;
+	switch (icore.di_format) {
+	case XFS_DINODE_FMT_LOCAL:
+		xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
+		xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
+		xfs.dirpos = -2;
+		break;
+	case XFS_DINODE_FMT_EXTENTS:
+	case XFS_DINODE_FMT_BTREE:
+		filepos = 0;
+		xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
+		if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
+#define tail		((xfs_dir2_block_tail_t *)dirbuf)
+			filepos = xfs.dirbsize - sizeof(*tail);
+			xfs_read (dirbuf, sizeof(*tail));
+			xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
+#undef tail
+		} else {
+			xfs.dablk = (1ULL << 35) >> xfs.blklog;
+#define h		((xfs_dir2_leaf_hdr_t *)dirbuf)
+#define n		((xfs_da_intnode_t *)dirbuf)
+			for (;;) {
+				xfs_dabread ();
+				if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
+				    || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
+					xfs.dirmax = le16 (h->count) - le16 (h->stale);
+					xfs.forw = le32 (h->info.forw);
+					break;
+				}
+				xfs.dablk = le32 (n->btree[0].before);
+			}
+#undef n
+#undef h
+		}
+		xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
+		filepos = xfs.blkoff;
+		xfs.dirpos = 0;
+	}
+	return next_dentry (ino);
+}
+
+int
+xfs_mount (void)
+{
+	xfs_sb_t super;
+
+	if (!devread (0, 0, sizeof(super), (char *)&super)
+	    || (le32(super.sb_magicnum) != XFS_SB_MAGIC)
+	    || ((le16(super.sb_versionnum) 
+		& XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
+		return 0;
+	}
+
+	xfs.bsize = le32 (super.sb_blocksize);
+	xfs.blklog = super.sb_blocklog;
+	xfs.bdlog = xfs.blklog - SECTOR_BITS;
+	xfs.rootino = le64 (super.sb_rootino);
+	xfs.isize = le16 (super.sb_inodesize);
+	xfs.agblocks = le32 (super.sb_agblocks);
+	xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
+
+	xfs.inopblog = super.sb_inopblog;
+	xfs.agblklog = super.sb_agblklog;
+	xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
+
+	xfs.btnode_ptr0_off =
+		((xfs.bsize - sizeof(xfs_btree_block_t)) /
+		(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
+		 * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
+
+	return 1;
+}
+
+int
+xfs_read (char *buf, int len)
+{
+	xad_t *xad;
+	xfs_fileoff_t endofprev, endofcur, offset;
+	xfs_filblks_t xadlen;
+	int toread, startpos, endpos;
+
+	if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
+		grub_memmove (buf, inode->di_u.di_c + filepos, len);
+		filepos += len;
+		return len;
+	}
+
+	startpos = filepos;
+	endpos = filepos + len;
+	endofprev = (xfs_fileoff_t)-1;
+	init_extents ();
+	while (len > 0 && (xad = next_extent ())) {
+		offset = xad->offset;
+		xadlen = xad->len;
+		if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
+			endofcur = (offset + xadlen) << xfs.blklog; 
+			toread = (endofcur >= endpos)
+				  ? len : (endofcur - filepos);
+
+			disk_read_func = disk_read_hook;
+			devread (fsb2daddr (xad->start),
+				 filepos - (offset << xfs.blklog), toread, buf);
+			disk_read_func = NULL;
+
+			buf += toread;
+			len -= toread;
+			filepos += toread;
+		} else if (offset > endofprev) {
+			toread = ((offset << xfs.blklog) >= endpos)
+				  ? len : ((offset - endofprev) << xfs.blklog);
+			len -= toread;
+			filepos += toread;
+			for (; toread; toread--) {
+				*buf++ = 0;
+			}
+			continue;
+		}
+		endofprev = offset + xadlen; 
+	}
+
+	return filepos - startpos;
+}
+
+int
+xfs_dir (char *dirname)
+{
+	xfs_ino_t ino, parent_ino, new_ino;
+	xfs_fsize_t di_size;
+	int di_mode;
+	int cmp, n, link_count;
+	char linkbuf[xfs.bsize];
+	char *rest, *name, ch;
+
+	parent_ino = ino = xfs.rootino;
+	link_count = 0;
+	for (;;) {
+		di_read (ino);
+		di_size = le64 (icore.di_size);
+		di_mode = le16 (icore.di_mode);
+
+		if ((di_mode & IFMT) == IFLNK) {
+			if (++link_count > MAX_LINK_COUNT) {
+				errnum = ERR_SYMLINK_LOOP;
+				return 0;
+			}
+			if (di_size < xfs.bsize - 1) {
+				filepos = 0;
+				filemax = di_size;
+				n = xfs_read (linkbuf, filemax);
+			} else {
+				errnum = ERR_FILELENGTH;
+				return 0;
+			}
+
+			ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
+			while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
+			linkbuf[n] = 0;
+			dirname = linkbuf;
+			continue;
+		}
+
+		if (!*dirname || isspace (*dirname)) {
+			if ((di_mode & IFMT) != IFREG) {
+				errnum = ERR_BAD_FILETYPE;
+				return 0;
+			}
+			filepos = 0;
+			filemax = di_size;
+			return 1;
+		}
+
+		if ((di_mode & IFMT) != IFDIR) {
+			errnum = ERR_BAD_FILETYPE;
+			return 0;
+		}
+
+		for (; *dirname == '/'; dirname++);
+
+		for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+		*rest = 0;
+
+		name = first_dentry (&new_ino);
+		for (;;) {
+			cmp = (!*dirname) ? -1 : substring (dirname, name);
+#ifndef STAGE1_5
+			if (print_possibilities && ch != '/' && cmp <= 0) {
+				if (print_possibilities > 0)
+					print_possibilities = -print_possibilities;
+				print_a_completion (name);
+			} else
+#endif
+			if (cmp == 0) {
+				parent_ino = ino;
+				if (new_ino)
+					ino = new_ino;
+		        	*(dirname = rest) = ch;
+				break;
+			}
+			name = next_dentry (&new_ino);
+			if (name == NULL) {
+				if (print_possibilities < 0)
+					return 1;
+
+				errnum = ERR_FILE_NOT_FOUND;
+				*rest = ch;
+				return 0;
+			}
+		}
+	}
+}
+

Added: trunk/filo/fs/iso9660.h
===================================================================
--- trunk/filo/fs/iso9660.h	                        (rev 0)
+++ trunk/filo/fs/iso9660.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,168 @@
+/*
+ *  ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
+ *  including Rock Ridge Extensions support
+ *
+ *  Copyright (C) 1998, 1999  Kousuke Takai  <tak at kmc.kyoto-u.ac.jp>
+ *
+ *  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.
+ */
+/*
+ *  References:
+ *	linux/fs/isofs/rock.[ch]
+ *	mkisofs-1.11.1/diag/isoinfo.c
+ *	mkisofs-1.11.1/iso9660.h
+ *		(all are written by Eric Youngdale)
+ */
+
+/*
+ * Modified by SONE Takeshi to work with FILO
+ */
+
+#ifndef _ISO9660_H_
+#define _ISO9660_H_
+
+#define ISO_SECTOR_BITS              (11)
+#define ISO_SECTOR_SIZE              (1<<ISO_SECTOR_BITS)
+
+#define	ISO_REGULAR	1	/* regular file	*/
+#define	ISO_DIRECTORY	2	/* directory	*/
+#define	ISO_OTHER	0	/* other file (with Rock Ridge) */
+
+#define	RR_FLAG_PX	0x01	/* have POSIX file attributes */
+#define	RR_FLAG_NM	0x08	/* have alternate file name   */
+
+/* POSIX file attributes for Rock Ridge extensions */
+#define	POSIX_S_IFMT	0xF000
+#define	POSIX_S_IFREG	0x8000
+#define	POSIX_S_IFDIR	0x4000
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+#ifndef ASM_FILE
+
+typedef uint8_t   u_int8_t;
+typedef uint16_t  u_int16_t;
+typedef uint32_t  u_int32_t;
+
+typedef	union {
+ u_int8_t l,b;
+}	iso_8bit_t;
+
+typedef	struct __iso_16bit {
+	u_int16_t l, b;
+} __attribute__ ((packed)) iso_16bit_t;
+
+typedef	struct __iso_32bit {
+	u_int32_t l, b;
+} __attribute__ ((packed)) iso_32bit_t;
+
+typedef u_int8_t		iso_date_t[7];
+
+struct iso_directory_record {
+	iso_8bit_t	length;
+	iso_8bit_t	ext_attr_length;
+	iso_32bit_t	extent;
+	iso_32bit_t	size;
+	iso_date_t	date;
+	iso_8bit_t	flags;
+	iso_8bit_t	file_unit_size;
+	iso_8bit_t	interleave;
+	iso_16bit_t	volume_seq_number;
+	iso_8bit_t	name_len;
+	u_int8_t	name[1];
+} __attribute__ ((packed));
+
+struct iso_primary_descriptor {
+	iso_8bit_t	type;
+	u_int8_t	id[5];
+	iso_8bit_t	version;
+	u_int8_t	_unused1[1];
+	u_int8_t	system_id[32];
+	u_int8_t	volume_id[32];
+	u_int8_t	_unused2[8];
+	iso_32bit_t	volume_space_size;
+	u_int8_t	_unused3[32];
+	iso_16bit_t	volume_set_size;
+	iso_16bit_t	volume_seq_number;
+	iso_16bit_t	logical_block_size;
+	iso_32bit_t	path_table_size;
+	u_int8_t	type_l_path_table[4];
+	u_int8_t	opt_type_l_path_table[4];
+	u_int8_t	type_m_path_table[4];
+	u_int8_t	opt_type_m_path_table[4];
+	struct iso_directory_record root_directory_record;
+	u_int8_t	volume_set_id[128];
+	u_int8_t	publisher_id[128];
+	u_int8_t	preparer_id[128];
+	u_int8_t	application_id[128];
+	u_int8_t	copyright_file_id[37];
+	u_int8_t	abstract_file_id[37];
+	u_int8_t	bibliographic_file_id[37];
+	u_int8_t	creation_date[17];
+	u_int8_t	modification_date[17];
+	u_int8_t	expiration_date[17];
+	u_int8_t	effective_date[17];
+	iso_8bit_t	file_structure_version;
+	u_int8_t	_unused4[1];
+	u_int8_t	application_data[512];
+	u_int8_t	_unused5[653];
+} __attribute__ ((packed));
+
+struct rock_ridge {
+	u_int16_t	signature;
+	u_int8_t	len;
+	u_int8_t	version;
+	union {
+	  struct CE {
+	    iso_32bit_t	extent;
+	    iso_32bit_t	offset;
+	    iso_32bit_t	size;
+	  } ce;
+	  struct NM {
+	    iso_8bit_t	flags;
+	    u_int8_t	name[0];
+	  } nm;
+	  struct PX {
+	    iso_32bit_t	mode;
+	    iso_32bit_t	nlink;
+	    iso_32bit_t	uid;
+	    iso_32bit_t	gid;
+	  } px;
+	  struct RR {
+	    iso_8bit_t	flags;
+	  } rr;
+	} u;
+} __attribute__ ((packed));
+
+typedef	union RR_ptr {
+	struct rock_ridge *rr;
+	unsigned char		  *ptr;
+	int		   i;
+} RR_ptr_t;
+
+#define	RRMAGIC(c1, c2)	((c1)|(c2) << 8)
+
+#define	CHECK2(ptr, c1, c2) \
+	(*(unsigned short *)(ptr) == (((c1) | (c2) << 8) & 0xFFFF))
+#define	CHECK4(ptr, c1, c2, c3, c4) \
+	(*(unsigned long *)(ptr) == ((c1) | (c2)<<8 | (c3)<<16 | (c4)<<24))
+
+#endif /* !ASM_FILE */
+
+#endif /* _ISO9660_H_ */

Added: trunk/filo/fs/jfs.h
===================================================================
--- trunk/filo/fs/jfs.h	                        (rev 0)
+++ trunk/filo/fs/jfs.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,602 @@
+/* jfs.h - an extractions from linux/include/linux/jfs/jfs* into one file */
+/*   
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  International Business Machines  Corp.
+ *  Copyright (C) 2001  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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _JFS_H_
+#define _JFS_H_
+
+/* those are from jfs_filsys.h */
+
+/*
+ *	 file system option (superblock flag)
+ */
+/* platform option (conditional compilation) */
+#define JFS_AIX		0x80000000	/* AIX support */
+/*	POSIX name/directory  support */
+
+#define JFS_OS2		0x40000000	/* OS/2 support */
+/*	case-insensitive name/directory support */
+
+#define JFS_LINUX      	0x10000000	/* Linux support */
+/*	case-sensitive name/directory support */
+
+/* directory option */
+#define JFS_UNICODE	0x00000001	/* unicode name */
+
+/* bba */
+#define	JFS_SWAP_BYTES		0x00100000	/* running on big endian computer */
+
+
+/*
+ *	buffer cache configuration
+ */
+/* page size */
+#ifdef PSIZE
+#undef PSIZE
+#endif
+#define	PSIZE		4096	/* page size (in byte) */
+
+/*
+ *	fs fundamental size
+ *
+ * PSIZE >= file system block size >= PBSIZE >= DISIZE
+ */
+#define	PBSIZE		512	/* physical block size (in byte) */
+#define DISIZE		512	/* on-disk inode size (in byte) */
+#define L2DISIZE	9
+#define	INOSPERIAG	4096	/* number of disk inodes per iag */
+#define	L2INOSPERIAG	12
+#define INOSPEREXT	32	/* number of disk inode per extent */
+#define L2INOSPEREXT	5
+
+/* Minimum number of bytes supported for a JFS partition */
+#define MINJFS			(0x1000000)
+
+/*
+ * fixed byte offset address
+ */
+#define SUPER1_OFF	0x8000	/* primary superblock */
+
+#define AITBL_OFF	(SUPER1_OFF + PSIZE + (PSIZE << 1))
+
+/*
+ *	fixed reserved inode number
+ */
+/* aggregate inode */
+#define	AGGREGATE_I	1	/* aggregate inode map inode */
+#define	FILESYSTEM_I	16	/* 1st/only fileset inode in ait:
+				 * fileset inode map inode
+				 */
+
+/* per fileset inode */
+#define	ROOT_I		2	/* fileset root inode */
+
+/*
+ *	directory configuration
+ */
+#define JFS_NAME_MAX	255
+#define JFS_PATH_MAX	PSIZE
+
+#if 0
+typedef unsigned char u8;
+typedef char s8;
+typedef unsigned short u16;
+typedef short s16;
+typedef unsigned int u32;
+typedef int s32;
+typedef unsigned long long u64;
+typedef long long s64;
+#endif
+typedef u16 UniChar;
+
+/* these from jfs_btree.h */
+
+/* btpaget_t flag */
+#define BT_TYPE		0x07	/* B+-tree index */
+#define	BT_ROOT		0x01	/* root page */
+#define	BT_LEAF		0x02	/* leaf page */
+#define	BT_INTERNAL	0x04	/* internal page */
+#define	BT_RIGHTMOST	0x10	/* rightmost page */
+#define	BT_LEFTMOST	0x20	/* leftmost page */
+
+/* those are from jfs_types.h */
+
+struct timestruc_t {
+	u32 tv_sec;
+	u32 tv_nsec;
+};
+
+/*
+ *	physical xd (pxd)
+ */
+typedef struct {
+	unsigned len:24;
+	unsigned addr1:8;
+	u32 addr2;
+} pxd_t;
+
+/* xd_t field extraction */
+#define	lengthPXD(pxd)	((pxd)->len)
+#define	addressPXD(pxd)	(((s64)((pxd)->addr1)) << 32 | ((pxd)->addr2))
+
+/*
+ *	data extent descriptor (dxd)
+ */
+typedef struct {
+	unsigned flag:8;	/* 1: flags */
+	unsigned rsrvd:24;	/* 3: */
+	u32 size;		/* 4: size in byte */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} dxd_t;			/* - 16 - */
+
+/*
+ *	DASD limit information - stored in directory inode
+ */
+typedef struct dasd {
+	u8 thresh;		/* Alert Threshold (in percent) */
+	u8 delta;		/* Alert Threshold delta (in percent)   */
+	u8 rsrvd1;
+	u8 limit_hi;		/* DASD limit (in logical blocks)       */
+	u32 limit_lo;		/* DASD limit (in logical blocks)       */
+	u8 rsrvd2[3];
+	u8 used_hi;		/* DASD usage (in logical blocks)       */
+	u32 used_lo;		/* DASD usage (in logical blocks)       */
+} dasd_t;
+
+
+/* from jfs_superblock.h */
+
+#define JFS_MAGIC 	0x3153464A	/* "JFS1" */
+
+struct jfs_superblock
+{
+	u32 s_magic;		/* 4: magic number */
+	u32 s_version;		/* 4: version number */
+
+	s64 s_size;		/* 8: aggregate size in hardware/LVM blocks;
+				 * VFS: number of blocks
+				 */
+	s32 s_bsize;		/* 4: aggregate block size in bytes; 
+				 * VFS: fragment size
+				 */
+	s16 s_l2bsize;		/* 2: log2 of s_bsize */
+	s16 s_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */
+	s32 s_pbsize;		/* 4: hardware/LVM block size in bytes */
+	s16 s_l2pbsize;		/* 2: log2 of s_pbsize */
+	s16 pad;		/* 2: padding necessary for alignment */
+
+	u32 s_agsize;		/* 4: allocation group size in aggr. blocks */
+
+	u32 s_flag;		/* 4: aggregate attributes:
+				 *    see jfs_filsys.h
+				 */
+	u32 s_state;		/* 4: mount/unmount/recovery state: 
+				 *    see jfs_filsys.h
+				 */
+	s32 s_compress;		/* 4: > 0 if data compression */
+
+	pxd_t s_ait2;		/* 8: first extent of secondary
+				 *    aggregate inode table
+				 */
+
+	pxd_t s_aim2;		/* 8: first extent of secondary
+				 *    aggregate inode map
+				 */
+	u32 s_logdev;		/* 4: device address of log */
+	s32 s_logserial;	/* 4: log serial number at aggregate mount */
+	pxd_t s_logpxd;		/* 8: inline log extent */
+
+	pxd_t s_fsckpxd;	/* 8: inline fsck work space extent */
+
+	struct timestruc_t s_time;	/* 8: time last updated */
+
+	s32 s_fsckloglen;	/* 4: Number of filesystem blocks reserved for
+				 *    the fsck service log.  
+				 *    N.B. These blocks are divided among the
+				 *         versions kept.  This is not a per
+				 *         version size.
+				 *    N.B. These blocks are included in the 
+				 *         length field of s_fsckpxd.
+				 */
+	s8 s_fscklog;		/* 1: which fsck service log is most recent
+				 *    0 => no service log data yet
+				 *    1 => the first one
+				 *    2 => the 2nd one
+				 */
+	char s_fpack[11];	/* 11: file system volume name 
+				 *     N.B. This must be 11 bytes to
+				 *          conform with the OS/2 BootSector
+				 *          requirements
+				 */
+
+	/* extendfs() parameter under s_state & FM_EXTENDFS */
+	s64 s_xsize;		/* 8: extendfs s_size */
+	pxd_t s_xfsckpxd;	/* 8: extendfs fsckpxd */
+	pxd_t s_xlogpxd;	/* 8: extendfs logpxd */
+	/* - 128 byte boundary - */
+
+	/*
+	 *      DFS VFS support (preliminary) 
+	 */
+	char s_attach;		/* 1: VFS: flag: set when aggregate is attached
+				 */
+	u8 rsrvd4[7];		/* 7: reserved - set to 0 */
+
+	u64 totalUsable;	/* 8: VFS: total of 1K blocks which are
+				 * available to "normal" (non-root) users.
+				 */
+	u64 minFree;		/* 8: VFS: # of 1K blocks held in reserve for 
+				 * exclusive use of root.  This value can be 0,
+				 * and if it is then totalUsable will be equal 
+				 * to # of blocks in aggregate.  I believe this
+				 * means that minFree + totalUsable = # blocks.
+				 * In that case, we don't need to store both 
+				 * totalUsable and minFree since we can compute
+				 * one from the other.  I would guess minFree 
+				 * would be the one we should store, and 
+				 * totalUsable would be the one we should 
+				 * compute.  (Just a guess...)
+				 */
+
+	u64 realFree;		/* 8: VFS: # of free 1K blocks can be used by 
+				 * "normal" users.  It may be this is something
+				 * we should compute when asked for instead of 
+				 * storing in the superblock.  I don't know how
+				 * often this information is needed.
+				 */
+	/*
+	 *      graffiti area
+	 */
+};
+
+/* from jfs_dtree.h */
+
+/*
+ *      entry segment/slot
+ *
+ * an entry consists of type dependent head/only segment/slot and
+ * additional segments/slots linked vi next field;
+ * N.B. last/only segment of entry is terminated by next = -1;
+ */
+/*
+ *	directory page slot
+ */
+typedef struct {
+	s8 next;		/* 1: */
+	s8 cnt;			/* 1: */
+	UniChar name[15];	/* 30: */
+} dtslot_t;			/* (32) */
+
+#define DTSLOTDATALEN	15
+
+/*
+ *	 internal node entry head/only segment
+ */
+typedef struct {
+	pxd_t xd;		/* 8: child extent descriptor */
+
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	UniChar name[11];	/* 22: 2-byte aligned */
+} idtentry_t;			/* (32) */
+
+/*
+ *	leaf node entry head/only segment
+ *
+ * 	For legacy filesystems, name contains 13 unichars -- no index field
+ */
+typedef struct {
+	u32 inumber;		/* 4: 4-byte aligned */
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	UniChar name[11];	/* 22: 2-byte aligned */
+	u32 index;		/* 4: index into dir_table */
+} ldtentry_t;			/* (32) */
+
+#define DTLHDRDATALEN	11
+
+/*
+ * dir_table used for directory traversal during readdir
+*/ 
+
+/*
+ * Maximum entry in inline directory table
+ */
+
+typedef struct dir_table_slot {
+	u8 rsrvd;	/* 1: */
+	u8 flag;	/* 1: 0 if free */
+	u8 slot;	/* 1: slot within leaf page of entry */
+	u8 addr1;	/* 1: upper 8 bits of leaf page address */
+	u32 addr2;	/* 4: lower 32 bits of leaf page address -OR-
+			      index of next entry when this entry was deleted */
+} dir_table_slot_t;	/* (8) */
+
+/*
+ *	directory root page (in-line in on-disk inode):
+ *
+ * cf. dtpage_t below.
+ */
+typedef union {
+	struct {
+		dasd_t DASD;	/* 16: DASD limit/usage info  F226941 */
+
+		u8 flag;	/* 1: */
+		s8 nextindex;	/* 1: next free entry in stbl */
+		s8 freecnt;	/* 1: free count */
+		s8 freelist;	/* 1: freelist header */
+
+		u32 idotdot;	/* 4: parent inode number */
+
+		s8 stbl[8];	/* 8: sorted entry index table */
+	} header;		/* (32) */
+
+	dtslot_t slot[9];
+} dtroot_t;
+
+/*
+ *	directory regular page:
+ *
+ *	entry slot array of 32 byte slot
+ *
+ * sorted entry slot index table (stbl):
+ * contiguous slots at slot specified by stblindex,
+ * 1-byte per entry
+ *   512 byte block:  16 entry tbl (1 slot)
+ *  1024 byte block:  32 entry tbl (1 slot)
+ *  2048 byte block:  64 entry tbl (2 slot)
+ *  4096 byte block: 128 entry tbl (4 slot)
+ *
+ * data area:
+ *   512 byte block:  16 - 2 =  14 slot
+ *  1024 byte block:  32 - 2 =  30 slot
+ *  2048 byte block:  64 - 3 =  61 slot
+ *  4096 byte block: 128 - 5 = 123 slot
+ *
+ * N.B. index is 0-based; index fields refer to slot index
+ * except nextindex which refers to entry index in stbl;
+ * end of entry stot list or freelist is marked with -1.
+ */
+typedef union {
+	struct {
+		s64 next;	/* 8: next sibling */
+		s64 prev;	/* 8: previous sibling */
+
+		u8 flag;	/* 1: */
+		s8 nextindex;	/* 1: next entry index in stbl */
+		s8 freecnt;	/* 1: */
+		s8 freelist;	/* 1: slot index of head of freelist */
+
+		u8 maxslot;	/* 1: number of slots in page slot[] */
+		s8 stblindex;	/* 1: slot index of start of stbl */
+		u8 rsrvd[2];	/* 2: */
+
+		pxd_t self;	/* 8: self pxd */
+	} header;		/* (32) */
+
+	dtslot_t slot[128];
+} dtpage_t;
+
+/* from jfs_xtree.h */
+
+/*
+ *      extent allocation descriptor (xad)
+ */
+typedef struct xad {
+	unsigned flag:8;	/* 1: flag */
+	unsigned rsvrd:16;	/* 2: reserved */
+	unsigned off1:8;	/* 1: offset in unit of fsblksize */
+	u32 off2;		/* 4: offset in unit of fsblksize */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} xad_t;			/* (16) */
+
+/* xad_t field extraction */
+#define offsetXAD(xad)	(((s64)((xad)->off1)) << 32 | ((xad)->off2))
+#define addressXAD(xad)	(((s64)((xad)->addr1)) << 32 | ((xad)->addr2))
+#define lengthXAD(xad)	((xad)->len)
+
+/* possible values for maxentry */
+#define XTPAGEMAXSLOT   256
+#define XTENTRYSTART    2
+
+/*
+ *      xtree page:
+ */
+typedef union {
+	struct xtheader {
+		s64 next;	/* 8: */
+		s64 prev;	/* 8: */
+
+		u8 flag;	/* 1: */
+		u8 rsrvd1;	/* 1: */
+		s16 nextindex;	/* 2: next index = number of entries */
+		s16 maxentry;	/* 2: max number of entries */
+		s16 rsrvd2;	/* 2: */
+
+		pxd_t self;	/* 8: self */
+	} header;		/* (32) */
+
+	xad_t xad[XTPAGEMAXSLOT];	/* 16 * maxentry: xad array */
+} xtpage_t;
+
+/* from jfs_dinode.h */
+
+struct dinode {
+	/*
+	 *      I. base area (128 bytes)
+	 *      ------------------------
+	 *
+	 * define generic/POSIX attributes
+	 */
+	u32 di_inostamp;	/* 4: stamp to show inode belongs to fileset */
+	s32 di_fileset;		/* 4: fileset number */
+	u32 di_number;		/* 4: inode number, aka file serial number */
+	u32 di_gen;		/* 4: inode generation number */
+
+	pxd_t di_ixpxd;		/* 8: inode extent descriptor */
+
+	s64 di_size;		/* 8: size */
+	s64 di_nblocks;		/* 8: number of blocks allocated */
+
+	u32 di_nlink;		/* 4: number of links to the object */
+
+	u32 di_uid;		/* 4: user id of owner */
+	u32 di_gid;		/* 4: group id of owner */
+
+	u32 di_mode;		/* 4: attribute, format and permission */
+
+	struct timestruc_t di_atime;	/* 8: time last data accessed */
+	struct timestruc_t di_ctime;	/* 8: time last status changed */
+	struct timestruc_t di_mtime;	/* 8: time last data modified */
+	struct timestruc_t di_otime;	/* 8: time created */
+
+	dxd_t di_acl;		/* 16: acl descriptor */
+
+	dxd_t di_ea;		/* 16: ea descriptor */
+
+	s32 di_next_index;  /* 4: Next available dir_table index */
+
+	s32 di_acltype;		/* 4: Type of ACL */
+
+	/*
+	 * 	Extension Areas.
+	 *
+	 *	Historically, the inode was partitioned into 4 128-byte areas,
+	 *	the last 3 being defined as unions which could have multiple
+	 *	uses.  The first 96 bytes had been completely unused until
+	 *	an index table was added to the directory.  It is now more
+	 *	useful to describe the last 3/4 of the inode as a single
+	 *	union.  We would probably be better off redesigning the
+	 *	entire structure from scratch, but we don't want to break
+	 *	commonality with OS/2's JFS at this time.
+	 */
+	union {
+		struct {
+			/*
+			 * This table contains the information needed to
+			 * find a directory entry from a 32-bit index.
+			 * If the index is small enough, the table is inline,
+			 * otherwise, an x-tree root overlays this table
+			 */
+			dir_table_slot_t _table[12];	/* 96: inline */
+
+			dtroot_t _dtroot;		/* 288: dtree root */
+		} _dir;					/* (384) */
+#define di_dirtable	u._dir._table
+#define di_dtroot	u._dir._dtroot
+#define di_parent       di_dtroot.header.idotdot
+#define di_DASD		di_dtroot.header.DASD
+
+		struct {
+			union {
+				u8 _data[96];		/* 96: unused */
+				struct {
+					void *_imap;	/* 4: unused */
+					u32 _gengen;	/* 4: generator */
+				} _imap;
+			} _u1;				/* 96: */
+#define di_gengen	u._file._u1._imap._gengen
+
+			union {
+				xtpage_t _xtroot;
+				struct {
+					u8 unused[16];	/* 16: */
+					dxd_t _dxd;	/* 16: */
+					union {
+						u32 _rdev;	/* 4: */
+						u8 _fastsymlink[128];
+					} _u;
+					u8 _inlineea[128];
+				} _special;
+			} _u2;
+		} _file;
+#define di_xtroot	u._file._u2._xtroot
+#define di_dxd		u._file._u2._special._dxd
+#define di_btroot	di_xtroot
+#define di_inlinedata	u._file._u2._special._u
+#define di_rdev		u._file._u2._special._u._rdev
+#define di_fastsymlink	u._file._u2._special._u._fastsymlink
+#define di_inlineea     u._file._u2._special._inlineea
+	} u;
+};
+
+typedef struct dinode dinode_t;
+
+/* di_mode */
+#define IFMT	0xF000		/* S_IFMT - mask of file type */
+#define IFDIR	0x4000		/* S_IFDIR - directory */
+#define IFREG	0x8000		/* S_IFREG - regular file */
+#define IFLNK	0xA000		/* S_IFLNK - symbolic link */
+
+/* extended mode bits (on-disk inode di_mode) */
+#define INLINEEA        0x00040000	/* inline EA area free */
+
+/* from jfs_imap.h */
+
+#define	EXTSPERIAG	128	/* number of disk inode extent per iag  */
+#define SMAPSZ		4	/* number of words per summary map      */
+#define	MAXAG		128	/* maximum number of allocation groups  */
+
+/*
+ *	inode allocation map:
+ * 
+ * inode allocation map consists of 
+ * . the inode map control page and
+ * . inode allocation group pages (per 4096 inodes)
+ * which are addressed by standard JFS xtree.
+ */
+/*
+ *	inode allocation group page (per 4096 inodes of an AG)
+ */
+typedef struct {
+	s64 agstart;		/* 8: starting block of ag              */
+	s32 iagnum;		/* 4: inode allocation group number     */
+	s32 inofreefwd;		/* 4: ag inode free list forward        */
+	s32 inofreeback;	/* 4: ag inode free list back           */
+	s32 extfreefwd;		/* 4: ag inode extent free list forward */
+	s32 extfreeback;	/* 4: ag inode extent free list back    */
+	s32 iagfree;		/* 4: iag free list                     */
+
+	/* summary map: 1 bit per inode extent */
+	s32 inosmap[SMAPSZ];	/* 16: sum map of mapwords w/ free inodes;
+				 *      note: this indicates free and backed
+				 *      inodes, if the extent is not backed the
+				 *      value will be 1.  if the extent is
+				 *      backed but all inodes are being used the
+				 *      value will be 1.  if the extent is
+				 *      backed but at least one of the inodes is
+				 *      free the value will be 0.
+				 */
+	s32 extsmap[SMAPSZ];	/* 16: sum map of mapwords w/ free extents */
+	s32 nfreeinos;		/* 4: number of free inodes             */
+	s32 nfreeexts;		/* 4: number of free extents            */
+	/* (72) */
+	u8 pad[1976];		/* 1976: pad to 2048 bytes */
+	/* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
+	u32 wmap[EXTSPERIAG];	/* 512: working allocation map  */
+	u32 pmap[EXTSPERIAG];	/* 512: persistent allocation map */
+	pxd_t inoext[EXTSPERIAG];	/* 1024: inode extent addresses */
+} iag_t;			/* (4096) */
+
+#endif /* _JFS_H_ */

Added: trunk/filo/fs/mini_inflate.c
===================================================================
--- trunk/filo/fs/mini_inflate.c	                        (rev 0)
+++ trunk/filo/fs/mini_inflate.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,388 @@
+/*-------------------------------------------------------------------------
+ * Filename:      mini_inflate.c
+ * Version:       $Id: mini_inflate.c,v 1.2 2001/10/17 19:43:32 jamey Exp $
+ * Copyright:     Copyright (C) 2001, Russ Dill
+ * Author:        Russ Dill <Russ.Dill at asu.edu>
+ * Description:   Mini inflate implementation (RFC 1951)
+ *-----------------------------------------------------------------------*/
+/*
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <libpayload.h>
+#include "mini_inflate.h"
+
+/* The order that the code lengths in section 3.2.7 are in */
+static unsigned char huffman_order[] = {16, 17, 18,  0,  8,  7,  9,  6, 10,  5,
+					11,  4, 12,  3, 13,  2, 14,  1, 15};
+	
+inline void cramfs_memset(int *s, const int c, size n)
+{
+	n--;
+	for (;n > 0; n--) s[n] = c;
+	s[0] = c;
+}
+
+/* associate a stream with a block of data and reset the stream */
+static void init_stream(struct bitstream *stream, unsigned char *data,
+			void *(*inflate_memcpy)(void *, const void *, size_t))
+{
+	stream->error = NO_ERROR;
+	stream->memcpy = inflate_memcpy;
+	stream->decoded = 0;
+	stream->data = data;
+	stream->bit = 0;	/* The first bit of the stream is the lsb of the
+				 * first byte */
+
+	/* really sorry about all this initialization, think of a better way,
+	 * let me know and it will get cleaned up */
+	stream->codes.bits = 8;
+	stream->codes.num_symbols = 19;
+	stream->codes.lengths = stream->code_lengths;
+	stream->codes.symbols = stream->code_symbols;
+	stream->codes.count = stream->code_count;
+	stream->codes.first = stream->code_first;
+	stream->codes.pos = stream->code_pos;
+
+	stream->lengths.bits = 16;
+	stream->lengths.num_symbols = 288;
+	stream->lengths.lengths = stream->length_lengths;
+	stream->lengths.symbols = stream->length_symbols;
+	stream->lengths.count = stream->length_count;
+	stream->lengths.first = stream->length_first;
+	stream->lengths.pos = stream->length_pos;
+
+	stream->distance.bits = 16;
+	stream->distance.num_symbols = 32;
+	stream->distance.lengths = stream->distance_lengths;
+	stream->distance.symbols = stream->distance_symbols;
+	stream->distance.count = stream->distance_count;
+	stream->distance.first = stream->distance_first;
+	stream->distance.pos = stream->distance_pos;	
+
+}
+
+/* pull 'bits' bits out of the stream. The last bit pulled it returned as the
+ * msb. (section 3.1.1)
+ */
+inline unsigned long pull_bits(struct bitstream *stream, 
+			       const unsigned int bits)
+{
+	unsigned long ret;
+	int i;
+	
+	ret = 0;
+	for (i = 0; i < bits; i++) {
+		ret += ((*(stream->data) >> stream->bit) & 1) << i;
+		
+		/* if, before incrementing, we are on bit 7, 
+		 * go to the lsb of the next byte */
+		if (stream->bit++ == 7) {
+			stream->bit = 0;
+			stream->data++;
+		}
+	}
+	return ret;
+}
+
+inline int pull_bit(struct bitstream *stream)
+{
+	int ret = ((*(stream->data) >> stream->bit) & 1);
+	if (stream->bit++ == 7) {
+		stream->bit = 0;
+		stream->data++;
+	}
+	return ret;
+}
+
+/* discard bits up to the next whole byte */
+static void discard_bits(struct bitstream *stream)
+{
+	if (stream->bit != 0) {
+		stream->bit = 0;
+		stream->data++;
+	}
+}
+
+/* No decompression, the data is all literals (section 3.2.4) */
+static void decompress_none(struct bitstream *stream, unsigned char *dest)
+{
+	unsigned int length;
+
+	discard_bits(stream);
+	length = *(stream->data++);
+	length += *(stream->data++) << 8;
+	pull_bits(stream, 16);	/* throw away the inverse of the size */
+	
+	stream->decoded += length;
+	stream->memcpy(dest, stream->data, length);
+	stream->data += length;
+}
+
+/* Read in a symbol from the stream (section 3.2.2) */
+static int read_symbol(struct bitstream *stream, struct huffman_set *set)
+{
+	int bits = 0;
+	int code = 0;
+	while (!(set->count[bits] && code < set->first[bits] + 
+					     set->count[bits])) {
+		code = (code << 1) + pull_bit(stream);
+		if (++bits > set->bits) {
+			/* error decoding (corrupted data?) */
+			stream->error = CODE_NOT_FOUND;
+			return -1;
+		}
+	}
+	return set->symbols[set->pos[bits] + code - set->first[bits]];
+}	
+
+/* decompress a stream of data encoded with the passed length and distance
+ * huffman codes */
+static void decompress_huffman(struct bitstream *stream, unsigned char *dest)
+{
+	struct huffman_set *lengths = &(stream->lengths);
+	struct huffman_set *distance = &(stream->distance);
+	
+	int symbol, length, dist, i;
+	
+	do {
+		if ((symbol = read_symbol(stream, lengths)) < 0) return;
+		if (symbol < 256) {
+			*(dest++) = symbol; /* symbol is a literal */
+			stream->decoded++;
+		} else if (symbol > 256) {
+			/* Determine the length of the repitition 
+			 * (section 3.2.5) */
+			if (symbol < 265) length = symbol - 254;
+			else if (symbol == 285) length = 258;
+			else {
+				length = pull_bits(stream, (symbol - 261) >> 2);
+				length += (4 << ((symbol - 261) >> 2)) + 3;
+				length += ((symbol - 1) % 4) << 
+					  ((symbol - 261) >> 2);
+			}
+						
+			/* Determine how far back to go */
+			if ((symbol = read_symbol(stream, distance)) < 0) 
+				return;
+			if (symbol < 4) dist = symbol + 1;
+			else {
+				dist = pull_bits(stream, (symbol - 2) >> 1);
+				dist += (2 << ((symbol - 2) >> 1)) + 1;
+				dist += (symbol % 2) << ((symbol - 2) >> 1);
+			}
+			stream->decoded += length;
+			for (i = 0; i < length; i++) *(dest++) = dest[-dist];
+		}
+	} while (symbol != 256); /* 256 is the end of the data block */
+}
+	
+/* Fill the lookup tables (section 3.2.2) */
+static void fill_code_tables(struct huffman_set *set)
+{
+	int code = 0, i, length;
+	
+	/* fill in the first code of each bit length, and the pos pointer */
+	set->pos[0] = 0;
+	for (i = 1; i < set->bits; i++) {
+		code = (code + set->count[i - 1]) << 1;
+		set->first[i] = code;
+		set->pos[i] = set->pos[i - 1] + set->count[i - 1];
+	}
+	
+	/* Fill in the table of symbols in order of their huffman code */
+	for (i = 0; i < set->num_symbols; i++) {
+		if ((length = set->lengths[i]))
+			set->symbols[set->pos[length]++] = i;
+	}
+	
+	/* reset the pos pointer */
+	for (i = 1; i < set->bits; i++) set->pos[i] -= set->count[i];
+}
+
+static void init_code_tables(struct huffman_set *set)
+{
+	cramfs_memset(set->lengths, 0, set->num_symbols);		
+	cramfs_memset(set->count, 0, set->bits);
+	cramfs_memset(set->first, 0, set->bits);
+}
+
+/* read in the huffman codes for dynamic decoding (section 3.2.7) */
+static void decompress_dynamic(struct bitstream *stream, unsigned char *dest)
+{
+	/* I tried my best to minimize the memory footprint here, while still
+	 * keeping up performance. I really dislike the _lengths[] tables, but
+	 * I see no way of eliminating them without a sizable performance
+	 * impact. The first struct table keeps track of stats on each bit
+	 * length. The _length table keeps a record of the bit length of each
+	 * symbol. The _symbols table is for looking up symbols by the huffman
+	 * code (the pos element points to the first place in the symbol table
+	 * where that bit length occurs). I also hate the initization of these
+	 * structs, if someone knows how to compact these, lemme know. */
+	
+	struct huffman_set *codes = &(stream->codes);
+	struct huffman_set *lengths = &(stream->lengths);
+	struct huffman_set *distance = &(stream->distance);
+	
+	int hlit = pull_bits(stream, 5) + 257;
+	int hdist = pull_bits(stream, 5) + 1;
+	int hclen = pull_bits(stream, 4) + 4;
+	int length, curr_code, symbol, i, last_code;
+	
+	last_code = 0;
+	
+	init_code_tables(codes);
+	init_code_tables(lengths);
+	init_code_tables(distance);
+	
+	/* fill in the count of each bit length' as well as the lengths 
+	 * table */
+	for (i = 0; i < hclen; i++) {
+		length = pull_bits(stream, 3);
+		codes->lengths[huffman_order[i]] = length; 
+		if (length) codes->count[length]++;
+		
+	}
+	fill_code_tables(codes);
+	
+	/* Do the same for the length codes, being carefull of wrap through
+	 * to the distance table */
+	curr_code = 0;
+	while (curr_code < hlit) {
+		if ((symbol = read_symbol(stream, codes)) < 0) return;
+		if (symbol == 0) {
+			curr_code++;
+			last_code = 0;
+		} else if (symbol < 16) { /* Literal length */
+			lengths->lengths[curr_code] =  last_code = symbol;
+			lengths->count[symbol]++;
+			curr_code++;
+		} else if (symbol == 16) { /* repeat the last symbol 3 - 6
+					    * times */
+			length = 3 + pull_bits(stream, 2);
+			for (;length; length--, curr_code++)
+				if (curr_code < hlit) {
+					lengths->lengths[curr_code] = 
+						last_code;
+					lengths->count[last_code]++;
+				} else { /* wrap to the distance table */
+					distance->lengths[curr_code - hlit] =
+						last_code;
+					distance->count[last_code]++;
+				}
+		} else if (symbol == 17) { /* repeat a bit length 0 */
+			curr_code += 3 + pull_bits(stream, 3);
+			last_code = 0;
+		} else { /* same, but more times */
+			curr_code += 11 + pull_bits(stream, 7);
+			last_code = 0;
+		}
+	}
+	fill_code_tables(lengths);
+
+	/* Fill the distance table, don't need to worry about wrapthrough
+	 * here */
+	curr_code -= hlit;
+	while (curr_code < hdist) {
+		if ((symbol = read_symbol(stream, codes)) < 0) return;
+		if (symbol == 0) {
+			curr_code++;
+			last_code = 0;
+		} else if (symbol < 16) {
+			distance->lengths[curr_code] = last_code = symbol;
+			distance->count[symbol]++;
+			curr_code++;
+		} else if (symbol == 16) {
+			length = 3 + pull_bits(stream, 2);
+			for (;length; length--, curr_code++) {
+				distance->lengths[curr_code] =
+					last_code;
+				distance->count[last_code]++;
+			}
+		} else if (symbol == 17) {
+			curr_code += 3 + pull_bits(stream, 3);
+			last_code = 0;
+		} else {
+			curr_code += 11 + pull_bits(stream, 7);
+			last_code = 0;
+		}
+	}
+	fill_code_tables(distance);
+
+	decompress_huffman(stream, dest);
+}
+
+/* fill in the length and distance huffman codes for fixed encoding 
+ * (section 3.2.6) */
+static void decompress_fixed(struct bitstream *stream, unsigned char *dest)
+{
+	/* let gcc fill in the initial values */
+	struct huffman_set *lengths = &(stream->lengths);
+	struct huffman_set *distance = &(stream->distance);
+	
+	cramfs_memset(lengths->count, 0, 16);
+	cramfs_memset(lengths->first, 0, 16);
+	cramfs_memset(lengths->lengths, 8, 144);
+	cramfs_memset(lengths->lengths + 144, 9, 112);
+	cramfs_memset(lengths->lengths + 256, 7, 24);
+	cramfs_memset(lengths->lengths + 280, 8, 8);
+	lengths->count[7] = 24;
+	lengths->count[8] = 152;
+	lengths->count[9] = 112;
+
+	cramfs_memset(distance->count, 0, 16);
+	cramfs_memset(distance->first, 0, 16);
+	cramfs_memset(distance->lengths, 5, 32);
+	distance->count[5] = 32;
+	
+	
+	fill_code_tables(lengths);
+	fill_code_tables(distance);
+	
+	
+	decompress_huffman(stream, dest);
+}
+
+/* returns the number of bytes decoded, < 0 if there was an error. Note that
+ * this function assumes that the block starts on a byte boundry
+ * (non-compliant, but I don't see where this would happen). section 3.2.3 */
+long decompress_block(unsigned char *dest, unsigned char *source,
+		      void *(*inflate_memcpy)(void *, const void *, size_t))
+{
+	int bfinal, btype;
+	struct bitstream stream;
+	
+	init_stream(&stream, source, inflate_memcpy);
+	do {
+		bfinal = pull_bit(&stream);
+		btype = pull_bits(&stream, 2);
+		if (btype == NO_COMP) decompress_none(&stream, dest + stream.decoded);
+		else if (btype == DYNAMIC_COMP) 
+			decompress_dynamic(&stream, dest + stream.decoded);
+		else if (btype == FIXED_COMP) decompress_fixed(&stream, dest + stream.decoded);
+		else stream.error = COMP_UNKNOWN;
+	} while (!bfinal && !stream.error);
+
+#if 0
+	putstr("decompress_block start\r\n");	
+	putLabeledWord("stream.error = ",stream.error);
+	putLabeledWord("stream.decoded = ",stream.decoded);
+	putLabeledWord("dest = ",dest);
+	putstr("decompress_block end\r\n");	
+#endif
+	return stream.error ? -stream.error : stream.decoded;
+}
+

Added: trunk/filo/fs/mini_inflate.h
===================================================================
--- trunk/filo/fs/mini_inflate.h	                        (rev 0)
+++ trunk/filo/fs/mini_inflate.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------
+ * Filename:      mini_inflate.h
+ * Version:       $Id: mini_inflate.h,v 1.1 2001/08/14 21:17:39 jamey Exp $
+ * Copyright:     Copyright (C) 2001, Russ Dill
+ * Author:        Russ Dill <Russ.Dill at asu.edu>
+ * Description:   Mini deflate implementation
+ *-----------------------------------------------------------------------*/
+/*
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+ 
+typedef __SIZE_TYPE__ size;
+
+#define NO_ERROR 0
+#define COMP_UNKNOWN 1	 /* The specififed bytype is invalid */
+#define CODE_NOT_FOUND 2 /* a huffman code in the stream could not be decoded */
+#define TOO_MANY_BITS 3	 /* pull_bits was passed an argument that is too 
+			  * large */ 
+
+/* This struct represents an entire huffman code set. It has various lookup
+ * tables to speed decoding */
+struct huffman_set {
+	int bits;	 /* maximum bit length */
+	int num_symbols; /* Number of symbols this code can represent */
+	int *lengths;	 /* The bit length of symbols */
+	int *symbols;	 /* All of the symbols, sorted by the huffman code */
+	int *count;	 /* the number of codes of this bit length */
+	int *first;	 /* the first code of this bit length */
+	int *pos;	 /* the symbol that first represents (in the symbols
+			  * array) */
+};
+
+struct bitstream {
+	unsigned char *data; /* increments as we move from byte to byte */
+	unsigned char bit;   /* 0 to 7 */
+	void *(*memcpy)(void *, const void *, size_t);
+	unsigned long decoded; /* The number of bytes decoded */
+	int error;
+
+	int  distance_count[16];
+	int  distance_first[16];
+	int  distance_pos[16];
+	int  distance_lengths[32];
+	int  distance_symbols[32];
+
+	int  code_count[8];
+	int  code_first[8];
+	int  code_pos[8];
+	int  code_lengths[19];
+	int  code_symbols[19];
+	
+	int  length_count[16];
+	int  length_first[16];
+	int  length_pos[16];
+	int  length_lengths[288];
+	int  length_symbols[288];
+	
+	struct huffman_set codes;
+	struct huffman_set lengths;
+	struct huffman_set distance;
+};
+	
+#define NO_COMP 0
+#define FIXED_COMP 1
+#define DYNAMIC_COMP 2
+
+long decompress_block(unsigned char *dest, unsigned char *source,
+		      void *(*inflate_memcpy)(void *dest, const void *src, size_t n));

Added: trunk/filo/fs/shared.h
===================================================================
--- trunk/filo/fs/shared.h	                        (rev 0)
+++ trunk/filo/fs/shared.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1 @@
+/* Sorry, nothing is shared here ;) Just for GRUB compatibility. */

Added: trunk/filo/fs/squashfs_fs.h
===================================================================
--- trunk/filo/fs/squashfs_fs.h	                        (rev 0)
+++ trunk/filo/fs/squashfs_fs.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,877 @@
+#ifndef SQUASHFS_FS
+#define SQUASHFS_FS
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip at lougher.org.uk>
+ *
+ * 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,
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs.h
+ */
+
+#define SQUASHFS_MAJOR			3
+#define SQUASHFS_MINOR			0
+#define SQUASHFS_MAGIC			0x73717368
+#define SQUASHFS_MAGIC_SWAP		0x68737173
+#define SQUASHFS_START			0
+
+/* size of metadata (inode and directory) blocks */
+#define SQUASHFS_METADATA_SIZE		8192
+#define SQUASHFS_METADATA_LOG		13
+
+/* default size of data blocks */
+#define SQUASHFS_FILE_SIZE		65536
+#define SQUASHFS_FILE_LOG		16
+
+#define SQUASHFS_FILE_MAX_SIZE		65536
+
+/* Max number of uids and gids */
+#define SQUASHFS_UIDS			256
+#define SQUASHFS_GUIDS			255
+
+/* Max length of filename (not 255) */
+#define SQUASHFS_NAME_LEN		256
+
+#define SQUASHFS_INVALID		((long long) 0xffffffffffff)
+#define SQUASHFS_INVALID_FRAG		((unsigned int) 0xffffffff)
+#define SQUASHFS_INVALID_BLK		((long long) -1)
+#define SQUASHFS_USED_BLK		((long long) -2)
+
+/* Filesystem flags */
+#define SQUASHFS_NOI			0
+#define SQUASHFS_NOD			1
+#define SQUASHFS_CHECK			2
+#define SQUASHFS_NOF			3
+#define SQUASHFS_NO_FRAG		4
+#define SQUASHFS_ALWAYS_FRAG		5
+#define SQUASHFS_DUPLICATE		6
+
+#define SQUASHFS_BIT(flag, bit)		((flag >> bit) & 1)
+
+#define SQUASHFS_UNCOMPRESSED_INODES(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOI)
+
+#define SQUASHFS_UNCOMPRESSED_DATA(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOD)
+
+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOF)
+
+#define SQUASHFS_NO_FRAGMENTS(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_NO_FRAG)
+
+#define SQUASHFS_ALWAYS_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_ALWAYS_FRAG)
+
+#define SQUASHFS_DUPLICATES(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_DUPLICATE)
+
+#define SQUASHFS_CHECK_DATA(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_CHECK)
+
+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
+		duplicate_checking)	(noi | (nod << 1) | (check_data << 2) \
+		| (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
+		(duplicate_checking << 6))
+
+/* Max number of types and file types */
+#define SQUASHFS_DIR_TYPE		1
+#define SQUASHFS_FILE_TYPE		2
+#define SQUASHFS_SYMLINK_TYPE		3
+#define SQUASHFS_BLKDEV_TYPE		4
+#define SQUASHFS_CHRDEV_TYPE		5
+#define SQUASHFS_FIFO_TYPE		6
+#define SQUASHFS_SOCKET_TYPE		7
+#define SQUASHFS_LDIR_TYPE		8
+#define SQUASHFS_LREG_TYPE		9
+
+/* 1.0 filesystem type definitions */
+#define SQUASHFS_TYPES			5
+#define SQUASHFS_IPC_TYPE		0
+
+/* Flag whether block is compressed or uncompressed, bit is set if block is
+ * uncompressed */
+#define SQUASHFS_COMPRESSED_BIT		(1 << 15)
+
+#define SQUASHFS_COMPRESSED_SIZE(B)	(((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
+		(B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
+
+#define SQUASHFS_COMPRESSED(B)		(!((B) & SQUASHFS_COMPRESSED_BIT))
+
+#define SQUASHFS_COMPRESSED_BIT_BLOCK		(1 << 24)
+
+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)	(((B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
+
+#define SQUASHFS_COMPRESSED_BLOCK(B)	(!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
+
+/*
+ * Inode number ops.  Inodes consist of a compressed block number, and an
+ * uncompressed  offset within that block
+ */
+#define SQUASHFS_INODE_BLK(a)		((unsigned int) ((a) >> 16))
+
+#define SQUASHFS_INODE_OFFSET(a)	((unsigned int) ((a) & 0xffff))
+
+#define SQUASHFS_MKINODE(A, B)		((squashfs_inode_t)(((squashfs_inode_t) (A)\
+					<< 16) + (B)))
+
+/* Compute 32 bit VFS inode number from squashfs inode number */
+#define SQUASHFS_MK_VFS_INODE(a, b)	((unsigned int) (((a) << 8) + \
+					((b) >> 2) + 1))
+/* XXX */
+
+/* Translate between VFS mode and squashfs mode */
+#define SQUASHFS_MODE(a)		((a) & 0xfff)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES(A)	(A * sizeof(struct squashfs_fragment_entry))
+
+#define SQUASHFS_FRAGMENT_INDEX(A)	(SQUASHFS_FRAGMENT_BYTES(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)	(SQUASHFS_FRAGMENT_BYTES(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES(A)	((SQUASHFS_FRAGMENT_BYTES(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)	(SQUASHFS_FRAGMENT_INDEXES(A) *\
+						sizeof(long long))
+
+#define SQUASHFS_CACHED_FRAGMENTS	3
+
+/* cached data constants for filesystem */
+#define SQUASHFS_CACHED_BLKS		8
+
+#define SQUASHFS_MAX_FILE_SIZE_LOG	64
+
+#define SQUASHFS_MAX_FILE_SIZE		((long long) 1 << \
+					(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
+
+#define SQUASHFS_MARKER_BYTE		0xff
+
+/*
+ * definitions for structures on disk
+ */
+
+typedef long long		squashfs_block_t;
+typedef long long		squashfs_inode_t;
+
+struct squashfs_super_block {
+	unsigned int		s_magic;
+	unsigned int		inodes;
+	unsigned int		bytes_used_2;
+	unsigned int		uid_start_2;
+	unsigned int		guid_start_2;
+	unsigned int		inode_table_start_2;
+	unsigned int		directory_table_start_2;
+	unsigned int		s_major:16;
+	unsigned int		s_minor:16;
+	unsigned int		block_size_1:16;
+	unsigned int		block_log:16;
+	unsigned int		flags:8;
+	unsigned int		no_uids:8;
+	unsigned int		no_guids:8;
+	unsigned int		mkfs_time /* time of filesystem creation */;
+	squashfs_inode_t	root_inode;
+	unsigned int		block_size;
+	unsigned int		fragments;
+	unsigned int		fragment_table_start_2;
+	long long		bytes_used;
+	long long		uid_start;
+	long long		guid_start;
+	long long		inode_table_start;
+	long long		directory_table_start;
+	long long		fragment_table_start;
+	long long		unused;
+} __attribute__ ((packed));
+
+struct squashfs_dir_index {
+	unsigned int		index;
+	unsigned int		start_block;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+#define SQUASHFS_BASE_INODE_HEADER		\
+	unsigned int		inode_type:4;	\
+	unsigned int		mode:12;	\
+	unsigned int		uid:8;		\
+	unsigned int		guid:8;		\
+	unsigned int		mtime;		\
+	unsigned int 		inode_number;
+
+struct squashfs_base_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_lreg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	long long		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		parent_inode;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		i_count:16;
+	unsigned int		parent_inode;
+	struct squashfs_dir_index	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header {
+	struct squashfs_base_inode_header	base;
+	struct squashfs_dev_inode_header	dev;
+	struct squashfs_symlink_inode_header	symlink;
+	struct squashfs_reg_inode_header	reg;
+	struct squashfs_lreg_inode_header	lreg;
+	struct squashfs_dir_inode_header	dir;
+	struct squashfs_ldir_inode_header	ldir;
+	struct squashfs_ipc_inode_header	ipc;
+};
+	
+struct squashfs_dir_entry {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	int			inode_number:16;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_header {
+	unsigned int		count:8;
+	unsigned int		start_block;
+	unsigned int		inode_number;
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry {
+	long long		start_block;
+	unsigned int		size;
+	unsigned int		pending;
+} __attribute__ ((packed));
+
+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
+extern int squashfs_uncompress_init(void);
+extern int squashfs_uncompress_exit(void);
+
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating or using a filesystem
+ * on a machine with different byte ordering to the target architecture.
+ *
+ */
+
+#define SQUASHFS_SWAP_START \
+	int bits;\
+	int b_pos;\
+	unsigned long long val;\
+	unsigned char *s;\
+	unsigned char *d;
+
+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
+	SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
+	SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
+	SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
+	SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
+	SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
+	SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
+	SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
+	SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
+	SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
+	SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
+	SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
+	SQUASHFS_SWAP((s)->flags, d, 288, 8);\
+	SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
+	SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
+	SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
+	SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
+	SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
+	SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
+	SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
+	SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
+	SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
+	SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
+	SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
+	SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
+	SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
+	SQUASHFS_SWAP((s)->unused, d, 888, 64);\
+}
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ipc_inode_header))\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dev_inode_header)); \
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_symlink_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_reg_inode_header));\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 192, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
+}
+
+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_lreg_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 224, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 147, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ldir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 155, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
+	SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
+	SQUASHFS_SWAP((s)->index, d, 0, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
+	SQUASHFS_SWAP((s)->size, d, 64, 8);\
+}
+
+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+	SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
+	SQUASHFS_SWAP((s)->size, d, 64, 32);\
+}
+
+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 2);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			16)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
+}
+
+#define SQUASHFS_SWAP_INTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 4);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			32)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
+}
+
+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			64)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
+}
+
+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * bits / 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			bits)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+
+struct squashfs_base_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		type:4;
+	unsigned int		offset:4;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 4);\
+	SQUASHFS_SWAP((s)->guid, d, 20, 4);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_ipc_inode_header_1));\
+	SQUASHFS_SWAP((s)->type, d, 24, 4);\
+	SQUASHFS_SWAP((s)->offset, d, 28, 4);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dev_inode_header_1));\
+	SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_1));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_reg_inode_header_1));\
+	SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dir_inode_header_1));\
+	SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 43, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
+}
+
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+
+struct squashfs_dir_index_2 {
+	unsigned int		index:27;
+	unsigned int		start_block:29;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+struct squashfs_base_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+	unsigned int		i_count:16;
+	struct squashfs_dir_index_2	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header_2 {
+	struct squashfs_base_inode_header_2	base;
+	struct squashfs_dev_inode_header_2	dev;
+	struct squashfs_symlink_inode_header_2	symlink;
+	struct squashfs_reg_inode_header_2	reg;
+	struct squashfs_dir_inode_header_2	dir;
+	struct squashfs_ldir_inode_header_2	ldir;
+	struct squashfs_ipc_inode_header_2	ipc;
+};
+	
+struct squashfs_dir_header_2 {
+	unsigned int		count:8;
+	unsigned int		start_block:24;
+} __attribute__ ((packed));
+
+struct squashfs_dir_entry_2 {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry_2 {
+	unsigned int		start_block;
+	unsigned int		size;
+} __attribute__ ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
+	SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dev_inode_header_2)); \
+	SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_2));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_reg_inode_header_2));\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
+	SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 128, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 51, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_ldir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 59, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
+	SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
+	SQUASHFS_SWAP((s)->index, d, 0, 27);\
+	SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
+	SQUASHFS_SWAP((s)->size, d, 56, 8);\
+}
+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
+	SQUASHFS_SWAP((s)->size, d, 32, 32);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES_2(A)	(A * sizeof(struct squashfs_fragment_entry_2))
+
+#define SQUASHFS_FRAGMENT_INDEX_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES_2(A)	((SQUASHFS_FRAGMENT_BYTES_2(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)	(SQUASHFS_FRAGMENT_INDEXES_2(A) *\
+						sizeof(int))
+
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing
+ * architectures
+ */
+
+#include <arch/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+	/* convert from little endian to big endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, b_pos)
+#else
+	/* convert from big endian to little endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	b_pos = pos % 8;\
+	val = 0;\
+	s = (unsigned char *)p + (pos / 8);\
+	d = ((unsigned char *) &val) + 7;\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d-- = *s++;\
+	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
+}
+
+#define SQUASHFS_MEMSET(s, d, n)	memset(s, 0, n);
+
+#endif
+#endif

Added: trunk/filo/fs/squashfs_zlib.c
===================================================================
--- trunk/filo/fs/squashfs_zlib.c	                        (rev 0)
+++ trunk/filo/fs/squashfs_zlib.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1698 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+
+#include <lib.h>
+#include "shared.h"
+#include "squashfs_zlib.h"
+
+
+
+
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+
+    - @start:	inflate()'s starting value for strm->avail_out
+ */
+static void inflate_fast(z_streamp strm, unsigned start)
+{
+    struct inflate_state *state;
+    unsigned char *in;      /* local strm->next_in */
+    unsigned char *last;    /* while in < last, enough input available */
+    unsigned char *out;     /* local strm->next_out */
+    unsigned char *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const *lcode;      /* local strm->lencode */
+    code const *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code this;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        this = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(this.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(this.op);
+        if (op == 0) {                          /* literal */
+            PUP(out) = (unsigned char)(this.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(this.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            this = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(this.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(this.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(this.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
+
+
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+
+#define MAXBITS 15
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int zlib_inflate_table(codetype type, unsigned short *lens, unsigned codes,
+			code **table, unsigned *bits, unsigned short *work)
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code this;                  /* table entry for duplication */
+    code *next;             /* next available space in table */
+    const unsigned short *base;     /* base value table to use */
+    const unsigned short *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        this.op = (unsigned char)64;    /* invalid code marker */
+        this.bits = (unsigned char)1;
+        this.val = (unsigned short)0;
+        *(*table)++ = this;             /* make a table to force an error */
+        *(*table)++ = this;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        this.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            this.op = (unsigned char)0;
+            this.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            this.op = (unsigned char)(extra[work[sym]]);
+            this.val = base[work[sym]];
+        }
+        else {
+            this.op = (unsigned char)(32 + 64);         /* end of block */
+            this.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = this;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    this.op = (unsigned char)64;                /* invalid code marker */
+    this.bits = (unsigned char)(len - drop);
+    this.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            this.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = this;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
+
+
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Based on zlib 1.2.3 but modified for the Linux Kernel by
+ * Richard Purdie <richard at openedhand.com>
+ *
+ * Changes mainly for static instead of dynamic memory allocation
+ *
+ */
+
+int zlib_inflate_workspacesize(void)
+{
+    return sizeof(struct inflate_workspace);
+}
+
+int zlib_inflateReset(z_streamp strm)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+
+    /* Initialise Window */
+    state->wsize = 1U << state->wbits;
+    state->write = 0;
+    state->whave = 0;
+
+    return Z_OK;
+}
+
+#if 0
+int zlib_inflatePrime(z_streamp strm, int bits, int value)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+#endif
+
+int zlib_inflateInit2(z_streamp strm, int windowBits)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL) return Z_STREAM_ERROR;
+    strm->msg = NULL;                 /* in case we return an error */
+
+    state = &WS(strm)->inflate_state;
+    strm->state = (struct internal_state *)state;
+
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = &WS(strm)->working_window[0];
+
+    return zlib_inflateReset(strm);
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  This returns fixed tables from inffixed.h.
+ */
+static void zlib_fixedtables(struct inflate_state *state)
+{
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning. This is only called when a window is already in use, or when
+   output has been written during this inflate call, but the end of the deflate
+   stream has not been reached yet. It is also called to window dictionary data
+   when a dictionary is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+static void zlib_updatewindow(z_streamp strm, unsigned out)
+{
+    struct inflate_state *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state *)strm->state;
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        memcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        memcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            memcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+static int zlib_inflateSyncPacket(z_streamp strm)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+
+    if (state->mode == STORED && state->bits == 0) {
+	state->mode = TYPE;
+        return Z_OK;
+    }
+    return Z_DATA_ERROR;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#define UPDATE(check, buf, len) zlib_adler32(check, buf, len)
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int zlib_inflate(z_streamp strm, int flush)
+{
+    struct inflate_state *state;
+    unsigned char *next;    /* next input */
+    unsigned char *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Do not check for strm->next_out == NULL here as ppc zImage
+       inflates to strm->next_out = 0 */
+
+    if (strm == NULL || strm->state == NULL ||
+        (strm->next_in == NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state *)strm->state;
+
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+            if (
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                zlib_fixedtables(state);
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                memcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const *)(state->next);
+            state->lenbits = 7;
+            ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const *)(state->next);
+            state->lenbits = 9;
+            ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const *)(state->next);
+            state->distbits = 6;
+            ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+            if ((int)(this.op) == 0) {
+                state->mode = LIT;
+                break;
+            }
+            if (this.op & 32) {
+                state->mode = TYPE;
+                break;
+            }
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call zlib_updatewindow() to create and/or update the window state.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        zlib_updatewindow(strm, out);
+
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+
+    if (flush == Z_PACKET_FLUSH && ret == Z_OK &&
+            (strm->avail_out != 0 || strm->avail_in == 0))
+		return zlib_inflateSyncPacket(strm);
+    return ret;
+}
+
+int zlib_inflateEnd(z_streamp strm)
+{
+    if (strm == NULL || strm->state == NULL)
+        return Z_STREAM_ERROR;
+    return Z_OK;
+}
+
+#if 0
+int zlib_inflateSetDictionary(z_streamp strm, const Byte *dictionary,
+        uInt dictLength)
+{
+    struct inflate_state *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = zlib_adler32(0L, NULL, 0);
+        id = zlib_adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    zlib_updatewindow(strm, strm->avail_out);
+
+    if (dictLength > state->wsize) {
+        memcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        memcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    return Z_OK;
+}
+#endif
+
+#if 0
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, zlib_syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+static unsigned zlib_syncsearch(unsigned *have, unsigned char *buf,
+        unsigned len)
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+#endif
+
+#if 0
+int zlib_inflateSync(z_streamp strm)
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state *state;
+
+    /* check parameters */
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        zlib_syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = zlib_syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    zlib_inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+#endif
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output but this should always be the case. The state must
+ * be waiting on the start of a block (i.e. mode == TYPE or HEAD).  On exit,
+ * the output will also be caught up, and the checksum will have been updated
+ * if need be.
+ */
+int zlib_inflateIncomp(z_stream *z)
+{
+    struct inflate_state *state = (struct inflate_state *)z->state;
+    Byte *saved_no = z->next_out;
+    uInt saved_ao = z->avail_out;
+
+    if (state->mode != TYPE && state->mode != HEAD)
+	return Z_DATA_ERROR;
+
+    /* Setup some variables to allow misuse of updateWindow */
+    z->avail_out = 0;
+    z->next_out = z->next_in + z->avail_in;
+
+    zlib_updatewindow(z, z->avail_in);
+
+    /* Restore saved variables */
+    z->avail_out = saved_ao;
+    z->next_out = saved_no;
+
+    z->adler = state->check =
+        UPDATE(state->check, z->next_in, z->avail_in);
+
+    z->total_out += z->avail_in;
+    z->total_in += z->avail_in;
+    z->next_in += z->avail_in;
+    state->total += z->avail_in;
+    z->avail_in = 0;
+
+    return Z_OK;
+}
+
+static struct inflate_workspace workspace;
+
+/*
+ * Uncompress a block in one pass (assume that we have enough data
+ *
+ * Call zlib decompression routine or LZMA (when implemented)
+ */
+int squashfs_uncompress(void *dest,   unsigned int *destlen,
+                        void *source, unsigned int  sourcelen)
+{
+  z_stream stream;
+  int err;
+
+  memset(&stream, 0, sizeof(stream));
+  memset(&workspace, 0, sizeof(workspace));
+  stream.workspace = &workspace;
+
+  stream.next_in = source;
+  stream.avail_in = sourcelen;
+
+  stream.next_out = dest;
+  stream.avail_out = *destlen;
+
+  *destlen = 0;
+  err = zlib_inflateInit(&stream);
+  if (err != Z_OK)
+    return err;
+
+  err = zlib_inflate(&stream, Z_FINISH);
+  if (err != Z_STREAM_END)
+   {
+     zlib_inflateEnd(&stream);
+     if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+       return Z_DATA_ERROR;
+     return err;
+  }
+  *destlen = stream.total_out;
+
+  err = zlib_inflateEnd(&stream);
+  return err;
+}
+
+
+

Added: trunk/filo/fs/squashfs_zlib.h
===================================================================
--- trunk/filo/fs/squashfs_zlib.h	                        (rev 0)
+++ trunk/filo/fs/squashfs_zlib.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1064 @@
+
+#ifndef SQUASHFS_ZLIB
+#define SQUASHFS_ZLIB
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  define MAX_MEM_LEVEL 8
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+
+                        /* Type declarations */
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+typedef void     *voidp;
+
+#endif /* _ZCONF_H */
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup at gzip.org          madler at alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* zlib deflate based on ZLIB_VERSION "1.1.3" */
+/* zlib inflate based on ZLIB_VERSION "1.2.3" */
+
+/*
+  This is a modified version of zlib for use inside the Linux kernel.
+  The main changes are to perform all memory allocation in advance.
+
+  Inflation Changes:
+    * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning
+      this checks there is no more input data available and the next data
+      is a STORED block. It also resets the mode to be read for the next
+      data, all as per PPP requirements.
+    * Addition of zlib_inflateIncomp which copies incompressible data into
+      the history window and adjusts the accoutning without calling
+      zlib_inflate itself to inflate the data.
+*/
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Byte    *next_in;   /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Byte    *next_out;  /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state *state; /* not visible by applications */
+
+    void     *workspace; /* memory allocated for this stream */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_PACKET_FLUSH  2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+#define Z_BLOCK         6 /* Only for inflate at present */
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+                        /* basic functions */
+
+extern int zlib_deflate_workspacesize (void);
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_deflateInit().
+*/
+
+/* 
+extern int deflateInit (z_streamp strm, int level);
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+extern int zlib_deflate (z_streamp strm, int flush);
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+extern int zlib_deflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+extern int zlib_inflate_workspacesize (void);
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_inflateInit().
+*/
+
+/* 
+extern int zlib_inflateInit (z_streamp strm);
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, and workspace must be initialized before by
+   the caller. If next_in is not NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+extern int zlib_inflate (z_streamp strm, int flush);
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+extern int zlib_inflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+extern int deflateInit2 (z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy);
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+#if 0
+extern int zlib_deflateSetDictionary (z_streamp strm,
+						     const Byte *dictionary,
+						     uInt  dictLength);
+#endif
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+#if 0
+extern int zlib_deflateCopy (z_streamp dest, z_streamp source);
+#endif
+
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+extern int zlib_deflateReset (z_streamp strm);
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+static inline unsigned long deflateBound(unsigned long s)
+{
+	return s + ((s + 7) >> 3) + ((s + 63) >> 6) + 11;
+}
+
+#if 0
+extern int zlib_deflateParams (z_streamp strm, int level, int strategy);
+#endif
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+extern int inflateInit2 (z_streamp strm, int  windowBits);
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+extern int zlib_inflateSetDictionary (z_streamp strm,
+						     const Byte *dictionary,
+						     uInt  dictLength);
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+#if 0
+extern int zlib_inflateSync (z_streamp strm);
+#endif
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int zlib_inflateReset (z_streamp strm);
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int zlib_inflateIncomp (z_stream *strm);
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+#define zlib_deflateInit(strm, level) \
+	zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \
+			      DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY)
+#define zlib_inflateInit(strm) \
+	zlib_inflateInit2((strm), DEF_WBITS)
+
+extern int zlib_deflateInit2(z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy);
+extern int zlib_inflateInit2(z_streamp strm, int  windowBits);
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
+
+
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+        /* common constants */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+         /* functions */
+
+typedef uLong (*check_func) (uLong check, const Byte *buf,
+				       uInt len);
+
+
+                        /* checksum functions */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+static inline uLong zlib_adler32(uLong adler,
+				 const Byte *buf,
+				 uInt len)
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+#endif /* _Z_UTIL_H */
+
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int zlib_inflate_table (codetype type, unsigned short *lens,
+                             unsigned codes, code **table,
+                             unsigned *bits, unsigned short *work);
+
+
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+ /*   gz_headerp head; */           /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const *lencode;    /* starting table for length/literal codes */
+    code const *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
+
+
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+/* memory allocation for inflation */
+
+struct inflate_workspace {
+	struct inflate_state inflate_state;
+	unsigned char working_window[1 << MAX_WBITS];
+};
+
+#define WS(z) ((struct inflate_workspace *)(z->workspace))
+
+#endif
+
+
+int squashfs_uncompress(void *dest,   unsigned int *destlen,
+                        void *source, unsigned int  sourcelen);
+
+
+#endif
+

Added: trunk/filo/fs/vfs.c
===================================================================
--- trunk/filo/fs/vfs.c	                        (rev 0)
+++ trunk/filo/fs/vfs.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,226 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+/* Interface between GRUB's fs drivers and application code */
+#include <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#include "filesys.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_VFS
+#include <debug.h>
+
+int filepos;
+int filemax;
+grub_error_t errnum;
+void (*disk_read_hook) (int, int, int);
+void (*disk_read_func) (int, int, int);
+char FSYS_BUF[FSYS_BUFLEN];
+int fsmax;
+
+struct fsys_entry {
+    char *name;
+    int (*mount_func) (void);
+    int (*read_func) (char *buf, int len);
+    int (*dir_func) (char *dirname);
+    void (*close_func) (void);
+    int (*embed_func) (int *start_sector, int needed_sectors);
+};
+
+struct fsys_entry fsys_table[] = {
+# ifdef CONFIG_FSYS_FAT
+    {"FAT filesystem", fat_mount, fat_read, fat_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_EXT2FS
+    {"EXT2 filesystem", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_MINIX
+    {"MINIX filesystem", minix_mount, minix_read, minix_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_REISERFS
+    {"REISERFS filesystem", reiserfs_mount, reiserfs_read, reiserfs_dir, 0,
+     reiserfs_embed},
+# endif
+# ifdef CONFIG_FSYS_JFS
+    {"JFS filesystem", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
+# endif
+# ifdef CONFIG_FSYS_XFS
+    {"XFS filesystem", xfs_mount, xfs_read, xfs_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_ISO9660
+    {"ISO9660 filesystem", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_CRAMFS
+    {"CRAM filesystem", cramfs_mount, cramfs_read, cramfs_dir, 0, 0},
+# endif
+# ifdef CONFIG_FSYS_SQUASHFS
+    {"SQUASH filesystem", squashfs_mount, squashfs_read, squashfs_dir, 0, 0},
+# endif
+# ifdef CONFIG_ARTEC_BOOT
+    {"Artecboot Virtual Filesystem", aboot_mount, aboot_read, aboot_dir, 0, 0},
+# endif
+
+};
+
+/* NULLFS is used to read images from raw device */
+static int nullfs_dir(char *name)
+{
+    uint64_t dev_size;
+
+    if (name) {
+	debug("can't have a named file\n");
+	return 0;
+    }
+
+    dev_size = (uint64_t) part_length << 9;
+    /* GRUB code doesn't like 2GB or bigger files */
+    if (dev_size > 0x7fffffff)
+	dev_size = 0x7fffffff;
+    filemax = dev_size;
+    return 1;
+}
+
+static int nullfs_read(char *buf, int len)
+{
+    if (devread(filepos>>9, filepos&0x1ff, len, buf)) {
+	filepos += len;
+	return len;
+    } else
+	return 0;
+}
+
+static struct fsys_entry nullfs =
+    {"nullfs", 0, nullfs_read, nullfs_dir, 0, 0};
+
+static struct fsys_entry *fsys;
+
+int mount_fs(void)
+{
+    int i;
+
+    for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
+	if (fsys_table[i].mount_func()) {
+	    fsys = &fsys_table[i];
+	    printf("Mounted %s\n", fsys->name);
+	    return 1;
+	}
+    }
+    fsys = 0;
+    printf("Unknown filesystem type\n");
+    return 0;
+}
+
+int file_open(const char *filename)
+{
+    char *dev = 0;
+    const char *path;
+    int len;
+    int retval = 0;
+    int reopen;
+
+    path = strchr(filename, ':');
+    if (path) {
+	len = path - filename;
+	path++;
+	dev = malloc(len + 1);
+	memcpy(dev, filename, len);
+	dev[len] = '\0';
+    } else {
+	/* No colon is given. Is this device or filename? */
+	if (filename[0] == '/') {
+	    /* Anything starts with '/' must be a filename */
+	    dev = 0;
+	    path = filename;
+	} else {
+	    dev = strdup(filename);
+	    path = 0;
+	}
+    }
+    debug("dev=%s, path=%s\n", dev, path);
+
+    if (dev && dev[0]) {
+	if (!devopen(dev, &reopen)) {
+	    fsys = 0;
+	    goto out;
+	}
+	if (!reopen)
+	    fsys = 0;
+    }
+
+    if (path) {
+	if (!fsys || fsys==&nullfs) {
+	    if (!mount_fs())
+		goto out;
+	}
+	using_devsize = 0;
+	if (!path[0]) {
+	    printf("No filename is given\n");
+	    goto out;
+	}
+    } else
+	fsys = &nullfs;
+
+    filepos = 0;
+    errnum = 0;
+    if (!fsys->dir_func((char *) path)) {
+	printf("File not found\n");
+	goto out;
+    }
+    retval = 1;
+out:
+    if (dev)
+	free(dev);
+    return retval;
+}
+
+int file_read(void *buf, unsigned long len)
+{
+    if (filepos < 0 || filepos > filemax)
+	filepos = filemax;
+    if (len < 0 || len > filemax-filepos)
+	len = filemax - filepos;
+    errnum = 0;
+
+	debug("reading %d bytes, offset 0x%x\n", len, filepos);
+	return fsys->read_func(buf, len);
+}
+
+int file_seek(unsigned long offset)
+{
+	debug("seeking to 0x%x\n", offset);
+    filepos = offset;
+    return filepos;
+}
+
+unsigned long file_size(void)
+{
+    return filemax;
+}
+
+void file_set_size(unsigned long size)
+{
+	debug("updating file size to %d bytes\n", size);
+    filemax = size;
+	using_devsize = 0;
+}
+
+void file_close(void)
+{
+	devclose();
+}
+

Added: trunk/filo/fs/xfs.h
===================================================================
--- trunk/filo/fs/xfs.h	                        (rev 0)
+++ trunk/filo/fs/xfs.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,546 @@
+/* xfs.h - an extraction from xfsprogs-1.3.5/include/xfs* into one file */
+/* 
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (C) 2001  Free Software Foundation, Inc.
+ * 
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of version 2 of the GNU General Public License as
+ *  published by the Free Software Foundation.
+ * 
+ *  This program is distributed in the hope that it would be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ *  Further, this software is distributed without any warranty that it is
+ *  free of the rightful claim of any third person regarding infringement
+ *  or the like.  Any license provided herein, whether implied or
+ *  otherwise, applies only to this software file.  Patent licenses, if
+ *  any, provided herein do not apply to combinations of this program with
+ *  other software, or any other product whatsoever.
+ * 
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ *  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ *  Mountain View, CA  94043, or:
+ * 
+ *  http://www.sgi.com 
+ * 
+ *  For further information regarding this notice, see: 
+ * 
+ *  http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#ifndef _BITS_TYPES_H
+typedef signed char	__int8_t;
+typedef unsigned char	__uint8_t;
+typedef short		__int16_t;
+typedef unsigned short	__uint16_t;
+typedef int		__int32_t;
+typedef unsigned int	__uint32_t;
+typedef long long	__int64_t;
+typedef unsigned long long __uint64_t;
+#endif
+
+typedef __uint64_t	xfs_ino_t;
+typedef	__uint32_t	xfs_agino_t;
+typedef __int64_t	xfs_daddr_t;
+typedef __int64_t	xfs_off_t;
+typedef __uint8_t	uuid_t[16];
+
+
+/* those are from xfs_types.h */
+
+typedef __uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
+typedef	__uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef	__uint32_t	xfs_agnumber_t;	/* allocation group number */
+typedef __int32_t	xfs_extnum_t;	/* # of extents in a file */
+typedef __int16_t	xfs_aextnum_t;	/* # extents in an attribute fork */
+typedef	__int64_t	xfs_fsize_t;	/* bytes in a file */
+
+typedef	__uint32_t	xfs_dablk_t;	/* dir/attr block number (in file) */
+typedef	__uint32_t	xfs_dahash_t;	/* dir/attr hash value */
+
+/*
+ * Disk based types:
+ */
+typedef __uint64_t	xfs_dfsbno_t;	/* blockno in filesystem (agno|agbno) */
+typedef __uint64_t	xfs_drfsbno_t;	/* blockno in filesystem (raw) */
+typedef	__uint64_t	xfs_drtbno_t;	/* extent (block) in realtime area */
+typedef	__uint64_t	xfs_dfiloff_t;	/* block number in a file */
+
+typedef	__uint64_t	xfs_fsblock_t;	/* blockno in filesystem (agno|agbno) */
+typedef	__uint64_t	xfs_fileoff_t;	/* block number in a file */
+typedef	__uint64_t	xfs_filblks_t;	/* number of blocks in a file */
+
+
+/* those are from xfs_sb.h */
+
+#define	XFS_SB_MAGIC		0x58465342	/* 'XFSB'*/
+#define	XFS_SB_VERSION_4	4		/* 6.2+ - bitmask version */
+#define	XFS_SB_VERSION_NUMBITS	0x000f
+
+typedef struct xfs_sb
+{
+	__uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+	__uint32_t	sb_blocksize;	/* logical block size, bytes */
+	xfs_drfsbno_t	sb_dblocks;	/* number of data blocks */
+	xfs_drfsbno_t	sb_rblocks;	/* number of realtime blocks */
+	xfs_drtbno_t	sb_rextents;	/* number of realtime extents */
+	uuid_t		sb_uuid;	/* file system unique id */
+	xfs_dfsbno_t	sb_logstart;	/* starting block of log if internal */
+	xfs_ino_t	sb_rootino;	/* root inode number */
+	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
+	xfs_ino_t	sb_rsumino;	/* summary inode for rt bitmap */
+	xfs_agblock_t	sb_rextsize;	/* realtime extent size, blocks */
+	xfs_agblock_t	sb_agblocks;	/* size of an allocation group */
+	xfs_agnumber_t	sb_agcount;	/* number of allocation groups */
+	xfs_extlen_t	sb_rbmblocks;	/* number of rt bitmap blocks */
+	xfs_extlen_t	sb_logblocks;	/* number of log blocks */
+	__uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
+	__uint16_t	sb_sectsize;	/* volume sector size, bytes */
+	__uint16_t	sb_inodesize;	/* inode size, bytes */
+	__uint16_t	sb_inopblock;	/* inodes per block */
+	char		sb_fname[12];	/* file system name */
+	__uint8_t	sb_blocklog;	/* log2 of sb_blocksize */
+	__uint8_t	sb_sectlog;	/* log2 of sb_sectsize */
+	__uint8_t	sb_inodelog;	/* log2 of sb_inodesize */
+	__uint8_t	sb_inopblog;	/* log2 of sb_inopblock */
+	__uint8_t	sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
+	__uint8_t	sb_rextslog;	/* log2 of sb_rextents */
+	__uint8_t	sb_inprogress;	/* mkfs is in progress, don't mount */
+	__uint8_t	sb_imax_pct;	/* max % of fs for inode space */
+					/* statistics */
+	/*
+	 * These fields must remain contiguous.  If you really
+	 * want to change their layout, make sure you fix the
+	 * code in xfs_trans_apply_sb_deltas().
+	 */
+	__uint64_t	sb_icount;	/* allocated inodes */
+	__uint64_t	sb_ifree;	/* free inodes */
+	__uint64_t	sb_fdblocks;	/* free data blocks */
+	__uint64_t	sb_frextents;	/* free realtime extents */
+	/*
+	 * End contiguous fields.
+	 */
+	xfs_ino_t	sb_uquotino;	/* user quota inode */
+	xfs_ino_t	sb_gquotino;	/* group quota inode */
+	__uint16_t	sb_qflags;	/* quota flags */
+	__uint8_t	sb_flags;	/* misc. flags */
+	__uint8_t	sb_shared_vn;	/* shared version number */
+	xfs_extlen_t	sb_inoalignmt;	/* inode chunk alignment, fsblocks */
+	__uint32_t	sb_unit;	/* stripe or raid unit */
+	__uint32_t	sb_width;	/* stripe or raid width */	
+	__uint8_t	sb_dirblklog;	/* log2 of dir block size (fsbs) */
+        __uint8_t       sb_dummy[7];    /* padding */
+} xfs_sb_t;
+
+
+/* those are from xfs_btree.h */
+
+/*
+ * Long form header: bmap btrees.
+ */
+typedef struct xfs_btree_lblock
+{
+	__uint32_t	bb_magic;	/* magic number for block type */
+	__uint16_t	bb_level;	/* 0 is a leaf */
+	__uint16_t	bb_numrecs;	/* current # of data records */
+	xfs_dfsbno_t	bb_leftsib;	/* left sibling block or NULLDFSBNO */
+	xfs_dfsbno_t	bb_rightsib;	/* right sibling block or NULLDFSBNO */
+} xfs_btree_lblock_t;
+
+/*
+ * Combined header and structure, used by common code.
+ */
+typedef struct xfs_btree_hdr
+{
+	__uint32_t	bb_magic;	/* magic number for block type */
+	__uint16_t	bb_level;	/* 0 is a leaf */
+	__uint16_t	bb_numrecs;	/* current # of data records */
+} xfs_btree_hdr_t;
+
+typedef struct xfs_btree_block
+{
+	xfs_btree_hdr_t	bb_h;		/* header */
+	union		{
+		struct	{
+			xfs_agblock_t	bb_leftsib;
+			xfs_agblock_t	bb_rightsib;
+		}	s;		/* short form pointers */
+		struct	{
+			xfs_dfsbno_t	bb_leftsib;
+			xfs_dfsbno_t	bb_rightsib;
+		}	l;		/* long form pointers */
+	}		bb_u;		/* rest */
+} xfs_btree_block_t;
+
+/* those are from xfs_bmap_btree.h */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block
+{
+	__uint16_t	bb_level;	/* 0 is a leaf */
+	__uint16_t	bb_numrecs;	/* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ * For 32-bit kernels,
+ *  l0:31 is an extent flag (value 1 indicates non-normal).
+ *  l0:0-30 and l1:9-31 are startoff.
+ *  l1:0-8, l2:0-31, and l3:21-31 are startblock.
+ *  l3:0-20 are blockcount.
+ * For 64-bit kernels,
+ *  l0:63 is an extent flag (value 1 indicates non-normal).
+ *  l0:9-62 are startoff.
+ *  l0:0-8 and l1:21-63 are startblock.
+ *  l1:0-20 are blockcount.
+ */
+
+#define	BMBT_USE_64	1
+
+typedef struct xfs_bmbt_rec_32
+{
+	__uint32_t		l0, l1, l2, l3;
+} xfs_bmbt_rec_32_t;
+typedef struct xfs_bmbt_rec_64
+{
+	__uint64_t		l0, l1;
+} xfs_bmbt_rec_64_t;
+
+#if BMBT_USE_64
+typedef	__uint64_t	xfs_bmbt_rec_base_t;	/* use this for casts */
+typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
+#else	/* !BMBT_USE_64 */
+typedef	__uint32_t	xfs_bmbt_rec_base_t;	/* use this for casts */
+typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
+#endif	/* BMBT_USE_64 */
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key
+{
+	xfs_dfiloff_t	br_startoff;	/* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;	/* btree pointer type */
+					/* btree block header type */
+typedef	struct xfs_btree_lblock xfs_bmbt_block_t;
+
+
+/* those are from xfs_dir2.h */
+/*
+ * Directory version 2.
+ * There are 4 possible formats:
+ *	shortform
+ *	single block - data with embedded leaf at the end
+ *	multiple data blocks, single leaf+freeindex block
+ *	data blocks, node&leaf blocks (btree), freeindex blocks
+ *
+ *	The shortform format is in xfs_dir2_sf.h.
+ *	The single block format is in xfs_dir2_block.h.
+ *	The data block format is in xfs_dir2_data.h.
+ *	The leaf and freeindex block formats are in xfs_dir2_leaf.h.
+ *	Node blocks are the same as the other version, in xfs_da_btree.h.
+ */
+
+/*
+ * Byte offset in data block and shortform entry.
+ */
+typedef	__uint16_t	xfs_dir2_data_off_t;
+
+/*
+ * Byte offset in a directory.
+ */
+typedef	xfs_off_t		xfs_dir2_off_t;
+
+/* those are from xfs_da_btree.h */
+/*========================================================================
+ * Directory Structure when greater than XFS_LBSIZE(mp) bytes.
+ *========================================================================*/
+
+/*
+ * This structure is common to both leaf nodes and non-leaf nodes in the Btree.
+ *
+ * Is is used to manage a doubly linked list of all blocks at the same
+ * level in the Btree, and to identify which type of block this is.
+ */
+#define	XFS_DIR2_LEAF1_MAGIC	0xd2f1	/* magic number: v2 dirlf single blks */
+#define	XFS_DIR2_LEAFN_MAGIC	0xd2ff	/* magic number: v2 dirlf multi blks */
+
+typedef struct xfs_da_blkinfo {
+	xfs_dablk_t forw;			/* previous block in list */
+	xfs_dablk_t back;			/* following block in list */
+	__uint16_t magic;			/* validity check on block */
+	__uint16_t pad;				/* unused */
+} xfs_da_blkinfo_t;
+
+/*
+ * This is the structure of the root and intermediate nodes in the Btree.
+ * The leaf nodes are defined above.
+ *
+ * Entries are not packed.
+ *
+ * Since we have duplicate keys, use a binary search but always follow
+ * all match in the block, not just the first match found.
+ */
+
+typedef struct xfs_da_intnode {
+	struct xfs_da_node_hdr {	/* constant-structure header block */
+		xfs_da_blkinfo_t info;	/* block type, links, etc. */
+		__uint16_t count;	/* count of active entries */
+		__uint16_t level;	/* level above leaves (leaf == 0) */
+	} hdr;
+	struct xfs_da_node_entry {
+		xfs_dahash_t hashval;	/* hash value for this descendant */
+		xfs_dablk_t before;	/* Btree block before this key */
+	} btree[1];			/* variable sized array of keys */
+} xfs_da_intnode_t;
+
+
+/* those are from xfs_dir2_data.h */
+/*
+ * Directory format 2, data block structures.
+ */
+
+/*
+ * Constants.
+ */
+#define	XFS_DIR2_DATA_FREE_TAG	0xffff
+#define	XFS_DIR2_DATA_FD_COUNT	3
+
+/*
+ * Structures.
+ */
+
+/*
+ * Describe a free area in the data block.
+ * The freespace will be formatted as a xfs_dir2_data_unused_t.
+ */
+typedef struct xfs_dir2_data_free {
+	xfs_dir2_data_off_t	offset;		/* start of freespace */
+	xfs_dir2_data_off_t	length;		/* length of freespace */
+} xfs_dir2_data_free_t;
+
+/*
+ * Header for the data blocks.
+ * Always at the beginning of a directory-sized block.
+ * The code knows that XFS_DIR2_DATA_FD_COUNT is 3.
+ */
+typedef struct xfs_dir2_data_hdr {
+	__uint32_t		magic;		/* XFS_DIR2_DATA_MAGIC */
+						/* or XFS_DIR2_BLOCK_MAGIC */
+	xfs_dir2_data_free_t	bestfree[XFS_DIR2_DATA_FD_COUNT];
+} xfs_dir2_data_hdr_t;
+
+/*
+ * Active entry in a data block.  Aligned to 8 bytes.
+ * Tag appears as the last 2 bytes.
+ */
+typedef struct xfs_dir2_data_entry {
+	xfs_ino_t		inumber;	/* inode number */
+	__uint8_t		namelen;	/* name length */
+	__uint8_t		name[1];	/* name bytes, no null */
+						/* variable offset */
+	xfs_dir2_data_off_t	tag;		/* starting offset of us */
+} xfs_dir2_data_entry_t;
+
+/*
+ * Unused entry in a data block.  Aligned to 8 bytes.
+ * Tag appears as the last 2 bytes.
+ */
+typedef struct xfs_dir2_data_unused {
+	__uint16_t		freetag;	/* XFS_DIR2_DATA_FREE_TAG */
+	xfs_dir2_data_off_t	length;		/* total free length */
+						/* variable offset */
+	xfs_dir2_data_off_t	tag;		/* starting offset of us */
+} xfs_dir2_data_unused_t;
+
+typedef union {
+	xfs_dir2_data_entry_t	entry;
+	xfs_dir2_data_unused_t	unused;
+} xfs_dir2_data_union_t;
+
+
+/* those are from xfs_dir2_leaf.h */
+/*
+ * Directory version 2, leaf block structures.
+ */
+
+/*
+ * Leaf block header.
+ */
+typedef struct xfs_dir2_leaf_hdr {
+	xfs_da_blkinfo_t	info;		/* header for da routines */
+	__uint16_t		count;		/* count of entries */
+	__uint16_t		stale;		/* count of stale entries */
+} xfs_dir2_leaf_hdr_t;
+
+
+/* those are from xfs_dir2_block.h */
+/*
+ * xfs_dir2_block.h
+ * Directory version 2, single block format structures
+ */
+
+/*
+ * The single block format is as follows:
+ * xfs_dir2_data_hdr_t structure
+ * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures
+ * xfs_dir2_leaf_entry_t structures
+ * xfs_dir2_block_tail_t structure
+ */
+
+#define	XFS_DIR2_BLOCK_MAGIC	0x58443242	/* XD2B: for one block dirs */
+
+typedef struct xfs_dir2_block_tail {
+	__uint32_t	count;			/* count of leaf entries */
+	__uint32_t	stale;			/* count of stale lf entries */
+} xfs_dir2_block_tail_t;
+
+
+/* those are from xfs_dir2_sf.h */
+
+/*
+ * Directory layout when stored internal to an inode.
+ *
+ * Small directories are packed as tightly as possible so as to
+ * fit into the literal area of the inode.
+ */
+
+/*
+ * Inode number stored as 8 8-bit values.
+ */
+typedef	struct { __uint8_t i[8]; } xfs_dir2_ino8_t;
+
+/*
+ * Inode number stored as 4 8-bit values.
+ * Works a lot of the time, when all the inode numbers in a directory
+ * fit in 32 bits.
+ */
+typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t;
+
+typedef union {
+	xfs_dir2_ino8_t	i8;
+	xfs_dir2_ino4_t	i4;
+} xfs_dir2_inou_t;
+
+/*
+ * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t.
+ * Only need 16 bits, this is the byte offset into the single block form.
+ */
+typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t;
+
+/*
+ * The parent directory has a dedicated field, and the self-pointer must
+ * be calculated on the fly.
+ *
+ * Entries are packed toward the top as tightly as possible.  The header
+ * and the elements must be bcopy()'d out into a work area to get correct
+ * alignment for the inode number fields.
+ */
+typedef struct xfs_dir2_sf_hdr {
+	__uint8_t		count;		/* count of entries */
+	__uint8_t		i8count;	/* count of 8-byte inode #s */
+	xfs_dir2_inou_t		parent;		/* parent dir inode number */
+} xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+	__uint8_t		namelen;	/* actual name length */
+	xfs_dir2_sf_off_t	offset;		/* saved offset */
+	__uint8_t		name[1];	/* name, variable size */
+	xfs_dir2_inou_t		inumber;	/* inode number, var. offset */
+} xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+	xfs_dir2_sf_hdr_t	hdr;		/* shortform header */
+	xfs_dir2_sf_entry_t	list[1];	/* shortform entries */
+} xfs_dir2_sf_t;
+
+/* those are from xfs_dinode.h */
+
+#define	XFS_DINODE_VERSION_1	1
+#define	XFS_DINODE_VERSION_2	2
+#define	XFS_DINODE_MAGIC	0x494e	/* 'IN' */
+
+/*
+ * Disk inode structure.
+ * This is just the header; the inode is expanded to fill a variable size
+ * with the last field expanding.  It is split into the core and "other"
+ * because we only need the core part in the in-core inode.
+ */
+typedef struct xfs_timestamp {
+	__int32_t	t_sec;		/* timestamp seconds */
+	__int32_t	t_nsec;		/* timestamp nanoseconds */
+} xfs_timestamp_t;
+
+/*
+ * Note: Coordinate changes to this structure with the XFS_DI_* #defines
+ * below and the offsets table in xfs_ialloc_log_di().
+ */
+typedef struct xfs_dinode_core
+{
+	__uint16_t	di_magic;	/* inode magic # = XFS_DINODE_MAGIC */
+	__uint16_t	di_mode;	/* mode and type of file */
+	__int8_t	di_version;	/* inode version */
+	__int8_t	di_format;	/* format of di_c data */
+	__uint16_t	di_onlink;	/* old number of links to file */
+	__uint32_t	di_uid;		/* owner's user id */
+	__uint32_t	di_gid;		/* owner's group id */
+	__uint32_t	di_nlink;	/* number of links to file */
+	__uint16_t	di_projid;	/* owner's project id */
+	__uint8_t	di_pad[10];	/* unused, zeroed space */
+	xfs_timestamp_t	di_atime;	/* time last accessed */
+	xfs_timestamp_t	di_mtime;	/* time last modified */
+	xfs_timestamp_t	di_ctime;	/* time created/inode modified */
+	xfs_fsize_t	di_size;	/* number of bytes in file */
+	xfs_drfsbno_t	di_nblocks;	/* # of direct & btree blocks used */
+	xfs_extlen_t	di_extsize;	/* basic/minimum extent size for file */
+	xfs_extnum_t	di_nextents;	/* number of extents in data fork */
+	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/
+	__uint8_t	di_forkoff;	/* attr fork offs, <<3 for 64b align */
+	__int8_t	di_aformat;	/* format of attr fork's data */
+	__uint32_t	di_dmevmask;	/* DMIG event mask */
+	__uint16_t	di_dmstate;	/* DMIG state info */
+	__uint16_t	di_flags;	/* random flags, XFS_DIFLAG_... */
+	__uint32_t	di_gen;		/* generation number */
+} xfs_dinode_core_t;
+
+typedef struct xfs_dinode
+{
+	xfs_dinode_core_t	di_core;
+	xfs_agino_t		di_next_unlinked;/* agi unlinked list ptr */
+	union {
+		xfs_bmdr_block_t di_bmbt;	/* btree root block */
+		xfs_bmbt_rec_32_t di_bmx[1];	/* extent list */
+		xfs_dir2_sf_t	di_dir2sf;	/* shortform directory v2 */
+		char		di_c[1];	/* local contents */
+	} di_u;
+} xfs_dinode_t;
+
+/*
+ * Values for di_format
+ */
+typedef enum xfs_dinode_fmt
+{
+	XFS_DINODE_FMT_DEV,		/* CHR, BLK: di_dev */
+	XFS_DINODE_FMT_LOCAL,		/* DIR, REG: di_c */
+					/* LNK: di_symlink */
+	XFS_DINODE_FMT_EXTENTS,		/* DIR, REG, LNK: di_bmx */
+	XFS_DINODE_FMT_BTREE,		/* DIR, REG, LNK: di_bmbt */
+	XFS_DINODE_FMT_UUID 		/* MNT: di_uuid */
+} xfs_dinode_fmt_t;
+
+/*
+ * File types (mode field)
+ */
+#define	IFMT		0170000		/* type of file */
+#define	IFDIR		0040000		/* directory */
+#define	IFREG		0100000		/* regular */
+#define	IFLNK		0120000		/* symbolic link */

Added: trunk/filo/i386/Makefile.inc
===================================================================
--- trunk/filo/i386/Makefile.inc	                        (rev 0)
+++ trunk/filo/i386/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-y += i386/context.o i386/switch.S.o i386/segment.o i386/timer.o i386/sys_info.o
+TARGETS-$(CONFIG_LINUX_LOADER) += i386/linux_load.o
+TARGETS-$(CONFIG_WINCE_LOADER) += i386/wince_load.o
+TARGETS-$(CONFIG_ARTEC_BOOT) += i386/artecboot.o

Added: trunk/filo/i386/artecboot.c
===================================================================
--- trunk/filo/i386/artecboot.c	                        (rev 0)
+++ trunk/filo/i386/artecboot.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ *
+ *	FILO Artecboot loader, enables multiboot through custom header 
+ *
+ *	Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ *	Artec Design LLC http://www.artecdesign.ee
+ *
+ *	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 <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#include "artecboot.h"
+#include "../fs/filesys.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_ARTECBOOT
+#include <debug.h>
+
+static ARTECBOOT_HEADER bootHdr;
+
+int artecboot_load(const char *file, const char *cmdline)
+{
+	int i;
+
+	printf("Starting the Artecboot loader...\n");
+	// clear the boot header
+	memset(&bootHdr, 0, sizeof(bootHdr));
+	
+	// try opening the boot parameter file
+	if (!file_open(file))
+	{
+		printf("Boot error: failed to open image file: %s\n", file);
+		return LOADER_NOT_SUPPORT;
+	}
+
+	file_seek(0);	// seek to the beginning of the parameter file
+	
+	// now read out the boot header
+	if(file_read(&bootHdr, sizeof(ARTECBOOT_HEADER)) != sizeof(ARTECBOOT_HEADER))
+	{
+		printf("Boot error: failed reading the boot image header\n");
+		file_close();
+		return LOADER_NOT_SUPPORT;
+	}
+	
+	// check whether the parameter data is valid at all
+	if(bootHdr.magicHeader != ARTECBOOT_HEADER_MAGIC)
+	{
+		debug("No Artecboot signature found, aborting\n");
+		file_close();
+		return LOADER_NOT_SUPPORT;
+	}
+
+	// check the version number
+	if(bootHdr.bootVersion > CURRENT_VERSION)
+	{
+		printf("Boot error: incompatible version number: %x\n", bootHdr.bootVersion);
+		file_close();
+		return LOADER_NOT_SUPPORT;
+	}
+	
+	// shall we replace the command line?
+	if(bootHdr.bitFlags & FLAG_CMDLINE)
+	{
+		// check the command line and wipe out all junk
+		for(i=0; bootHdr.cmdLine[i] != 0; i++)
+			switch(bootHdr.cmdLine[i])
+			{
+			case '\n':
+			case '\r':
+				bootHdr.cmdLine[i] = ' ';
+				break;
+			default:
+				// do nothing
+				break;
+			}
+	}
+	else if(cmdline) 
+		strncpy(bootHdr.cmdLine, cmdline, sizeof(bootHdr.cmdLine));
+	
+	// proceed basing on the specified OS type
+	switch(bootHdr.osType)
+	{
+	case OS_LINUX:
+		if(bootHdr.bitFlags & FLAG_INITRD)
+		{
+			char initrdParam[100];
+			if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+			{
+				// we are using a real filesystem, so format the initrd file as usually
+				sprintf(initrdParam, " initrd=%s", bootHdr.initrdFile); 
+			}
+			else
+			{
+				// we are using a 'fake' filesystem, so use the image offset
+				sprintf(initrdParam, " initrd=flashb at 0x%x,0x%x", 
+						bootHdr.initrdStart, bootHdr.initrdSize);
+			}			
+
+			debug("adding initrd parameter: %s\n", initrdParam); 
+			strncat(bootHdr.cmdLine, initrdParam, sizeof(bootHdr.cmdLine));
+		}
+	
+		printf("Starting Linux loader...\n");
+
+		// if using a real filesystem, load the kernel image from a specified file		
+		if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+			linux_load(bootHdr.kernelFile, bootHdr.cmdLine);
+		// if using a 'fake' filesystem, consider reading from the same image
+		else
+		{
+			part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS;	
+			part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1;
+			filemax = bootHdr.kernelSize;
+			linux_load(file, bootHdr.cmdLine);
+		}
+	
+		break;
+		
+	case OS_WINCE:
+
+		printf("Starting Windows CE loader...\n");
+		// if using a real filesystem, load the kernel image from a specified file		
+		if(bootHdr.bitFlags & FLAG_FILESYSTEM)
+			wince_load(bootHdr.kernelFile, bootHdr.cmdLine);
+		// if using a 'fake' filesystem, consider reading from the same image
+		else
+		{
+			part_start = bootHdr.kernelStart >> DEV_SECTOR_BITS;	
+			part_length = ((bootHdr.kernelSize-1) >> DEV_SECTOR_BITS) + 1;
+			filemax = bootHdr.kernelSize;	
+			wince_load(file, bootHdr.cmdLine);
+		}
+
+		break;	
+		
+	default:
+		printf("Boot error: unknown OS type, aborting: %d\n", bootHdr.osType);
+		return LOADER_NOT_SUPPORT;
+	}
+	
+	file_close();
+	return 0;
+}

Added: trunk/filo/i386/context.c
===================================================================
--- trunk/filo/i386/context.c	                        (rev 0)
+++ trunk/filo/i386/context.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,139 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+/*
+ * context switching
+ * 2003-10 by SONE Takeshi
+ */
+
+#include <libpayload.h>
+#include <lib.h>
+#include "segment.h"
+#include "context.h"
+
+#define MAIN_STACK_SIZE 16384
+#define IMAGE_STACK_SIZE 4096
+
+static void start_main(void); /* forward decl. */
+void __exit_context(void); /* assembly routine */
+
+/*
+ * Main context structure 
+ * It is placed at the bottom of our stack, and loaded by assembly routine
+ * to start us up.
+ */
+struct context main_ctx __attribute__((section (".initctx"))) = {
+    .gdt_base = (u32) gdt,
+    .gdt_limit = GDT_LIMIT,
+    .cs = FLAT_CS,
+    .ds = FLAT_DS,
+    .es = FLAT_DS,
+    .fs = FLAT_DS,
+    .gs = FLAT_DS,
+    .ss = FLAT_DS,
+    .esp = (u32) ESP_LOC(&main_ctx),
+    .eip = (u32) start_main,
+    .return_addr = (u32) __exit_context,
+};
+
+/* This is used by assembly routine to load/store the context which
+ * it is to switch/switched.  */
+struct context *__context = &main_ctx;
+
+/* Stack for loaded ELF image */
+static u8 image_stack[IMAGE_STACK_SIZE];
+
+/* Pointer to startup context (physical address) */
+unsigned long __boot_ctx;
+
+/*
+ * Main starter
+ * This is the C function that runs first.
+ */
+static void start_main(void)
+{
+    int retval;
+    extern int main(void);
+
+    /* Save startup context, so we can refer to it later.
+     * We have to keep it in physical address since we will relocate. */
+    __boot_ctx = virt_to_phys(__context);
+
+    /* Start the real fun */
+    retval = main();
+
+    /* Pass return value to startup context. Bootloader may see it. */
+    boot_ctx->eax = retval;
+
+    /* Returning from here should jump to __exit_context */
+    __context = boot_ctx;
+}
+
+/* Setup a new context using the given stack.
+ */
+struct context *
+init_context(u8 *stack, u32 stack_size, int num_params)
+{
+    struct context *ctx;
+
+    ctx = (struct context *)
+	(stack + stack_size - (sizeof(*ctx) + num_params*sizeof(u32)));
+    memset(ctx, 0, sizeof(*ctx));
+
+    /* Fill in reasonable default for flat memory model */
+    ctx->gdt_base = virt_to_phys(gdt);
+    ctx->gdt_limit = GDT_LIMIT;
+    ctx->cs = FLAT_CS;
+    ctx->ds = FLAT_DS;
+    ctx->es = FLAT_DS;
+    ctx->fs = FLAT_DS;
+    ctx->gs = FLAT_DS;
+    ctx->ss = FLAT_DS;
+    ctx->esp = virt_to_phys(ESP_LOC(ctx));
+    ctx->return_addr = virt_to_phys(__exit_context);
+
+    return ctx;
+}
+
+/* Switch to another context. */
+struct context *switch_to(struct context *ctx)
+{
+    struct context *save, *ret;
+
+    save = __context;
+    __context = ctx;
+    asm volatile ("push %%cs; call __switch_context" : : : "memory");
+    ret = __context;
+    __context = save;
+    return ret;
+}
+
+/* Start ELF Boot image */
+u32 start_elf(u32 entry_point, u32 param)
+{
+    struct context *ctx;
+
+    ctx = init_context(image_stack, sizeof image_stack, 1);
+    ctx->eip = entry_point;
+    ctx->param[0] = param;
+    ctx->eax = 0xe1fb007;
+    ctx->ebx = param;
+
+    ctx = switch_to(ctx);
+    return ctx->eax;
+}

Added: trunk/filo/i386/context.h
===================================================================
--- trunk/filo/i386/context.h	                        (rev 0)
+++ trunk/filo/i386/context.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,66 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef i386_CONTEXT_H
+#define i386_CONTEXT_H
+
+struct context {
+    /* Stack Segment, placed here because of the alignment issue... */
+    u16 ss;
+    /* Used with sgdt/lgdt */
+    u16 gdt_limit;
+    u32 gdt_base;
+    /* General registers, accessed with pushal/popal */
+    u32 edi;
+    u32 esi;
+    u32 ebp;
+    u32 esp; /* points just below eax */
+    u32 ebx;
+    u32 edx;
+    u32 ecx;
+    u32 eax;
+#define ESP_LOC(ctx) (&(ctx)->gs)
+    /* Segment registers */
+    u32 gs;
+    u32 fs;
+    u32 es;
+    u32 ds;
+    /* Flags */
+    u32 eflags;
+    /* Code segment:offset */
+    u32 eip;
+    u32 cs;
+    /* Optional stack contents */
+    u32 return_addr;
+    u32 param[0];
+};
+
+/* Create a new context in the given stack */
+struct context *
+init_context(u8 *stack, u32 stack_size, int num_param);
+
+/* Switch context */
+struct context *switch_to(struct context *);
+
+/* Holds physical address of boot context */
+extern unsigned long __boot_ctx;
+
+/* This can always be safely used to refer to the boot context */
+#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx))
+
+#endif /* i386_CONTEXT_H */

Added: trunk/filo/i386/include/arch/byteorder.h
===================================================================
--- trunk/filo/i386/include/arch/byteorder.h	                        (rev 0)
+++ trunk/filo/i386/include/arch/byteorder.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,64 @@
+#ifndef ARCH_ENDIAN_H
+#define ARCH_ENDIAN_H
+
+static inline u16 __i386_bswap_16(u16 x)
+{
+	__asm__("xchgb %b0,%h0\n\t"
+		: "=q" (x)
+		: "0" (x));
+	return x;
+}
+
+static inline u32 __i386_bswap_32(u32 x)
+{
+	__asm__("xchgb %b0,%h0\n\t"
+		"rorl $16,%0\n\t"
+		"xchgb %b0,%h0"
+		: "=q" (x)
+		: "0" (x));
+	return x;
+}
+
+
+#define __bswap_constant_16(x) \
+	((u16)((((u16)(x) & 0x00ff) << 8) | \
+		(((u16)(x) & 0xff00) >> 8)))
+
+#define __bswap_constant_32(x) \
+	((u32)((((u32)(x) & 0x000000ffU) << 24) | \
+		(((u32)(x) & 0x0000ff00U) <<  8) | \
+		(((u32)(x) & 0x00ff0000U) >>  8) | \
+		(((u32)(x) & 0xff000000U) >> 24)))
+
+#define __bswap_16(x) \
+	((u16)(__builtin_constant_p(x) ? \
+	__bswap_constant_16(x) : \
+	__i386_bswap_16(x)))
+
+
+#define __bswap_32(x) \
+	((u32)(__builtin_constant_p(x) ? \
+	__bswap_constant_32(x) : \
+	__i386_bswap_32(x)))
+
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#define le32_to_cpup(x) (*(u32 *)(x))
+#define cpu_to_le16p(x) (*(u16*)(x))
+
+#define ntohl(x)        __bswap_32(x)
+#define htonl(x)        __bswap_32(x)
+#define ntohs(x)        __bswap_16(x)
+#define htons(x)        __bswap_16(x)
+#define cpu_to_le32(x)  (x)
+#define cpu_to_le16(x)  (x)
+#define cpu_to_be32(x)  __bswap_32(x)
+#define cpu_to_be16(x)  __bswap_16(x)
+#define le32_to_cpu(x)  (x)
+#define le16_to_cpu(x)  (x)
+#define be32_to_cpu(x)  __bswap_32(x)
+#define be16_to_cpu(x)  __bswap_16(x)
+
+#endif /* ARCH_ENDIAN_H */
+

Added: trunk/filo/i386/include/arch/elf.h
===================================================================
--- trunk/filo/i386/include/arch/elf.h	                        (rev 0)
+++ trunk/filo/i386/include/arch/elf.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,5 @@
+#define ARCH_ELF_CLASS ELFCLASS32
+#define ARCH_ELF_DATA ELFDATA2LSB
+#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486)
+typedef Elf32_Ehdr Elf_ehdr;
+typedef Elf32_Phdr Elf_phdr;

Added: trunk/filo/i386/include/arch/eltorito.h
===================================================================
--- trunk/filo/i386/include/arch/eltorito.h	                        (rev 0)
+++ trunk/filo/i386/include/arch/eltorito.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,3 @@
+#ifndef ELTORITO_PLATFORM
+#define ELTORITO_PLATFORM ELTORITO_PLATFORM_X86
+#endif /* ELTORITO_PLATFORM */

Added: trunk/filo/i386/include/arch/timer.h
===================================================================
--- trunk/filo/i386/include/arch/timer.h	                        (rev 0)
+++ trunk/filo/i386/include/arch/timer.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,32 @@
+/*
+ * This file is part of FILO.
+ *
+ * (C) 2004-2008 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef	TIMER_H
+#define TIMER_H
+
+extern u32 cpu_khz;
+
+u64 currticks(void);
+int getrtsecs (void);
+
+#define TICKS_PER_SEC (cpu_khz * 1000)
+#define TICKS_PER_USEC (cpu_khz / 1000)
+
+
+#endif	/* TIMER_H */

Added: trunk/filo/i386/ldscript
===================================================================
--- trunk/filo/i386/ldscript	                        (rev 0)
+++ trunk/filo/i386/ldscript	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,91 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* When started from General Software BIOS */
+/* BASE_ADDR = 0x40000; */
+/* When started from coreboot */
+BASE_ADDR = 0x100000;          
+
+
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386)
+
+ENTRY(entry)
+
+/* 32KB heap and 16KB stack */
+HEAP_SIZE = 3276800;
+STACK_SIZE = 163840;
+
+SECTIONS
+{
+    . = BASE_ADDR;
+
+    /* Put Multiboot header near beginning of file, if any. */
+    .hdr : { *(.hdr) *(.hdr.*) }
+
+    /* Start of the program. 
+     * Now the version string is in the note, we must include it
+     * in the program. Otherwise we lose the string after relocation. */
+    . = ALIGN(16);
+    _start = .;
+
+    /* Putting ELF notes near beginning of file might help bootloaders.
+     * We discard .note sections other than .note.ELFBoot and .note.pinfo,
+     * because some versions of GCC generates useless ones. */
+    .note : { *(.note.ELFBoot) *(note.pinfo) }
+
+    /* Normal sections */
+    .boot : { *(.boot) *(.boot.*) }
+    .text : { *(.text) *(.text.*) }
+    .rodata : {
+	. = ALIGN(4);
+	sound_drivers_start = .;
+	*(.rodata.sound_drivers)
+	sound_drivers_end = .;
+	*(.rodata)
+	*(.rodata.*)
+    }
+    .data : { *(.data) *(.data.*) }
+
+    .bss : {
+	*(.bss)
+	*(.bss.*)
+	*(COMMON)
+
+	/* heap and stack */
+
+	. = ALIGN(16);
+	_heap = .;
+	. += HEAP_SIZE;
+	. = ALIGN(16);
+	_eheap = .;
+
+	_stack = .;
+	. += STACK_SIZE;
+	. = ALIGN(16);
+	_estack = .;
+    }
+
+    .initctx : {
+	/* Initial contents of stack. This MUST BE just after the stack. */
+	*(.initctx)
+    }
+
+    _end = .;
+
+    /DISCARD/ : { *(.comment) *(.note) }
+}

Added: trunk/filo/i386/linux_load.c
===================================================================
--- trunk/filo/i386/linux_load.c	                        (rev 0)
+++ trunk/filo/i386/linux_load.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,695 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Linux/i386 loader
+ * Supports bzImage, zImage and Image format.
+ *
+ * Based on work by Steve Gehlbach.
+ * Portions are taken from mkelfImage.
+ *
+ * 2003-09 by SONE Takeshi
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <fs.h>
+#include "context.h"
+#include "segment.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_LINUXLOAD
+#include <debug.h>
+
+#define LINUX_PARAM_LOC 0x90000
+#define COMMAND_LINE_LOC 0x91000
+#define GDT_LOC 0x92000
+#define STACK_LOC 0x93000
+
+#define E820MAX	32		/* number of entries in E820MAP */
+struct e820entry {
+	unsigned long long addr;	/* start of memory segment */
+	unsigned long long size;	/* size of memory segment */
+	unsigned long type;		/* type of memory segment */
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS	4
+};
+
+/* The header of Linux/i386 kernel */
+struct linux_header {
+    u8  reserved1[0x1f1];		/* 0x000 */
+    u8  setup_sects;		/* 0x1f1 */
+    u16 root_flags;		/* 0x1f2 */
+    u8  reserved2[6];		/* 0x1f4 */
+    u16 vid_mode;			/* 0x1fa */
+    u16 root_dev;			/* 0x1fc */
+    u16 boot_sector_magic;		/* 0x1fe */
+    /* 2.00+ */
+    u8  reserved3[2];		/* 0x200 */
+    u8  header_magic[4];		/* 0x202 */
+    u16 protocol_version;		/* 0x206 */
+    u32 realmode_swtch;		/* 0x208 */
+    u16 start_sys;			/* 0x20c */
+    u16 kver_addr;			/* 0x20e */
+    u8  type_of_loader;		/* 0x210 */
+    u8  loadflags;			/* 0x211 */
+    u16 setup_move_size;		/* 0x212 */
+    u32 code32_start;		/* 0x214 */
+    u32 ramdisk_image;		/* 0x218 */
+    u32 ramdisk_size;		/* 0x21c */
+    u8  reserved4[4];		/* 0x220 */
+    /* 2.01+ */
+    u16 heap_end_ptr;		/* 0x224 */
+    u8  reserved5[2];		/* 0x226 */
+    /* 2.02+ */
+    u32 cmd_line_ptr;		/* 0x228 */
+    /* 2.03+ */
+    u32 initrd_addr_max;		/* 0x22c */
+} __attribute__ ((packed));
+
+
+/* Paramters passed to 32-bit part of Linux
+ * This is another view of the structure above.. */
+struct linux_params {
+    u8  orig_x;			/* 0x00 */
+    u8  orig_y;			/* 0x01 */
+    u16 ext_mem_k;			/* 0x02 -- EXT_MEM_K sits here */
+    u16 orig_video_page;		/* 0x04 */
+    u8  orig_video_mode;		/* 0x06 */
+    u8  orig_video_cols;		/* 0x07 */
+    u16 unused2;			/* 0x08 */
+    u16 orig_video_ega_bx;		/* 0x0a */
+    u16 unused3;			/* 0x0c */
+    u8  orig_video_lines;		/* 0x0e */
+    u8  orig_video_isVGA;		/* 0x0f */
+    u16 orig_video_points;		/* 0x10 */
+
+    /* VESA graphic mode -- linear frame buffer */
+    u16 lfb_width;			/* 0x12 */
+    u16 lfb_height;		/* 0x14 */
+    u16 lfb_depth;			/* 0x16 */
+    u32 lfb_base;			/* 0x18 */
+    u32 lfb_size;			/* 0x1c */
+    u16 cl_magic;			/* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+    u16 cl_offset;			/* 0x22 */
+    u16 lfb_linelength;		/* 0x24 */
+    u8  red_size;			/* 0x26 */
+    u8  red_pos;			/* 0x27 */
+    u8  green_size;		/* 0x28 */
+    u8  green_pos;			/* 0x29 */
+    u8  blue_size;			/* 0x2a */
+    u8  blue_pos;			/* 0x2b */
+    u8  rsvd_size;			/* 0x2c */
+    u8  rsvd_pos;			/* 0x2d */
+    u16 vesapm_seg;		/* 0x2e */
+    u16 vesapm_off;		/* 0x30 */
+    u16 pages;			/* 0x32 */
+    u8  reserved4[12];		/* 0x34 -- 0x3f reserved for future expansion */
+
+    //struct apm_bios_info apm_bios_info;	/* 0x40 */
+    u8  apm_bios_info[0x40];
+    //struct drive_info_struct drive_info;	/* 0x80 */
+    u8  drive_info[0x20];
+    //struct sys_desc_table sys_desc_table;	/* 0xa0 */
+    u8  sys_desc_table[0x140];
+    u32 alt_mem_k;			/* 0x1e0 */
+    u8  reserved5[4];		/* 0x1e4 */
+    u8  e820_map_nr;		/* 0x1e8 */
+    u8  reserved6[9];		/* 0x1e9 */
+    u16 mount_root_rdonly;		/* 0x1f2 */
+    u8  reserved7[4];		/* 0x1f4 */
+    u16 ramdisk_flags;		/* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+    u8  reserved8[2];		/* 0x1fa */
+    u16 orig_root_dev;		/* 0x1fc */
+    u8  reserved9[1];		/* 0x1fe */
+    u8  aux_device_info;		/* 0x1ff */
+    u8  reserved10[2];		/* 0x200 */
+    u8  param_block_signature[4];	/* 0x202 */
+    u16 param_block_version;	/* 0x206 */
+    u8  reserved11[8];		/* 0x208 */
+    u8  loader_type;		/* 0x210 */
+#define LOADER_TYPE_LOADLIN         1
+#define LOADER_TYPE_BOOTSECT_LOADER 2
+#define LOADER_TYPE_SYSLINUX        3
+#define LOADER_TYPE_ETHERBOOT       4
+#define LOADER_TYPE_KERNEL          5
+    u8  loader_flags;		/* 0x211 */
+    u8  reserved12[2];		/* 0x212 */
+    u32 kernel_start;		/* 0x214 */
+    u32 initrd_start;		/* 0x218 */
+    u32 initrd_size;		/* 0x21c */
+    u8  reserved12_5[8];		/* 0x220 */
+    u32 cmd_line_ptr;		/* 0x228 */
+    u8  reserved13[164];		/* 0x22c */
+    struct e820entry e820_map[E820MAX];	/* 0x2d0 */
+    u8  reserved16[688];		/* 0x550 */
+#define COMMAND_LINE_SIZE 256
+    /* Command line is copied here by 32-bit i386/kernel/head.S.
+     * So I will follow the boot protocol, rather than putting it
+     * directly here. --ts1 */
+    u8  command_line[COMMAND_LINE_SIZE]; /* 0x800 */
+    u8  reserved17[1792];		/* 0x900 - 0x1000 */
+};
+
+uint64_t forced_memsize;
+
+/* Load the first part the file and check if it's Linux */
+static u32 load_linux_header(struct linux_header *hdr)
+{
+    int load_high;
+    u32 kern_addr;
+
+    if (file_read(hdr, sizeof *hdr) != sizeof *hdr) {
+	printf("Can't read Linux header\n");
+	return 0;
+    }
+    if (hdr->boot_sector_magic != 0xaa55) {
+	printf("Not a Linux kernel image\n");
+	return 0;
+    }
+
+    /* Linux is found. Print some information */
+    if (memcmp(hdr->header_magic, "HdrS", 4) != 0) {
+	/* This may be floppy disk image or something.
+	 * Perform a simple (incomplete) sanity check. */
+	if (hdr->setup_sects >= 16
+		|| file_size() - (hdr->setup_sects<<9) >= 512<<10) {
+	    printf("This looks like a bootdisk image but not like Linux...\n");
+	    return 0;
+	}
+
+	printf("Possible very old Linux");
+	/* This kernel does not even have a protocol version.
+	 * Force the value. */
+	hdr->protocol_version = 0; /* pre-2.00 */
+    } else
+	printf("Found Linux");
+    if (hdr->protocol_version >= 0x200 && hdr->kver_addr) {
+	char kver[256];
+	file_seek(hdr->kver_addr + 0x200);
+	if (file_read(kver, sizeof kver) != 0) {
+	    kver[255] = 0;
+	    printf(" version %s", kver);
+	}
+    }
+    debug(" (protocol %#x)", hdr->protocol_version);
+    load_high = 0;
+    if (hdr->protocol_version >= 0x200) {
+	debug(" (loadflags %#x)", hdr->loadflags);
+	load_high = hdr->loadflags & 1;
+    }
+    if (load_high) {
+	printf(" bzImage");
+	kern_addr = 0x100000;
+    } else {
+	printf(" zImage or Image");
+	kern_addr = 0x1000;
+    }
+    printf(".\n");
+
+    return kern_addr;
+}
+
+/* Set up parameters for 32-bit kernel */
+static void
+init_linux_params(struct linux_params *params, struct linux_header *hdr)
+{
+    debug("Setting up paramters at %#lx\n", virt_to_phys(params));
+    memset(params, 0, sizeof *params);
+
+    /* Copy some useful values from header */
+    params->mount_root_rdonly = hdr->root_flags;
+    params->orig_root_dev = hdr->root_dev;
+
+    /* Video parameters.
+     * This assumes we have VGA in standard 80x25 text mode,
+     * just like our vga.c does.
+     * Cursor position is filled later to allow some more printf's. */
+    params->orig_video_mode = 3;
+    params->orig_video_cols = 80;
+    params->orig_video_lines = 25;
+    params->orig_video_isVGA = 1;
+    params->orig_video_points = 16;
+
+    params->loader_type = 0xff; /* Unregistered Linux loader */
+}
+
+/* Memory map */
+static void
+set_memory_size(struct linux_params *params)
+{
+    int i;
+    uint64_t end;
+    u32 ramtop = 0;
+    struct e820entry *linux_map;
+    struct sysinfo_t *info = &lib_sysinfo;
+    struct memrange *filo_map;
+
+    linux_map = params->e820_map;
+    filo_map = info->memrange;
+    for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) {
+	if (i < E820MAX) {
+	    /* Convert to BIOS e820 style */
+	    linux_map->addr = filo_map->base;
+	    linux_map->size = filo_map->size;
+	    linux_map->type = E820_RAM;
+	    debug("%016Lx - %016Lx\n", linux_map->addr,
+		    linux_map->addr + linux_map->size);
+	    params->e820_map_nr = i+1;
+	}
+
+	/* Find out top of RAM. XXX This ignores hole above 1MB */
+	end = filo_map->base + filo_map->size;
+	if (end < (1ULL << 32)) { /* don't count memory above 4GB */
+	    if (end > ramtop)
+		ramtop = (u32) end;
+	}
+    }
+    debug("ramtop=%#x\n", ramtop);
+    /* Size of memory above 1MB in KB */
+    params->alt_mem_k = (ramtop - (1<<20)) >> 10;
+    /* old style, 64MB max */
+    if (ramtop >= (64<<20))
+	params->ext_mem_k = (63<<10);
+    else
+	params->ext_mem_k = params->alt_mem_k;
+    debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k);
+}
+
+/*
+ * Parse command line
+ * Some parameters, like initrd=<file>, are not passed to kernel,
+ * we are responsible to process them.
+ * Parameters for kernel are copied to kern_cmdline. Returns name of initrd.
+ */
+static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline)
+{
+    const char *start, *sep, *end, *val;
+    char name[64];
+    int len;
+    int k_len;
+    int to_kern;
+    char *initrd = 0;
+    int toolong = 0;
+
+    forced_memsize = 0;
+
+    if (!orig_cmdline) {
+	*kern_cmdline = 0;
+	return 0;
+    }
+
+    k_len = 0;
+    debug("original command line: \"%s\"\n", orig_cmdline);
+    debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline));
+
+    start = orig_cmdline;
+    while (*start == ' ')
+	start++;
+    while (*start) {
+	end = strchr(start, ' ');
+	if (!end)
+	    end = start + strlen(start);
+	sep = strchr(start, '=');
+	if (!sep || sep > end)
+	    sep = end;
+	len = sep - start;
+	if (len >= sizeof(name))
+	    len = sizeof(name) - 1;
+	memcpy(name, start, len);
+	name[len] = 0;
+
+	if (*sep == '=') {
+	    val = sep + 1;
+	    len = end - val;
+	} else {
+	    val = 0;
+	    len = 0;
+	}
+
+	/* Only initrd= and mem= are handled here. vga= is not,
+	 * which I believe is a paramter to the realmode part of Linux,
+	 * which we don't execute. */
+	if (strcmp(name, "initrd") == 0) {
+	    if (!val)
+		printf("Missing filename to initrd parameter\n");
+	    else {
+		initrd = malloc(len + 1);
+		memcpy(initrd, val, len);
+		initrd[len] = 0;
+		debug("initrd=%s\n", initrd);
+	    }
+	    /* Don't pass this to kernel */
+	    to_kern = 0;
+	} else if (strcmp(name, "mem") == 0) {
+	    if (!val)
+		printf("Missing value for mem parameter\n");
+	    else {
+		forced_memsize = strtoull_with_suffix(val, (char**)&val, 0);
+		if (forced_memsize == 0)
+		    printf("Invalid mem option, ignored\n");
+		if (val != end) {
+		    printf("Garbage after mem=<size>, ignored\n");
+		    forced_memsize = 0;
+		}
+		debug("mem=%Lu\n", forced_memsize);
+	    }
+	    /* mem= is for both loader and kernel */
+	    to_kern = 1;
+	} else
+	    to_kern = 1;
+
+	if (to_kern) {
+	    /* Copy to kernel command line buffer */
+	    if (k_len != 0)
+		kern_cmdline[k_len++] = ' '; /* put separator */
+	    len = end - start;
+	    if (k_len + len >= COMMAND_LINE_SIZE) {
+		len = COMMAND_LINE_SIZE - k_len - 1;
+		if (!toolong) {
+		    printf("Kernel command line is too long; truncated to "
+			    "%d bytes\n", COMMAND_LINE_SIZE-1);
+		    toolong = 1;
+		}
+	    }
+	    memcpy(kern_cmdline + k_len, start, len);
+	    k_len += len;
+	}
+
+	start = end;
+	while (*start == ' ')
+	    start++;
+    }
+    kern_cmdline[k_len] = 0;
+    debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline);
+
+    return initrd;
+}
+
+/* Set command line location */
+static void set_command_line_loc(struct linux_params *params,
+	struct linux_header *hdr)
+{
+    if (hdr->protocol_version >= 0x202) {
+	/* new style */
+	params->cmd_line_ptr = COMMAND_LINE_LOC;
+    } else {
+	/* old style */
+	params->cl_magic = CL_MAGIC_VALUE;
+	params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;
+    }
+}
+
+/* Load 32-bit part of kernel */
+static int load_linux_kernel(struct linux_header *hdr, u32 kern_addr)
+{
+    u32 kern_offset, kern_size;
+
+    if (hdr->setup_sects == 0)
+	hdr->setup_sects = 4;
+    kern_offset = (hdr->setup_sects + 1) * 512;
+    file_seek(kern_offset);
+    kern_size = file_size() - kern_offset;
+    debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size);
+
+    if (using_devsize) {
+	printf("Attempt to load up to end of device as kernel; "
+		"specify the image size\n");
+	return 0;
+    }
+
+    printf("Loading kernel... ");
+    if (file_read(phys_to_virt(kern_addr), kern_size) != kern_size) {
+	printf("Can't read kernel\n");
+	return 0;
+    }
+    printf("ok\n");
+
+    return kern_size;
+}
+
+static int load_initrd(struct linux_header *hdr, 
+	u32 kern_end, struct linux_params *params, const char *initrd_file)
+{
+    u32 max;
+    u32 start, end, size;
+    uint64_t forced;
+    extern char _start[];
+#if 0
+    extern char _end[];
+#endif
+
+    if (!file_open(initrd_file)) {
+	printf("Can't open initrd: %s\n", initrd_file);
+	return -1;
+    }
+    if (using_devsize) {
+	printf("Attempt to load up to end of device as initrd; "
+		"specify the image size\n");
+	return -1;
+    }
+    size = file_size();
+
+
+    /* Find out the kernel's restriction on how high the initrd can be
+     * placed */
+    if (hdr->protocol_version >= 0x203)
+	max = hdr->initrd_addr_max;
+    else
+	max = 0x38000000; /* Hardcoded value for older kernels */
+    
+    /* FILO itself is at the top of RAM. (relocated)
+     * So, try putting initrd just below us. */
+    end = virt_to_phys(_start);
+    if (end > max)
+	end = max;
+
+    /* If "mem=" option is given, we have to put the initrd within
+     * the specified range. */
+    if (forced_memsize) {
+	forced = forced_memsize;
+	if (forced > max)
+	    forced = max;
+	/* If the "mem=" is lower, it's easy */
+	if (forced <= end)
+	    end = forced;
+#if 0
+	else {
+	    /* Otherwise, see if we can put it above us.
+	     * 
+	     *   This would be a good idea if we could easily find out
+	     *   where the memory hole lives.
+	     *   
+	     *   There's nothing wrong with the initrd living below
+	     *   FILO. (stepan)
+	     *
+	     *   The problems is even a 64bit kernel will live in
+	     *   32bit address space, so if you have a lot of memory
+	     *   and specify mem=xG with x>4, the maximum allowed 
+	     *   initrd address (2.6.x sets this to 0xffffffff) will 
+	     *   be used for the high limit. (offset 22c in vmlinuz)
+	     *
+	     *   you might want to enable this if you limit memory with
+	     *   mem=yG with y<4.
+	     */
+	    if (virt_to_phys(_end) + size <= forced)
+		end = forced; /* Ok */
+	}
+#endif
+    }
+
+    start = end - size;
+    start &= ~0xfff; /* page align */
+    end = start + size;
+
+    debug("start=%#x end=%#x\n", start, end);
+
+    if (start < kern_end) {
+	printf("Initrd is too big to fit in memory\n");
+	return -1;
+    }
+
+    printf("Loading initrd... ");
+    if (file_read(phys_to_virt(start), size) != size) {
+	printf("Can't read initrd\n");
+	return -1;
+    }
+    printf("ok\n");
+
+    params->initrd_start = start;
+    params->initrd_size = size;
+
+    return 0;
+}
+
+static void hardware_setup(void)
+{
+    /* Disable nmi */
+    outb(0x80, 0x70);
+
+    /* Make sure any coprocessor is properly reset.. */
+    outb(0, 0xf0);
+    outb(0, 0xf1);
+
+    /* we're getting screwed again and again by this problem of the 8259. 
+     * so we're going to leave this lying around for inclusion into 
+     * crt0.S on an as-needed basis. 
+     *
+     * well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+     * we put them right after the intel-reserved hardware interrupts, at
+     * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+     * messed this up with the original PC, and they haven't been able to
+     * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+     * which is used for the internal hardware interrupts as well. We just
+     * have to reprogram the 8259's, and it isn't fun.
+     */
+
+    outb(0x11, 0x20);		/* initialization sequence to 8259A-1 */
+    outb(0x11, 0xA0);		/* and to 8259A-2 */
+
+    outb(0x20, 0x21);		/* start of hardware int's (0x20) */
+    outb(0x28, 0xA1);		/* start of hardware int's 2 (0x28) */
+
+    outb(0x04, 0x21);		/* 8259-1 is master */
+    outb(0x02, 0xA1);		/* 8259-2 is slave */
+
+    outb(0x01, 0x21);		/* 8086 mode for both */
+    outb(0x01, 0xA1);
+
+    outb(0xFF, 0xA1);		/* mask off all interrupts for now */
+    outb(0xFB, 0x21);		/* mask all irq's but irq2 which is cascaded */
+}
+
+/* Start Linux */
+static int start_linux(u32 kern_addr, struct linux_params *params)
+{
+    struct segment_desc *linux_gdt;
+    struct context *ctx;
+#ifdef CONFIG_VGA_CONSOLE
+    unsigned int cursor_x, cursor_y, cursor_en;
+#endif
+#ifdef CONFIG_PCMCIA_CF
+    unsigned char *cf_bar;
+    int i;
+#endif
+
+    ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);
+
+    /* Linux expects GDT being in low memory */
+    linux_gdt = phys_to_virt(GDT_LOC);
+    memset(linux_gdt, 0, 13*sizeof(struct segment_desc));
+    /* Normal kernel code/data segments */
+    linux_gdt[2] = gdt[FLAT_CODE];
+    linux_gdt[3] = gdt[FLAT_DATA];
+    /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible
+     * segments (2 and 3), so it SHOULD not be a problem. 
+     * However, some distro kernels (eg. RH9) with backported threading 
+     * patch use 12 and 13 also when booting... */
+    linux_gdt[12] = gdt[FLAT_CODE];
+    linux_gdt[13] = gdt[FLAT_DATA];
+    ctx->gdt_base = GDT_LOC;
+    ctx->gdt_limit = 14*8-1;
+    ctx->cs = 0x10;
+    ctx->ds = 0x18;
+    ctx->es = 0x18;
+    ctx->fs = 0x18;
+    ctx->gs = 0x18;
+    ctx->ss = 0x18;
+
+    /* Parameter location */
+    ctx->esi = virt_to_phys(params);
+
+    /* Entry point */
+    ctx->eip = kern_addr;
+
+    debug("eip=%#x\n", kern_addr);
+    printf("Jumping to entry point...\n");
+
+#ifdef CONFIG_VGA_CONSOLE
+    /* Update VGA cursor position.
+     * This must be here because the printf changes the value! */
+    video_console_get_cursor(&cursor_x, &cursor_y, &cursor_en);
+    params->orig_x = cursor_x;
+    params->orig_y = cursor_y;
+#endif
+#ifdef CONFIG_PCMCIA_CF
+    cf_bar = phys_to_virt(pci_read_config32(PCI_DEV(0, 0xa, 1), 0x10));
+    for( i = 0x836 ; i < 0x840 ; i++){
+        cf_bar[i] = 0;
+    }
+#endif
+    /* Go... */
+    ctx = switch_to(ctx);
+
+    /* It's impossible but... */
+    printf("Returned with eax=%#x\n", ctx->eax);
+
+    return ctx->eax;
+}
+
+int linux_load(const char *file, const char *cmdline)
+{
+    struct linux_header hdr;
+    struct linux_params *params;
+    u32 kern_addr, kern_size;
+    char *initrd_file = 0;
+
+    if (!file_open(file))
+	return -1;
+
+    kern_addr = load_linux_header(&hdr);
+    if (kern_addr == 0) {
+    	file_close();
+    	return LOADER_NOT_SUPPORT;
+    }
+
+    params = phys_to_virt(LINUX_PARAM_LOC);
+    init_linux_params(params, &hdr);
+    set_memory_size(params);
+    initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC));
+    set_command_line_loc(params, &hdr);
+
+    kern_size = load_linux_kernel(&hdr, kern_addr);
+    if (kern_size == 0) {
+	if (initrd_file)
+	    free(initrd_file);
+	file_close();
+	return -1;
+    }
+
+    if (initrd_file) {
+	if (load_initrd(&hdr, kern_addr+kern_size, params, initrd_file)
+		!= 0) {
+	    free(initrd_file);
+	    file_close();
+	    return -1;
+	}
+	free(initrd_file);
+    }
+    
+    file_close();
+
+    hardware_setup();
+
+    start_linux(kern_addr, params);
+    return 0;
+}

Added: trunk/filo/i386/segment.c
===================================================================
--- trunk/filo/i386/segment.c	                        (rev 0)
+++ trunk/filo/i386/segment.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,132 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+/* Segmentation of the i386 architecture.
+ *
+ * 2003-07 by SONE Takeshi
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include "segment.h"
+
+#define DEBUG_THIS CONFIG_DEBUG_SEGMENT
+#include <debug.h>
+
+/* i386 lgdt argument */
+struct gdtarg {
+    unsigned short limit;
+    unsigned int base;
+} __attribute__((packed));
+
+/* How far the virtual address (used in C) is different from physical 
+ * address. Since we start in flat mode, the initial value is zero. */
+unsigned long virt_offset = 0;
+
+/* GDT, the global descriptor table */
+struct segment_desc gdt[NUM_SEG] = {
+    /* 0x00: null segment */
+    {0, 0, 0, 0, 0, 0},
+    /* 0x08: flat code segment */
+    {0xffff, 0, 0, 0x9f, 0xcf, 0},
+    /* 0x10: flat data segment */
+    {0xffff, 0, 0, 0x93, 0xcf, 0},
+    /* 0x18: code segment for relocated execution */
+    {0xffff, 0, 0, 0x9f, 0xcf, 0},
+    /* 0x20: data segment for relocated execution */
+    {0xffff, 0, 0, 0x93, 0xcf, 0},
+};
+
+extern char _start[], _end[];
+
+void relocate(void)
+{
+    int i;
+    unsigned long prog_addr;
+    unsigned long prog_size;
+    unsigned long addr, new_base;
+    unsigned long long segsize;
+    unsigned long new_offset;
+    unsigned d0, d1, d2;
+    struct gdtarg gdtarg;
+    struct sysinfo_t *info = &lib_sysinfo;
+#define ALIGNMENT 0x1000
+
+    prog_addr = virt_to_phys(&_start);
+    prog_size = virt_to_phys(&_end) - virt_to_phys(&_start);
+    debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1);
+
+    new_base = 0;
+    for (i = 0; i < info->n_memranges; i++) {
+	if (info->memrange[i].base >= 1ULL<<32)
+	    continue;
+	segsize = info->memrange[i].size;
+	if (info->memrange[i].base + segsize > 1ULL<<32)
+	    segsize = (1ULL<<32) - info->memrange[i].base;
+	if (segsize < prog_size+ALIGNMENT)
+	    continue;
+	addr = info->memrange[i].base + segsize - prog_size;
+	addr &= ~(ALIGNMENT-1);
+	if (addr >= prog_addr && addr < prog_addr + prog_size)
+	    continue;
+	if (prog_addr >= addr && prog_addr < addr + prog_size)
+	    continue;
+	if (addr > new_base)
+	    new_base = addr;
+    }
+    if (new_base == 0) {
+	printf("Can't find address to relocate\n");
+	return;
+    }
+
+    debug("Relocating to %#lx-%#lx... ",
+	    new_base, new_base + prog_size - 1);
+
+    /* New virtual address offset */
+    new_offset = new_base - (unsigned long) &_start;
+
+    /* Tweak the GDT */
+    gdt[RELOC_CODE].base_0 = (unsigned short) new_offset;
+    gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16);
+    gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24);
+    gdt[RELOC_DATA].base_0 = (unsigned short) new_offset;
+    gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16);
+    gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24);
+
+    /* Load new GDT and reload segments */
+    gdtarg.base = new_offset + (unsigned long) gdt;
+    gdtarg.limit = GDT_LIMIT;
+    __asm__ __volatile__ (
+	    "rep; movsb\n\t" /* copy everything */
+	    "lgdt %3\n\t"
+	    "ljmp %4, $1f\n1:\t"
+	    "movw %5, %%ds\n\t"
+	    "movw %5, %%es\n\t"
+	    "movw %5, %%fs\n\t"
+	    "movw %5, %%gs\n\t"
+	    "movw %5, %%ss\n"
+	    : "=&S" (d0), "=&D" (d1), "=&c" (d2)
+	    : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS), 
+	    "0" (&_start), "1" (new_base), "2" (prog_size));
+
+    virt_offset = new_offset; // for FILO
+    virtual_offset = new_offset; // for libpayload
+
+    debug("ok\n");
+}
+

Added: trunk/filo/i386/segment.h
===================================================================
--- trunk/filo/i386/segment.h	                        (rev 0)
+++ trunk/filo/i386/segment.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,47 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+/* Segment indexes. Must match the gdt definition in segment.c. */
+enum {
+    NULL_SEG,
+    FLAT_CODE,
+    FLAT_DATA,
+    RELOC_CODE,
+    RELOC_DATA,
+    NUM_SEG,
+};
+
+/* Values for segment selector register */
+#define FLAT_CS (FLAT_CODE << 3)
+#define FLAT_DS (FLAT_DATA << 3)
+#define RELOC_CS (RELOC_CODE << 3)
+#define RELOC_DS (RELOC_DATA << 3)
+
+/* i386 segment descriptor */
+struct segment_desc {
+    unsigned short limit_0;
+    unsigned short base_0;
+    unsigned char base_16;
+    unsigned char types;
+    unsigned char flags;
+    unsigned char base_24;
+};
+
+extern struct segment_desc gdt[NUM_SEG];
+
+#define GDT_LIMIT ((NUM_SEG << 3) - 1)

Added: trunk/filo/i386/switch.S
===================================================================
--- trunk/filo/i386/switch.S	                        (rev 0)
+++ trunk/filo/i386/switch.S	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,116 @@
+	.globl	entry, __switch_context, __exit_context, halt
+
+	.section ".boot", "xa"
+	.align	4
+
+/*
+ * Entry point
+ * We start execution from here.
+ * It is assumed that CPU is in 32-bit protected mode and 
+ * all segments are 4GB and base zero (flat model).
+ */
+entry:
+	/* Save boot context and switch to our main context.
+	 * Main context is statically defined in C.
+	 */
+	pushl	%cs
+	call	__switch_context
+
+	/* We get here when the main context switches back to
+	 * the boot context.
+	 * Return to previous bootloader.
+	 */
+	ret
+
+/*
+ * Switch execution context
+ * This saves registers, segments, and GDT in the stack, then
+ * switches the stack, and restores everything from the new stack.
+ * This function takes no argument. New stack pointer is
+ * taken from global variable __context, and old stack pointer
+ * is also saved to __context. This way we can just jump to 
+ * this routine to get back to the original context.
+ *
+ * Call this routine with lcall or pushl %cs; call.
+ */
+__switch_context:
+	/* Save everything in current stack */
+	pushfl		    /* 56 */
+	pushl	%ds	    /* 52 */
+	pushl	%es	    /* 48 */
+	pushl	%fs	    /* 44 */
+	pushl	%gs	    /* 40 */
+	pushal		    /* 8 */
+	subl	$8, %esp
+	movw	%ss, (%esp) /* 0 */
+	sgdt	2(%esp)	    /* 2 */
+
+#if 0
+	/* Swap %cs and %eip on the stack, so lret will work */
+	movl	60(%esp), %eax
+	xchgl	%eax, 64(%esp)
+	movl	%eax, 60(%esp)
+#endif
+	
+	/* At this point we don't know if we are on flat segment
+	 * or relocated. So compute the address offset from %eip.
+	 * Assuming CS.base==DS.base==SS.base.
+	 */
+	call	1f
+1:	popl	%ebx
+	subl	$1b, %ebx
+
+	/* Interrupts are not allowed... */
+	cli
+	
+	/* Current context pointer is our stack pointer */
+	movl	%esp, %esi
+
+	/* Normalize the ctx pointer */
+	subl	%ebx, %esi
+
+	/* Swap it with new value */
+	xchgl	%esi, __context(%ebx)
+
+	/* Adjust new ctx pointer for current address offset */
+	addl	%ebx, %esi
+
+	/* Load new %ss and %esp to temporary */
+	movzwl	(%esi), %edx
+	movl	20(%esi), %eax
+
+	/* Load new GDT */
+	lgdt	2(%esi)
+
+	/* Load new stack segment with new GDT */
+	movl	%edx, %ss
+
+	/* Set new stack pointer, but we have to adjust it because
+	 * pushal saves %esp value before pushal, and we want the value
+	 * after pushal.
+	 */
+	leal	-32(%eax), %esp
+
+	/* Load the rest from new stack */
+	popal
+	popl	%gs
+	popl	%fs
+	popl	%es
+	popl	%ds
+	popfl
+
+	/* Finally, load new %cs and %eip */
+	lret
+
+__exit_context:
+	/* Get back to the original context */
+	pushl	%cs
+	call	__switch_context
+
+	/* We get here if the other context attempt to switch to this
+	 * dead context. This should not happen. */
+
+halt:
+	cli
+	hlt
+	jmp	halt

Added: trunk/filo/i386/sys_info.c
===================================================================
--- trunk/filo/i386/sys_info.c	                        (rev 0)
+++ trunk/filo/i386/sys_info.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,36 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <sys_info.h>
+#include "context.h"
+#define DEBUG_THIS CONFIG_DEBUG_SYS_INFO
+#include <debug.h>
+
+void collect_sys_info(struct sys_info *info)
+{
+    /* Pick up paramters given by bootloader to us */
+    info->boot_type = boot_ctx->eax;
+    info->boot_data = boot_ctx->ebx;
+    info->boot_arg = boot_ctx->param[0];
+    debug("boot eax = %#lx\n", info->boot_type);
+    debug("boot ebx = %#lx\n", info->boot_data);
+    debug("boot arg = %#lx\n", info->boot_arg);
+
+    collect_elfboot_info(info);
+}

Added: trunk/filo/i386/timer.c
===================================================================
--- trunk/filo/i386/timer.c	                        (rev 0)
+++ trunk/filo/i386/timer.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,39 @@
+/*
+ * This file is part of FILO.
+ *
+ * (C) 2004-2008 coresystems GmbH
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <arch/rdtsc.h>
+
+extern unsigned int cpu_khz;
+
+u64 currticks(void)
+{
+	/* Read the Time Stamp Counter */
+	return  rdtsc() / cpu_khz;
+}
+
+int getrtsecs (void)
+{
+	u64 t;
+	t=currticks();
+	t=t/1000;
+	return (int)t;
+}
+
+

Added: trunk/filo/i386/wince_load.c
===================================================================
--- trunk/filo/i386/wince_load.c	                        (rev 0)
+++ trunk/filo/i386/wince_load.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ *
+ *	WindowsCE/i386 loader 
+ *
+ *	Copyright 2006 Andrei Birjukov <andrei.birjukov at artecdesign.ee> and
+ *	Artec Design LLC http://www.artecdesign.ee
+ *
+ *	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 <libpayload.h>
+#include <lib.h>
+#include <fs.h>
+#include <arch/io.h>
+#include "context.h"
+#include "segment.h"
+
+#define DEBUG_THIS DEBUG_WINCELOAD
+#include <debug.h>
+
+#define BOOTARG_PTR_LOCATION	0x001FFFFC
+#define BOOTARG_LOCATION		0x001FFF00
+#define BOOTARG_SIGNATURE		0x544F4F42
+#define BOOTARG_VERSION_SIG		0x12345678
+#define BOOTARG_MAJOR_VER		1
+#define BOOTARG_MINOR_VER		0
+
+#define MAX_DEV_NAMELEN			16	// Should match EDBG_MAX_DEV_NAMELEN.
+
+#define LDRFL_USE_EDBG			0x0001	// Set to attempt to use debug Ethernet
+// The following two flags are only looked at if LDRFL_USE_EDBG is set
+#define LDRFL_ADDR_VALID		0x0002	// Set if EdbgAddr field is valid
+#define LDRFL_JUMPIMG			0x0004	// If set, don't communicate with eshell to get
+// The following flag is only used for backup FLASH operation
+#define LDRFL_FLASH_BACKUP		0x80
+// configuration, use ucEshellFlags field.
+// Use this constant in EdbgIRQ to specify that EDBG should run without an interrupt.
+#define EDBG_IRQ_NONE			0xFF
+
+#define EDBG_ADAPTER_DEFAULT	2
+#define EDBG_ADAPTER_RTL8139	4
+
+#define PSIZE					(1500)	// Max Packet Size
+#define DSIZE					(PSIZE+12)
+#define BIN_HDRSIG_SIZE			7
+
+#define ROM_SIGNATURE_OFFSET	0x40	// Offset from the image's physfirst address to the ROM signature.
+#define ROM_SIGNATURE			0x43454345
+#define ROM_TOC_POINTER_OFFSET	0x44	// Offset from the image's physfirst address to the TOC pointer.
+#define ROM_TOC_OFFSET_OFFSET	0x48	// Offset from the image's physfirst address to the TOC offset (from physfirst).
+
+#define GDT_LOC					0x92000
+#define STACK_LOC				0x93000
+
+typedef struct _EDBG_ADDR {
+	u32 dwIP;
+	u16 wMAC[3];
+	u16 wPort;
+} EDBG_ADDR;
+
+typedef struct _BOOT_ARGS {
+	u8 ucVideoMode;
+	u8 ucComPort;
+	u8 ucBaudDivisor;
+	u8 ucPCIConfigType;
+	u32 dwSig;
+	u32 dwLen;
+	u8 ucLoaderFlags;
+	u8 ucEshellFlags;
+	u8 ucEdbgAdapterType;
+	u8 ucEdbgIRQ;
+	u32 dwEdbgBaseAddr;
+	u32 dwEdbgDebugZone;
+	EDBG_ADDR EdbgAddr;
+	EDBG_ADDR EshellHostAddr;
+	EDBG_ADDR DbgHostAddr;
+	EDBG_ADDR CeshHostAddr;
+	EDBG_ADDR KdbgHostAddr;
+	u32 DHCPLeaseTime;
+	u16 EdbgFlags;
+	u16 KitlTransport;
+	u32 dwEBootFlag;
+	u32 dwEBootAddr;
+	u32 dwLaunchAddr;
+	u32 pvFlatFrameBuffer;
+	u16 vesaMode;
+	u16 cxDisplayScreen;
+	u16 cyDisplayScreen;
+	u16 cxPhysicalScreen;
+	u16 cyPhysicalScreen;
+	u16 cbScanLineLength;
+	u16 bppScreen;
+	u8 RedMaskSize;
+	u8 RedMaskPosition;
+	u8 GreenMaskSize;
+	u8 GreenMaskPosition;
+	u8 BlueMaskSize;
+	u8 BlueMaskPosition;
+	u32 dwVersionSig;
+	u16 MajorVersion;
+	u16 MinorVersion;
+	u8 szDeviceNameRoot[MAX_DEV_NAMELEN];
+	u32 dwImgStoreAddr;
+	u32 dwImgLoadAddr;
+	u32 dwImgLength;
+	u8 NANDBootFlags;
+	u8 NANDBusNumber;
+	u32 NANDSlotNumber;
+} BOOT_ARGS;
+
+typedef struct _ROMHDR {
+	u32 dllfirst;
+	u32 dlllast;
+	u32 physfirst;
+	u32 physlast;
+	u32 nummods;
+	u32 ulRAMStart;
+	u32 ulRAMFree;
+	u32 ulRAMEnd;
+	u32 ulCopyEntries;
+	u32 ulCopyOffset;
+	u32 ulProfileLen;
+	u32 ulProfileOffset;
+	u32 numfiles;
+	u32 ulKernelFlags;
+	u32 ulFSRamPercent;
+	u32 ulDrivglobStart;
+	u32 ulDrivglobLen;
+	u16 usCPUType;
+	u16 usMiscFlags;
+	void *pExtensions;
+	u32 ulTrackingStart;
+	u32 ulTrackingLen;
+} ROMHDR;
+
+typedef struct _SEGMENT_INFO {
+	u32 segAddr;
+	u32 segSize;
+	u32 checkSum;
+} SEGMENT_INFO;
+
+typedef void (*PFN_LAUNCH) ();	// WinCE launch function proto
+
+static u8 g_ceSignature[] = { 'B', '0', '0', '0', 'F', 'F', '\n' };
+static void **g_ppBootArgs = NULL;
+BOOT_ARGS *g_pBootArgs = NULL;
+static ROMHDR *pROMHeader = NULL;
+
+static u32 g_imageStart = 0;
+static u32 g_imageSize = 0;
+static u32 g_romOffset = 0;
+
+static int verifyCheckSum(u8 * pData, int nSize, u32 checkSum)
+{
+	// check the CRC
+	u32 crc = 0;
+	int i;
+
+	for (i = 0; i < nSize; i++)
+		crc += *pData++;
+
+	return (crc == checkSum);
+}
+
+int wince_launch(u32 imageStart, u32 imageSize,
+		 u32 entryPoint, ROMHDR * pRomHdr)
+{
+	struct segment_desc *wince_gdt;
+	struct context *ctx;
+
+	debug("start Windows CE from address 0x%x, image loaded 0x%x,%d\n",
+	      entryPoint, imageStart, imageSize);
+
+	// initialize new stack
+	ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);
+
+	// initialize GDT in low memory
+	wince_gdt = phys_to_virt(GDT_LOC);
+	memset(wince_gdt, 0, 13 * sizeof(struct segment_desc));
+	// flat kernel code/data segments
+	wince_gdt[2] = gdt[FLAT_CODE];
+	wince_gdt[3] = gdt[FLAT_DATA];
+
+	wince_gdt[12] = gdt[FLAT_CODE];
+	wince_gdt[13] = gdt[FLAT_DATA];
+	ctx->gdt_base = GDT_LOC;
+	ctx->gdt_limit = 14 * 8 - 1;
+	ctx->cs = 0x10;
+	ctx->ds = 0x18;
+	ctx->es = 0x18;
+	ctx->fs = 0x18;
+	ctx->gs = 0x18;
+	ctx->ss = 0x18;
+
+	// kernel entry point
+	ctx->eip = entryPoint;
+
+	printf("Launching Windows CE...\n");
+
+	// go...!
+	ctx = switch_to(ctx);
+
+	// may never return here
+	printf("returned with eax=%#x\n", ctx->eax);
+	return ctx->eax;
+}
+
+void wince_init_bootarg(u32 entryPoint)
+{
+	// init the BOOT_ARGS pointer at the known address
+	g_ppBootArgs = phys_to_virt(BOOTARG_PTR_LOCATION);
+	*g_ppBootArgs = (void *) BOOTARG_LOCATION;
+
+	// keep our BOOT_ARGS somewhere in a dry dark place 
+	g_pBootArgs = phys_to_virt(BOOTARG_LOCATION);
+
+	debug("BOOT_ARGS at addr 0x%x, pointer at 0x%x [%x]\n",
+	      (unsigned int) *g_ppBootArgs, BOOTARG_PTR_LOCATION,
+	      (unsigned int) g_ppBootArgs);
+
+	memset(g_pBootArgs, 0, sizeof(BOOT_ARGS));
+
+	// this data was copied from WinCE EDBG boot args       
+	g_pBootArgs->ucEdbgAdapterType = EDBG_ADAPTER_DEFAULT;
+	// use the first PCI NIC available
+	g_pBootArgs->ucEdbgIRQ = 0;
+	g_pBootArgs->dwEdbgBaseAddr = 0;
+
+	// set the KITL device name to something adequate
+	strcpy(g_pBootArgs->szDeviceNameRoot, "FILO");
+
+	g_pBootArgs->dwSig = BOOTARG_SIGNATURE;
+	g_pBootArgs->dwLen = sizeof(BOOT_ARGS);
+	g_pBootArgs->dwVersionSig = BOOTARG_VERSION_SIG;
+	g_pBootArgs->MajorVersion = BOOTARG_MAJOR_VER;
+	g_pBootArgs->MinorVersion = BOOTARG_MINOR_VER;
+
+/*
+	g_pBootArgs->ucVideoMode = 255;
+	g_pBootArgs->ucComPort = 1;
+	g_pBootArgs->ucBaudDivisor = 3;
+	g_pBootArgs->ucPCIConfigType = 1;
+	g_pBootArgs->ucLoaderFlags = 0x7;
+*/
+
+	debug("Boot arguments initialized at 0x%x\n",
+	      (unsigned int) *g_ppBootArgs);
+}
+
+int wince_load(const char *file, const char *cmdline)
+{
+	u8 signBuf[BIN_HDRSIG_SIZE], *pDest = NULL;
+	SEGMENT_INFO segInfo;
+	u32 totalBytes = 0;
+
+	if (!file_open(file)) {
+		printf("Failed opening image file: %s\n", file);
+		return LOADER_NOT_SUPPORT;
+	}
+	// read the image signature
+	file_read((void *) signBuf, BIN_HDRSIG_SIZE);
+
+	if (memcmp(signBuf, g_ceSignature, BIN_HDRSIG_SIZE)) {
+		printf("Bad or unknown Windows CE image signature\n");
+		file_close();
+		return LOADER_NOT_SUPPORT;
+	}
+	// now read image start address and size        
+	file_read((void *) &g_imageStart, sizeof(u32));
+	file_read((void *) &g_imageSize, sizeof(u32));
+
+	if (!g_imageStart || !g_imageSize)	// sanity check
+	{
+		printf("Invalid image descriptors\n");
+		file_close();
+		return LOADER_NOT_SUPPORT;
+	}
+
+	printf("Windows CE BIN image, start 0x%x, length %d\n",
+	       g_imageStart, g_imageSize);
+
+	// main image reading loop      
+	while (1) {
+		// first grab the segment descriptor
+		if (file_read(&segInfo, sizeof(SEGMENT_INFO)) <
+		    sizeof(SEGMENT_INFO)) {
+			printf ("\nFailed reading image segment descriptor\n");
+			file_close();
+			return LOADER_NOT_SUPPORT;
+		}
+
+		totalBytes += sizeof(SEGMENT_INFO);	// update data counter
+		printf("#");	// that's a progress bar :)
+
+		// now check if that's the last one
+		if (segInfo.segAddr == 0 && segInfo.checkSum == 0)
+			break;
+
+		// map segment address to current address space
+		pDest = (u8 *) phys_to_virt(segInfo.segAddr);
+		debug("fetched segment address 0x%x [%x] size %d\n",
+		      segInfo.segAddr, (unsigned int) pDest,
+		      segInfo.segSize);
+
+		// read the image segment data from VFS
+		if (file_read((void *) pDest, segInfo.segSize) <
+		    segInfo.segSize) {
+			printf ("\nFailed reading image segment data (address 0x%x, size %d)\n",
+			     segInfo.segAddr, segInfo.segSize);
+			file_close();
+			return LOADER_NOT_SUPPORT;
+		}
+		// check the data integrity
+		if (!verifyCheckSum
+		    (pDest, segInfo.segSize, segInfo.checkSum)) {
+			printf ("\nFailed verifying segment checksum at address 0x%x, size %d\n",
+			     (unsigned int) pDest, segInfo.segSize);
+			file_close();
+			return LOADER_NOT_SUPPORT;
+		}
+		// Look for ROMHDR to compute ROM offset.  NOTE: romimage guarantees that the record containing
+		// the TOC signature and pointer will always come before the record that contains the ROMHDR contents.
+
+		if (segInfo.segSize == sizeof(ROMHDR) && 
+				(*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)) {
+			u32 tempOffset =
+			    (segInfo.segAddr -
+			     *(u32 *) phys_to_virt(g_imageStart +
+							ROM_SIGNATURE_OFFSET
+							+ sizeof(long)));
+			ROMHDR *pROMhdr = (ROMHDR *) pDest;
+
+			// check to make sure this record really contains the ROMHDR.
+			if ((pROMhdr->physfirst == (g_imageStart - tempOffset)) && 
+					(pROMhdr->physlast == (g_imageStart - tempOffset + g_imageSize)) &&
+			    		(u32) (((pROMhdr-> dllfirst << 16) & 0xffff0000) <= pROMhdr->dlllast) &&
+			    		(u32) (((pROMhdr-> dllfirst << 16) & 0x0000ffff) <= pROMhdr->dlllast)) {
+				g_romOffset = tempOffset;
+				debug("\nROM offset = 0x%x\n", g_romOffset);
+			}
+		}
+
+		totalBytes += segInfo.segSize;	// update data counter
+	}
+
+	// we should have moved all image segments to RAM by now
+	printf("\nOS image loaded.\n");
+
+	// check for pTOC signature ("CECE") here, after image in place
+	if (*(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE) {
+		// a pointer to the ROMHDR structure lives just past the ROM_SIGNATURE (which is a longword value).  Note that
+		// this pointer is remapped since it might be a flash address (image destined for flash), but is actually cached
+		// in RAM.
+
+		u32 cacheAddress = *(u32 *) phys_to_virt(g_imageStart + ROM_SIGNATURE_OFFSET + sizeof(u32));
+
+		pROMHeader =
+		    (ROMHDR *) phys_to_virt(cacheAddress + g_romOffset);
+		debug("ROMHDR at address 0x%xh\n",
+		      cacheAddress + g_romOffset);
+	}
+
+	file_close();
+
+	// prepare the boot arguments
+	// note that the last segment size carries the launch address 
+	wince_init_bootarg(segInfo.segSize);
+
+	// finally, call the generic launch() function
+	return wince_launch(g_imageStart, g_imageSize, segInfo.segSize,
+			    pROMHeader);
+}

Added: trunk/filo/include/artecboot.h
===================================================================
--- trunk/filo/include/artecboot.h	                        (rev 0)
+++ trunk/filo/include/artecboot.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,52 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+// Artecboot header, gives information to loader
+
+#define ARTECBOOT_HEADER_MAGIC		0x10ADFACE
+#define CURRENT_VERSION				0x0102
+
+#define OS_UNKNOWN					0x00
+#define OS_LINUX					0x01
+#define OS_WINCE					0x02
+
+#define FLAG_INITRD					0x0001		// if set, the loader will provide initrd to kernel
+#define FLAG_FILESYSTEM				0x0002		// if set, the loader will use specified file names
+#define FLAG_CMDLINE				0x0004		// if set, the loader will pass the new command line
+
+typedef struct __attribute__ ((packed))
+{
+	unsigned long	magicHeader;
+	unsigned short	bootVersion;
+	unsigned short	headerSize;		// also kernel image start
+	unsigned long	imageSize;		// NB! since 1.02 is the total image/partition size
+	unsigned long	bitFlags;
+	unsigned short	osType;
+	char			cmdLine[256];
+	unsigned long	kernelStart;	// used with Artecboot VFS / NULLFS
+	unsigned long	kernelSize;		// used with Artecboot VFS / NULLFS
+	unsigned long	initrdStart;	// used with Artecboot VFS / NULLFS
+	unsigned long	initrdSize;		// used with Artecboot VFS / NULLFS
+	char			kernelFile[100];	// valid only with FLAG_FILESYSTEM
+	char			initrdFile[100];	// valid only with FLAG_FILESYSTEM
+
+} ARTECBOOT_HEADER;
+
+#define ABOOT_FILE_KERNEL	"/kernel"
+#define ABOOT_FILE_INITRD	"/initrd"
+#define ABOOT_FILE_HEADER	"/header"

Added: trunk/filo/include/debug.h
===================================================================
--- trunk/filo/include/debug.h	                        (rev 0)
+++ trunk/filo/include/debug.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,42 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <lib.h>
+
+/* Defining DEBUG_THIS before including this file enables debug() macro
+ * for the file. DEBUG_ALL is for global control. */
+
+#if DEBUG_THIS || DEBUG_ALL
+#define DEBUG 1
+#else
+#undef DEBUG
+#endif
+
+#if DEBUG
+# define debug(...) \
+    printf(__VA_ARGS__)
+# define debug_hexdump hexdump
+#else
+# define debug(...) /* nothing */
+# define debug_hexdump(...) /* nothing */
+#endif
+
+#endif /* DEBUG_H */

Added: trunk/filo/include/elf.h
===================================================================
--- trunk/filo/include/elf.h	                        (rev 0)
+++ trunk/filo/include/elf.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,244 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef ELF_H
+#define ELF_H
+
+#define EI_NIDENT	16	/* Size of e_ident array. */
+
+/* Values for e_type. */
+#define ET_NONE		0	/* No file type */
+#define ET_REL		1	/* Relocatable file */
+#define ET_EXEC		2	/* Executable file */
+#define ET_DYN		3	/* Shared object file */
+#define ET_CORE		4	/* Core file */
+
+/* Values for e_machine (architecute). */
+#define EM_NONE		 0		/* No machine */
+#define EM_M32		 1		/* AT&T WE 32100 */
+#define EM_SPARC	 2		/* SUN SPARC */
+#define EM_386		 3		/* Intel 80386+ */
+#define EM_68K		 4		/* Motorola m68k family */
+#define EM_88K		 5		/* Motorola m88k family */
+#define EM_486		 6		/* Perhaps disused */
+#define EM_860		 7		/* Intel 80860 */
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_S370		 9		/* IBM System/370 */
+#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
+
+#define EM_PARISC	15		/* HPPA */
+#define EM_VPP500	17		/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
+#define EM_960		19		/* Intel 80960 */
+#define EM_PPC		20		/* PowerPC */
+#define EM_PPC64	21		/* PowerPC 64-bit */
+#define EM_S390		22		/* IBM S390 */
+
+#define EM_V800		36		/* NEC V800 series */
+#define EM_FR20		37		/* Fujitsu FR20 */
+#define EM_RH32		38		/* TRW RH-32 */
+#define EM_RCE		39		/* Motorola RCE */
+#define EM_ARM		40		/* ARM */
+#define EM_FAKE_ALPHA	41		/* Digital Alpha */
+#define EM_SH		42		/* Hitachi SH */
+#define EM_SPARCV9	43		/* SPARC v9 64-bit */
+#define EM_TRICORE	44		/* Siemens Tricore */
+#define EM_ARC		45		/* Argonaut RISC Core */
+#define EM_H8_300	46		/* Hitachi H8/300 */
+#define EM_H8_300H	47		/* Hitachi H8/300H */
+#define EM_H8S		48		/* Hitachi H8S */
+#define EM_H8_500	49		/* Hitachi H8/500 */
+#define EM_IA_64	50		/* Intel Merced */
+#define EM_MIPS_X	51		/* Stanford MIPS-X */
+#define EM_COLDFIRE	52		/* Motorola Coldfire */
+#define EM_68HC12	53		/* Motorola M68HC12 */
+#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP		55		/* Siemens PCP */
+#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
+#define EM_NDR1		57		/* Denso NDR1 microprocessor */
+#define EM_STARCORE	58		/* Motorola Start*Core processor */
+#define EM_ME16		59		/* Toyota ME16 processor */
+#define EM_ST100	60		/* STMicroelectronic ST100 processor */
+#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64	62		/* AMD x86-64 architecture */
+#define EM_PDSP		63		/* Sony DSP Processor */
+
+#define EM_FX66		66		/* Siemens FX66 microcontroller */
+#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
+#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
+#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
+#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
+#define EM_SVX		73		/* Silicon Graphics SVx */
+#define EM_AT19		74		/* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX		75		/* Digital VAX */
+#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
+#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY	81		/* Harvard University machine-independent object files */
+#define EM_PRISM	82		/* SiTera Prism */
+#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
+#define EM_FR30		84		/* Fujitsu FR30 */
+#define EM_D10V		85		/* Mitsubishi D10V */
+#define EM_D30V		86		/* Mitsubishi D30V */
+#define EM_V850		87		/* NEC v850 */
+#define EM_M32R		88		/* Mitsubishi M32R */
+#define EM_MN10300	89		/* Matsushita MN10300 */
+#define EM_MN10200	90		/* Matsushita MN10200 */
+#define EM_PJ		91		/* picoJava */
+#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
+#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
+#define EM_NUM		95
+
+/* Values for p_type. */
+#define PT_NULL		0	/* Unused entry. */
+#define PT_LOAD		1	/* Loadable segment. */
+#define PT_DYNAMIC	2	/* Dynamic linking information segment. */
+#define PT_INTERP	3	/* Pathname of interpreter. */
+#define PT_NOTE		4	/* Auxiliary information. */
+#define PT_SHLIB	5	/* Reserved (not used). */
+#define PT_PHDR		6	/* Location of program header itself. */
+
+/* Values for p_flags. */
+#define PF_X		0x1	/* Executable. */
+#define PF_W		0x2	/* Writable. */
+#define PF_R		0x4	/* Readable. */
+
+
+#define	ELF_PROGRAM_RETURNS_BIT	0x8000000	/* e_flags bit 31 */
+
+#define EI_MAG0		0
+#define ELFMAG0		0x7f
+
+#define EI_MAG1		1
+#define ELFMAG1		'E'
+
+#define EI_MAG2		2
+#define ELFMAG2		'L'
+
+#define EI_MAG3		3
+#define ELFMAG3		'F'
+
+#define ELFMAG		"\177ELF"
+
+#define EI_CLASS	4	/* File class byte index */
+#define ELFCLASSNONE	0	/* Invalid class */
+#define ELFCLASS32	1	/* 32-bit objects */
+#define ELFCLASS64	2	/* 64-bit objects */
+
+#define EI_DATA		5	/* Data encodeing byte index */
+#define ELFDATANONE	0	/* Invalid data encoding */
+#define ELFDATA2LSB	1	/* 2's complement little endian */
+#define ELFDATA2MSB	2	/* 2's complement big endian */
+
+#define EI_VERSION	6	/* File version byte index */
+				/* Value must be EV_CURRENT */
+
+#define EV_NONE		0	/* Invalid ELF Version */
+#define EV_CURRENT	1	/* Current version */
+
+#define ELF32_PHDR_SIZE (8*4)	/* Size of an elf program header */
+
+#ifndef __ASSEMBLY__
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef uint32_t	Elf32_Addr;
+typedef uint16_t	Elf32_Half;
+typedef uint32_t	Elf32_Off;
+typedef int32_t		Elf32_Sword;
+typedef uint32_t	Elf32_Word;
+typedef uint32_t	Elf32_Size;
+
+typedef uint64_t	Elf64_Addr;
+typedef uint16_t	Elf64_Half;
+typedef uint64_t	Elf64_Off;
+typedef int32_t		Elf64_Sword;
+typedef uint32_t	Elf64_Word;
+typedef uint64_t	Elf64_Size;
+
+/*
+ * ELF header.
+ */
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf32_Half	e_type;		/* File type. */
+	Elf32_Half	e_machine;	/* Machine architecture. */
+	Elf32_Word	e_version;	/* ELF format version. */
+	Elf32_Addr	e_entry;	/* Entry point. */
+	Elf32_Off	e_phoff;	/* Program header file offset. */
+	Elf32_Off	e_shoff;	/* Section header file offset. */
+	Elf32_Word	e_flags;	/* Architecture-specific flags. */
+	Elf32_Half	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf32_Half	e_phentsize;	/* Size of program header entry. */
+	Elf32_Half	e_phnum;	/* Number of program header entries. */
+	Elf32_Half	e_shentsize;	/* Size of section header entry. */
+	Elf32_Half	e_shnum;	/* Number of section header entries. */
+	Elf32_Half	e_shstrndx;	/* Section name strings section. */
+} Elf32_Ehdr;
+
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf64_Half	e_type;		/* File type. */
+	Elf64_Half	e_machine;	/* Machine architecture. */
+	Elf64_Word	e_version;	/* ELF format version. */
+	Elf64_Addr	e_entry;	/* Entry point. */
+	Elf64_Off	e_phoff;	/* Program header file offset. */
+	Elf64_Off	e_shoff;	/* Section header file offset. */
+	Elf64_Word	e_flags;	/* Architecture-specific flags. */
+	Elf64_Half	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf64_Half	e_phentsize;	/* Size of program header entry. */
+	Elf64_Half	e_phnum;	/* Number of program header entries. */
+	Elf64_Half	e_shentsize;	/* Size of section header entry. */
+	Elf64_Half	e_shnum;	/* Number of section header entries. */
+	Elf64_Half	e_shstrndx;	/* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Program header.
+ */
+typedef struct {
+	Elf32_Word	p_type;		/* Entry type. */
+	Elf32_Off	p_offset;	/* File offset of contents. */
+	Elf32_Addr	p_vaddr;	/* Virtual address (not used). */
+	Elf32_Addr	p_paddr;	/* Physical address. */
+	Elf32_Size	p_filesz;	/* Size of contents in file. */
+	Elf32_Size	p_memsz;	/* Size of contents in memory. */
+	Elf32_Word	p_flags;	/* Access permission flags. */
+	Elf32_Size	p_align;	/* Alignment in memory and file. */
+} Elf32_Phdr;
+
+typedef struct {
+	Elf64_Word	p_type;		/* Entry type. */
+	Elf64_Word	p_flags;	/* Access permission flags. */
+	Elf64_Off	p_offset;	/* File offset of contents. */
+	Elf64_Addr	p_vaddr;	/* Virtual address (not used). */
+	Elf64_Addr	p_paddr;	/* Physical address. */
+	Elf64_Size	p_filesz;	/* Size of contents in file. */
+	Elf64_Size	p_memsz;	/* Size of contents in memory. */
+	Elf64_Size	p_align;	/* Alignment in memory and file. */
+} Elf64_Phdr;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ELF_H */

Added: trunk/filo/include/elf_boot.h
===================================================================
--- trunk/filo/include/elf_boot.h	                        (rev 0)
+++ trunk/filo/include/elf_boot.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,122 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef ELF_BOOT_H 
+#define ELF_BOOT_H 
+
+
+/* This defines the structure of a table of parameters useful for ELF
+ * bootable images.  These parameters are all passed and generated
+ * by the bootloader to the booted image.  For simplicity and
+ * consistency the Elf Note format is reused.
+ *
+ * All of the information must be Position Independent Data.
+ * That is it must be safe to relocate the whole ELF boot parameter
+ * block without changing the meaning or correctnes of the data.
+ * Additionally it must be safe to permute the order of the ELF notes
+ * to any possible permutation without changing the meaning or correctness
+ * of the data.
+ *
+ */
+
+#define ELF_BHDR_MAGIC		0x0E1FB007
+
+#ifndef __ASSEMBLY__
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+
+/*
+ * Elf boot notes...
+ */
+
+typedef struct Elf_Bhdr
+{
+	Elf_Word b_signature; /* "0x0E1FB007" */
+	Elf_Word b_size;
+	Elf_Half b_checksum;
+	Elf_Half b_records;
+} Elf_Bhdr;
+
+/* 
+ * ELF Notes.
+ */
+
+typedef struct Elf_Nhdr
+{
+	Elf_Word n_namesz;		/* Length of the note's name.  */
+	Elf_Word n_descsz;		/* Length of the note's descriptor.  */
+	Elf_Word n_type;		/* Type of the note.  */
+} Elf_Nhdr;
+
+#endif /* __ASSEMBLY__ */
+
+/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
+#define ELF_NOTE_BOOT		"ELFBoot"
+
+#define EIN_PROGRAM_NAME	0x00000001
+/* The program in this ELF file */
+#define EIN_PROGRAM_VERSION	0x00000002
+/* The version of the program in this ELF file */
+#define EIN_PROGRAM_CHECKSUM	0x00000003
+/* ip style checksum of the memory image. */
+
+
+/* Linux image notes for booting... The name for all of these is Linux */
+
+#define LIN_COMMAND_LINE	0x00000001
+/* The command line to pass to the loaded kernel. */
+#define LIN_ROOT_DEV		0x00000002
+/* The root dev to pass to the loaded kernel. */
+#define LIN_RAMDISK_FLAGS	0x00000003
+/* Various old ramdisk flags */
+#define LIN_INITRD_START	0x00000004
+/* Start of the ramdisk in bytes */
+#define LIN_INITRD_SIZE		0x00000005
+/* Size of the ramdisk in bytes */
+
+/* Notes that are passed to a loaded image */
+/* For the standard elf boot notes n_namesz must be zero */
+#define EBN_FIRMWARE_TYPE	0x00000001
+/* ASCIZ name of the platform firmware. */
+#define EBN_BOOTLOADER_NAME	0x00000002
+/* This specifies just the ASCIZ name of the bootloader */
+#define EBN_BOOTLOADER_VERSION	0x00000003
+/* This specifies the version of the bootloader as an ASCIZ string */
+#define EBN_COMMAND_LINE	0x00000004
+/* This specifies a command line that can be set by user interaction,
+ * and is provided as a free form ASCIZ string to the loaded image.
+ */
+#define EBN_NOP			0x00000005
+/* A note nop note has no meaning, useful for inserting explicit padding */
+#define EBN_LOADED_IMAGE	0x00000006
+/* An ASCIZ string naming the loaded image */
+
+
+/* Etherboot specific notes */
+#define EB_PARAM_NOTE		"Etherboot"
+#define EB_IA64_SYSTAB		0x00000001
+#define EB_IA64_MEMMAP		0x00000002
+#define EB_IA64_FPSWA		0x00000003
+#define EB_IA64_CONINFO		0x00000004
+#define EB_BOOTP_DATA		0x00000005
+#define EB_HEADER		0x00000006
+#define EB_IA64_IMAGE_HANDLE	0x00000007
+#define EB_I386_MEMMAP		0x00000008
+
+
+#endif /* ELF_BOOT_H */

Added: trunk/filo/include/fs.h
===================================================================
--- trunk/filo/include/fs.h	                        (rev 0)
+++ trunk/filo/include/fs.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,81 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef FS_H
+#define FS_H
+
+#include <libpayload.h>
+#include <arch/byteorder.h>
+typedef uint64_t sector_t;
+
+#define DEV_SECTOR_BITS		9
+#define DEV_SECTOR_SIZE		(1<<9)
+#define DEV_SECTOR_MASK		(DEV_SECTOR_SIZE-1)
+
+#ifdef CONFIG_IDE_DISK
+int ide_probe(int drive);
+int ide_read(int drive, sector_t sector, void *buffer);
+#endif
+
+#ifdef CONFIG_USB_DISK
+int usb_probe(int drive);
+int usb_read(int drive, sector_t sector, void *buffer);
+#endif
+
+#ifdef CONFIG_USB_NEW_DISK
+int usb_new_probe(int drive);
+int usb_new_read(int drive, sector_t sector, void *buffer);
+#endif
+
+#ifdef CONFIG_FLASH_DISK
+int flash_probe(int drive);
+int flash_read(int drive, sector_t sector, void *buffer);
+int NAND_close(void);
+#endif
+
+#define DISK_IDE 1
+#define DISK_MEM 2
+#define DISK_USB 3
+#define DISK_FLASH 4
+#define DISK_NEW_USB 5
+
+int devopen(const char *name, int *reopen);
+void devclose(void);
+int devread(unsigned long sector, unsigned long byte_offset,
+	unsigned long byte_len, void *buf);
+void dev_set_partition(unsigned long start, unsigned long size);
+void dev_get_partition(unsigned long *start, unsigned long *size);
+
+int file_open(const char *filename);
+int file_read(void *buf, unsigned long len);
+int file_seek(unsigned long offset);
+unsigned long file_size(void);
+void file_set_size(unsigned long size);
+void file_close(void);
+
+#define PARTITION_UNKNOWN	0xbad6a7
+
+#ifdef CONFIG_ELTORITO
+int open_eltorito_image(int part, unsigned long *start, unsigned long *length);
+#else
+# define open_eltorito_image(x,y,z) PARTITION_UNKNOWN
+#endif
+
+extern int using_devsize;
+
+#endif /* FS_H */

Added: trunk/filo/include/grub/config.h
===================================================================
--- trunk/filo/include/grub/config.h	                        (rev 0)
+++ trunk/filo/include/grub/config.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,107 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if an absolute indirect call/jump must NOT be prefixed with `*' */
+/* #undef ABSOLUTE_WITHOUT_ASTERISK */
+
+/* Define it to \"addr32\" or \"addr32;\" to make GAS happy */
+#define ADDR32 addr32
+
+/* Define if you don't want to pass the mem= option to Linux */
+#define AUTO_LINUX_MEM_OPT 1
+
+/* Define it to \"data32\" or \"data32;\" to make GAS happy */
+#define DATA32 data32
+
+/* Define if C symbols get an underscore after compilation */
+/* #undef HAVE_ASM_USCORE */
+
+/* Define to 1 if you have the <curses.h> header file. */
+#define HAVE_CURSES_H 1
+
+/* Define if edata is defined */
+#define HAVE_EDATA_SYMBOL 1
+
+/* Define if end is defined */
+#define HAVE_END_SYMBOL 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have a curses library */
+#define HAVE_LIBCURSES 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <ncurses/curses.h> header file. */
+/* #undef HAVE_NCURSES_CURSES_H */
+
+/* Define to 1 if you have the <ncurses.h> header file. */
+#define HAVE_NCURSES_H 1
+
+/* Define if opendisk() in -lutil can be used */
+/* #undef HAVE_OPENDISK */
+
+/* Define if start is defined */
+/* #undef HAVE_START_SYMBOL */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if _edata is defined */
+#define HAVE_USCORE_EDATA_SYMBOL 1
+
+/* Define if end is defined */
+#define HAVE_USCORE_END_SYMBOL 1
+
+/* Define if _start is defined */
+#define HAVE_USCORE_START_SYMBOL 1
+
+/* Define if __bss_start is defined */
+#define HAVE_USCORE_USCORE_BSS_START_SYMBOL 1
+
+/* Name of package */
+#define PACKAGE "grub"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "bug-grub at gnu.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "GRUB"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "GRUB 0.97"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "grub"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.97"
+
+/* Define if there is user specified preset menu string */
+/* #undef PRESET_MENU_STRING */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.97"

Added: trunk/filo/include/grub/mb_header.h
===================================================================
--- trunk/filo/include/grub/mb_header.h	                        (rev 0)
+++ trunk/filo/include/grub/mb_header.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,90 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000   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.
+ */
+
+/*
+ *  MultiBoot Header description
+ */
+
+struct multiboot_header
+{
+  /* Must be MULTIBOOT_MAGIC - see below.  */
+  unsigned magic;
+  
+  /* Feature flags - see below.  */
+  unsigned flags;
+  
+  /*
+   * Checksum
+   *
+   * The above fields plus this one must equal 0 mod 2^32.
+   */
+  unsigned checksum;
+  
+  /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set.  */
+  unsigned header_addr;
+  unsigned load_addr;
+  unsigned load_end_addr;
+  unsigned bss_end_addr;
+  unsigned entry_addr;
+
+  /* These are only valid if MULTIBOOT_VIDEO_MODE is set.  */
+  unsigned mode_type;
+  unsigned width;
+  unsigned height;
+  unsigned depth;
+};
+
+/*
+ * The entire multiboot_header must be contained
+ * within the first MULTIBOOT_SEARCH bytes of the kernel image.
+ */
+#define MULTIBOOT_SEARCH		8192
+#define MULTIBOOT_FOUND(addr, len) \
+  (! ((addr) & 0x3) \
+   && (len) >= 12 \
+   && *((int *) (addr)) == MULTIBOOT_MAGIC \
+   && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \
+	 + *((unsigned *) (addr + 8))) \
+   && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \
+   && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48))
+
+/* Magic value identifying the multiboot_header.  */
+#define MULTIBOOT_MAGIC			0x1BADB002
+
+/*
+ * Features flags for 'flags'.
+ * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set
+ * and it doesn't understand it, it must fail.
+ */
+#define MULTIBOOT_MUSTKNOW		0x0000FFFF
+
+/* currently unsupported flags...  this is a kind of version number.  */
+#define MULTIBOOT_UNSUPPORTED		0x0000FFF8
+
+/* Align all boot modules on i386 page (4KB) boundaries.  */
+#define MULTIBOOT_PAGE_ALIGN		0x00000001
+
+/* Must pass memory information to OS.  */
+#define MULTIBOOT_MEMORY_INFO		0x00000002
+
+/* Must pass video information to OS.  */
+#define MULTIBOOT_VIDEO_MODE		0x00000004
+
+/* This flag indicates the use of the address fields in the header.  */
+#define MULTIBOOT_AOUT_KLUDGE		0x00010000

Added: trunk/filo/include/grub/mb_info.h
===================================================================
--- trunk/filo/include/grub/mb_info.h	                        (rev 0)
+++ trunk/filo/include/grub/mb_info.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,217 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2003  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.
+ */
+
+/*
+ *  The structure type "mod_list" is used by the "multiboot_info" structure.
+ */
+
+struct mod_list
+{
+  /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
+  unsigned long mod_start;
+  unsigned long mod_end;
+  
+  /* Module command line */
+  unsigned long cmdline;
+  
+  /* padding to take it to 16 bytes (must be zero) */
+  unsigned long pad;
+};
+
+
+/*
+ *  INT-15, AX=E820 style "AddressRangeDescriptor"
+ *  ...with a "size" parameter on the front which is the structure size - 4,
+ *  pointing to the next one, up until the full buffer length of the memory
+ *  map has been reached.
+ */
+
+struct AddrRangeDesc
+{
+  unsigned long size;
+  unsigned long long BaseAddr;
+  unsigned long long Length;
+  unsigned long Type;
+  
+  /* unspecified optional padding... */
+} __attribute__ ((packed));
+
+/* usable memory "Type", all others are reserved.  */
+#define MB_ARD_MEMORY		1
+
+
+/* Drive Info structure.  */
+struct drive_info
+{
+  /* The size of this structure.  */
+  unsigned long size;
+
+  /* The BIOS drive number.  */
+  unsigned char drive_number;
+
+  /* The access mode (see below).  */
+  unsigned char drive_mode;
+
+  /* The BIOS geometry.  */
+  unsigned short drive_cylinders;
+  unsigned char drive_heads;
+  unsigned char drive_sectors;
+
+  /* The array of I/O ports used for the drive.  */
+  unsigned short drive_ports[0];
+};
+
+/* Drive Mode.  */
+#define MB_DI_CHS_MODE		0
+#define MB_DI_LBA_MODE		1
+
+
+/* APM BIOS info.  */
+struct apm_info
+{
+  unsigned short version;
+  unsigned short cseg;
+  unsigned long offset;
+  unsigned short cseg_16;
+  unsigned short dseg_16;
+  unsigned short cseg_len;
+  unsigned short cseg_16_len;
+  unsigned short dseg_16_len;
+};
+
+
+/*
+ *  MultiBoot Info description
+ *
+ *  This is the struct passed to the boot image.  This is done by placing
+ *  its address in the EAX register.
+ */
+
+struct multiboot_info
+{
+  /* MultiBoot info version number */
+  unsigned long flags;
+  
+  /* Available memory from BIOS */
+  unsigned long mem_lower;
+  unsigned long mem_upper;
+  
+  /* "root" partition */
+  unsigned long boot_device;
+  
+  /* Kernel command line */
+  unsigned long cmdline;
+  
+  /* Boot-Module list */
+  unsigned long mods_count;
+  unsigned long mods_addr;
+  
+  union
+  {
+    struct
+    {
+      /* (a.out) Kernel symbol table info */
+      unsigned long tabsize;
+      unsigned long strsize;
+      unsigned long addr;
+      unsigned long pad;
+    }
+    a;
+    
+    struct
+    {
+      /* (ELF) Kernel section header table */
+      unsigned long num;
+      unsigned long size;
+      unsigned long addr;
+      unsigned long shndx;
+    }
+    e;
+  }
+  syms;
+  
+  /* Memory Mapping buffer */
+  unsigned long mmap_length;
+  unsigned long mmap_addr;
+  
+  /* Drive Info buffer */
+  unsigned long drives_length;
+  unsigned long drives_addr;
+  
+  /* ROM configuration table */
+  unsigned long config_table;
+  
+  /* Boot Loader Name */
+  unsigned long boot_loader_name;
+
+  /* APM table */
+  unsigned long apm_table;
+
+  /* Video */
+  unsigned long vbe_control_info;
+  unsigned long vbe_mode_info;
+  unsigned short vbe_mode;
+  unsigned short vbe_interface_seg;
+  unsigned short vbe_interface_off;
+  unsigned short vbe_interface_len;
+};
+
+/*
+ *  Flags to be set in the 'flags' parameter above
+ */
+
+/* is there basic lower/upper memory information? */
+#define MB_INFO_MEMORY			0x00000001
+/* is there a boot device set? */
+#define MB_INFO_BOOTDEV			0x00000002
+/* is the command-line defined? */
+#define MB_INFO_CMDLINE			0x00000004
+/* are there modules to do something with? */
+#define MB_INFO_MODS			0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MB_INFO_AOUT_SYMS		0x00000010
+/* is there an ELF section header table? */
+#define MB_INFO_ELF_SHDR		0x00000020
+
+/* is there a full memory map? */
+#define MB_INFO_MEM_MAP			0x00000040
+
+/* Is there drive info?  */
+#define MB_INFO_DRIVE_INFO		0x00000080
+
+/* Is there a config table?  */
+#define MB_INFO_CONFIG_TABLE		0x00000100
+
+/* Is there a boot loader name?  */
+#define MB_INFO_BOOT_LOADER_NAME	0x00000200
+
+/* Is there a APM table?  */
+#define MB_INFO_APM_TABLE		0x00000400
+
+/* Is there video information?  */
+#define MB_INFO_VIDEO_INFO		0x00000800
+
+/*
+ *  The following value must be present in the EAX register.
+ */
+
+#define MULTIBOOT_VALID			0x2BADB002

Added: trunk/filo/include/grub/md5.h
===================================================================
--- trunk/filo/include/grub/md5.h	                        (rev 0)
+++ trunk/filo/include/grub/md5.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,30 @@
+/* md5.h - an implementation of the MD5 algorithm and MD5 crypt */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  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.
+ */
+
+/* If CHECK is true, check a password for correctness. Returns 0
+   if password was correct, and a value != 0 for error, similarly
+   to strcmp.
+   If CHECK is false, crypt KEY and save the result in CRYPTED.
+   CRYPTED must have a salt.  */
+extern int md5_password (const char *key, char *crypted, int check);
+
+/* For convenience.  */
+#define check_md5_password(key,crypted)	md5_password((key), (crypted), 1)
+#define make_md5_password(key,crypted)	md5_password((key), (crypted), 0)

Added: trunk/filo/include/grub/serial.h
===================================================================
--- trunk/filo/include/grub/serial.h	                        (rev 0)
+++ trunk/filo/include/grub/serial.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,93 @@
+/* serial.h - serial device interface */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2002  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.
+ */
+
+#ifndef GRUB_SERIAL_HEADER
+#define GRUB_SERIAL_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	0xC7
+
+/* Turn on DTR, RTS, and OUT2.  */
+#define UART_ENABLE_MODEM	0x0B
+
+
+/* Function prototypes.  */
+
+/* Fetch a key.  */
+int serial_hw_fetch (void);
+
+/* Put a character.  */
+void serial_hw_put (int c);
+
+/* Insert a delay.  */
+void serial_hw_delay (void);
+
+/* Return the port number for the UNITth serial device.  */
+unsigned short serial_hw_get_port (int unit);
+
+/* Initialize a serial device.  */
+int serial_hw_init (unsigned short port, unsigned int speed,
+		    int word_len, int parity, int stop_bit_len);
+
+#ifdef GRUB_UTIL
+/* Set the file name of a serial device (or a pty device). This is a
+   function specific to the grub shell.  */
+void serial_set_device (const char *device);
+#endif /* GRUB_UTIL */
+
+#endif /* ! GRUB_SERIAL_HEADER */

Added: trunk/filo/include/grub/shared.h
===================================================================
--- trunk/filo/include/grub/shared.h	                        (rev 0)
+++ trunk/filo/include/grub/shared.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1026 @@
+/* shared.h - definitions used in all GRUB-specific code */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004  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.
+ */
+
+/*
+ *  Generic defines to use anywhere
+ */
+
+#ifndef GRUB_SHARED_HEADER
+#define GRUB_SHARED_HEADER	1
+
+#include <grub/config.h>
+
+/* Add an underscore to a C symbol in assembler code if needed. */
+#ifdef HAVE_ASM_USCORE
+# define EXT_C(sym) _ ## sym
+#else
+# define EXT_C(sym) sym
+#endif
+
+/* Maybe redirect memory requests through grub_scratch_mem. */
+#ifdef GRUB_UTIL
+extern char *grub_scratch_mem;
+# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
+# define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
+#else
+# define RAW_ADDR(x) (x)
+# define RAW_SEG(x) (x)
+#endif
+
+/*
+ *  Integer sizes
+ */
+
+#define MAXINT     0x7FFFFFFF
+
+/* Maximum command line size. Before you blindly increase this value,
+   see the comment in char_io.c (get_cmdline).  */
+#define MAX_CMDLINE 1600
+#define NEW_HEAPSIZE 1500
+
+/* 512-byte scratch area */
+#define SCRATCHADDR  RAW_ADDR (0x77e00)
+#define SCRATCHSEG   RAW_SEG (0x77e0)
+
+/*
+ *  This is the location of the raw device buffer.  It is 31.5K
+ *  in size.
+ */
+
+#define BUFFERLEN   0x7e00
+#define BUFFERADDR  RAW_ADDR (0x70000)
+#define BUFFERSEG   RAW_SEG (0x7000)
+
+#define BOOT_PART_TABLE	RAW_ADDR (0x07be)
+
+/*
+ *  BIOS disk defines
+ */
+#define BIOSDISK_READ			0x0
+#define BIOSDISK_WRITE			0x1
+#define BIOSDISK_ERROR_GEOMETRY		0x100
+#define BIOSDISK_FLAG_LBA_EXTENSION	0x1
+#define BIOSDISK_FLAG_CDROM		0x2
+
+/*
+ *  This is the filesystem (not raw device) buffer.
+ *  It is 32K in size, do not overrun!
+ */
+
+#define FSYS_BUFLEN  0x8000
+#define FSYS_BUF RAW_ADDR (0x68000)
+
+/* Command-line buffer for Multiboot kernels and modules. This area
+   includes the area into which Stage 1.5 and Stage 1 are loaded, but
+   that's no problem.  */
+#define MB_CMDLINE_BUF		RAW_ADDR (0x2000)
+#define MB_CMDLINE_BUFLEN	0x6000
+
+/* The buffer for the password.  */
+#define PASSWORD_BUF		RAW_ADDR (0x78000)
+#define PASSWORD_BUFLEN		0x200
+
+/* THe buffer for the filename of "/boot/grub/default".  */
+#define DEFAULT_FILE_BUF	(PASSWORD_BUF + PASSWORD_BUFLEN)
+#define DEFAULT_FILE_BUFLEN	0x60
+
+/* The buffer for the command-line.  */
+#define CMDLINE_BUF		(DEFAULT_FILE_BUF + DEFAULT_FILE_BUFLEN)
+#define CMDLINE_BUFLEN		MAX_CMDLINE
+
+/* The kill buffer for the command-line.  */
+#define KILL_BUF		(CMDLINE_BUF + CMDLINE_BUFLEN)
+#define KILL_BUFLEN		MAX_CMDLINE
+
+/* The history buffer for the command-line.  */
+#define HISTORY_BUF		(KILL_BUF + KILL_BUFLEN)
+#define HISTORY_SIZE		5
+#define HISTORY_BUFLEN		(MAX_CMDLINE * HISTORY_SIZE)
+
+/* The buffer for the completion.  */
+#define COMPLETION_BUF		(HISTORY_BUF + HISTORY_BUFLEN)
+#define COMPLETION_BUFLEN	MAX_CMDLINE
+
+/* The buffer for the unique string.  */
+#define UNIQUE_BUF		(COMPLETION_BUF + COMPLETION_BUFLEN)
+#define UNIQUE_BUFLEN		MAX_CMDLINE
+
+/* The buffer for the menu entries.  */
+#define MENU_BUF		(UNIQUE_BUF + UNIQUE_BUFLEN)
+#define MENU_BUFLEN		(0x8000 + PASSWORD_BUF - MENU_BUF)
+
+/* The size of the drive map.  */
+#define DRIVE_MAP_SIZE		8
+
+/* The size of the key map.  */
+#define KEY_MAP_SIZE		128
+
+/* The size of the io map.  */
+#define IO_MAP_SIZE		128
+
+/*
+ *  Linux setup parameters
+ */
+
+#define LINUX_MAGIC_SIGNATURE		0x53726448	/* "HdrS" */
+#define LINUX_DEFAULT_SETUP_SECTS	4
+#define LINUX_FLAG_CAN_USE_HEAP		0x80
+#define LINUX_INITRD_MAX_ADDRESS	0x38000000
+#define LINUX_MAX_SETUP_SECTS		64
+#define LINUX_BOOT_LOADER_TYPE		0x71
+#define LINUX_HEAP_END_OFFSET		(0x9000 - 0x200)
+
+#define LINUX_BZIMAGE_ADDR		RAW_ADDR (0x100000)
+#define LINUX_ZIMAGE_ADDR		RAW_ADDR (0x10000)
+#define LINUX_OLD_REAL_MODE_ADDR	RAW_ADDR (0x90000)
+#define LINUX_SETUP_STACK		0x9000
+
+#define LINUX_FLAG_BIG_KERNEL		0x1
+
+/* Linux's video mode selection support. Actually I hate it!  */
+#define LINUX_VID_MODE_NORMAL		0xFFFF
+#define LINUX_VID_MODE_EXTENDED		0xFFFE
+#define LINUX_VID_MODE_ASK		0xFFFD
+
+#define LINUX_CL_OFFSET			0x9000
+#define LINUX_CL_END_OFFSET		0x90FF
+#define LINUX_SETUP_MOVE_SIZE		0x9100
+#define LINUX_CL_MAGIC			0xA33F
+
+/*
+ *  General disk stuff
+ */
+
+#define SECTOR_SIZE		0x200
+#define SECTOR_BITS		9
+#define BIOS_FLAG_FIXED_DISK	0x80
+
+#define BOOTSEC_LOCATION		RAW_ADDR (0x7C00)
+#define BOOTSEC_SIGNATURE		0xAA55
+#define BOOTSEC_BPB_OFFSET		0x3
+#define BOOTSEC_BPB_LENGTH		0x3B
+#define BOOTSEC_BPB_SYSTEM_ID		0x3
+#define BOOTSEC_BPB_HIDDEN_SECTORS	0x1C
+#define BOOTSEC_PART_OFFSET		0x1BE
+#define BOOTSEC_PART_LENGTH		0x40
+#define BOOTSEC_SIG_OFFSET		0x1FE
+#define BOOTSEC_LISTSIZE		8
+
+/* Not bad, perhaps.  */
+#define NETWORK_DRIVE	0x20
+
+/*
+ *  GRUB specific information
+ *    (in LSB order)
+ */
+
+#define GRUB_INVALID_DRIVE      0xFF
+
+// #include <stage1.h>
+
+#define STAGE2_VER_MAJ_OFFS	0x6
+#define STAGE2_INSTALLPART	0x8
+#define STAGE2_SAVED_ENTRYNO	0xc
+#define STAGE2_STAGE2_ID	0x10
+#define STAGE2_FORCE_LBA	0x11
+#define STAGE2_VER_STR_OFFS	0x12
+
+/* Stage 2 identifiers */
+#define STAGE2_ID_STAGE2		0
+#define STAGE2_ID_FFS_STAGE1_5		1
+#define STAGE2_ID_E2FS_STAGE1_5		2
+#define STAGE2_ID_FAT_STAGE1_5		3
+#define STAGE2_ID_MINIX_STAGE1_5	4
+#define STAGE2_ID_REISERFS_STAGE1_5	5
+#define STAGE2_ID_VSTAFS_STAGE1_5	6
+#define STAGE2_ID_JFS_STAGE1_5		7
+#define STAGE2_ID_XFS_STAGE1_5		8
+#define STAGE2_ID_ISO9660_STAGE1_5	9
+#define STAGE2_ID_UFS2_STAGE1_5		10
+
+#ifndef STAGE1_5
+# define STAGE2_ID	STAGE2_ID_STAGE2
+#else
+# if defined(FSYS_FFS)
+#  define STAGE2_ID	STAGE2_ID_FFS_STAGE1_5
+# elif defined(FSYS_EXT2FS)
+#  define STAGE2_ID	STAGE2_ID_E2FS_STAGE1_5
+# elif defined(FSYS_FAT)
+#  define STAGE2_ID	STAGE2_ID_FAT_STAGE1_5
+# elif defined(FSYS_MINIX)
+#  define STAGE2_ID	STAGE2_ID_MINIX_STAGE1_5
+# elif defined(FSYS_REISERFS)
+#  define STAGE2_ID	STAGE2_ID_REISERFS_STAGE1_5
+# elif defined(FSYS_VSTAFS)
+#  define STAGE2_ID	STAGE2_ID_VSTAFS_STAGE1_5
+# elif defined(FSYS_JFS)
+#  define STAGE2_ID	STAGE2_ID_JFS_STAGE1_5
+# elif defined(FSYS_XFS)
+#  define STAGE2_ID	STAGE2_ID_XFS_STAGE1_5
+# elif defined(FSYS_ISO9660)
+#  define STAGE2_ID	STAGE2_ID_ISO9660_STAGE1_5
+# elif defined(FSYS_UFS2)
+#  define STAGE2_ID	STAGE2_ID_UFS2_STAGE1_5
+# else
+#  error "unknown Stage 2"
+# endif
+#endif
+
+/*
+ *  defines for use when switching between real and protected mode
+ */
+
+#define CR0_PE_ON	0x1
+#define CR0_PE_OFF	0xfffffffe
+#define PROT_MODE_CSEG	0x8
+#define PROT_MODE_DSEG  0x10
+#define PSEUDO_RM_CSEG	0x18
+#define PSEUDO_RM_DSEG	0x20
+#define STACKOFF	(0x2000 - 0x10)
+#define PROTSTACKINIT   (FSYS_BUF - 0x10)
+
+
+/*
+ * Assembly code defines
+ *
+ * "EXT_C" is assumed to be defined in the Makefile by the configure
+ *   command.
+ */
+
+#define ENTRY(x) .globl EXT_C(x) ; EXT_C(x):
+#define VARIABLE(x) ENTRY(x)
+
+
+#define K_RDWR  	0x60	/* keyboard data & cmds (read/write) */
+#define K_STATUS	0x64	/* keyboard status */
+#define K_CMD		0x64	/* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 	0x01	/* output buffer full */
+#define K_IBUF_FUL 	0x02	/* input buffer full */
+
+#define KC_CMD_WIN	0xd0	/* read  output port */
+#define KC_CMD_WOUT	0xd1	/* write output port */
+#define KB_OUTPUT_MASK  0xdd	/* enable output buffer full interrupt
+				   enable data line
+				   enable clock line */
+#define KB_A20_ENABLE   0x02
+
+/* Codes for getchar. */
+#define ASCII_CHAR(x)   ((x) & 0xFF)
+#if !defined(GRUB_UTIL) || !defined(HAVE_LIBCURSES)
+# define KEY_LEFT        0x4B00
+# define KEY_RIGHT       0x4D00
+# define KEY_UP          0x4800
+# define KEY_DOWN        0x5000
+# define KEY_IC          0x5200	/* insert char */
+# define KEY_DC          0x5300	/* delete char */
+# define KEY_BACKSPACE   0x0008
+# define KEY_HOME        0x4700
+# define KEY_END         0x4F00
+# define KEY_NPAGE       0x5100
+# define KEY_PPAGE       0x4900
+# define A_NORMAL        0x7
+# define A_REVERSE       0x70
+#elif defined(HAVE_NCURSES_CURSES_H)
+# include <ncurses/curses.h>
+#elif defined(HAVE_NCURSES_H)
+# include <ncurses.h>
+#elif defined(HAVE_CURSES_H)
+# include <curses.h>
+#endif
+
+/* In old BSD curses, A_NORMAL and A_REVERSE are not defined, so we
+   define them here if they are undefined.  */
+#ifndef A_NORMAL
+# define A_NORMAL	0
+#endif /* ! A_NORMAL */
+#ifndef A_REVERSE
+# ifdef A_STANDOUT
+#  define A_REVERSE	A_STANDOUT
+# else /* ! A_STANDOUT */
+#  define A_REVERSE	0
+# endif /* ! A_STANDOUT */
+#endif /* ! A_REVERSE */
+
+/* Define ACS_* ourselves, since the definitions are not consistent among
+   various curses implementations.  */
+#undef ACS_ULCORNER
+#undef ACS_URCORNER
+#undef ACS_LLCORNER
+#undef ACS_LRCORNER
+#undef ACS_HLINE
+#undef ACS_VLINE
+#undef ACS_LARROW
+#undef ACS_RARROW
+#undef ACS_UARROW
+#undef ACS_DARROW
+
+#define ACS_ULCORNER	'+'
+#define ACS_URCORNER	'+'
+#define ACS_LLCORNER	'+'
+#define ACS_LRCORNER	'+'
+#define ACS_HLINE	'-'
+#define ACS_VLINE	'|'
+#define ACS_LARROW	'<'
+#define ACS_RARROW	'>'
+#define ACS_UARROW	'^'
+#define ACS_DARROW	'v'
+
+/* Special graphics characters for IBM displays. */
+#define DISP_UL		218
+#define DISP_UR		191
+#define DISP_LL		192
+#define DISP_LR		217
+#define DISP_HORIZ	196
+#define DISP_VERT	179
+#define DISP_LEFT	0x1b
+#define DISP_RIGHT	0x1a
+#define DISP_UP		0x18
+#define DISP_DOWN	0x19
+
+/* Remap some libc-API-compatible function names so that we prevent
+   circularararity. */
+#ifndef WITHOUT_LIBC_STUBS
+//#define memmove grub_memmove
+//#define memcpy grub_memmove	/* we don't need a separate memcpy */
+//#define memset grub_memset
+//#define isspace grub_isspace
+#define printf grub_printf
+//#define sprintf grub_sprintf
+#undef putchar
+#define putchar grub_putchar
+//#define strncat grub_strncat
+//#define strstr grub_strstr
+//#define memcmp grub_memcmp
+//#define strcmp grub_strcmp
+//#define tolower grub_tolower
+//#define strlen grub_strlen
+//#define strcpy grub_strcpy
+
+/* Instead, for FILO we map the grub_ functions to 
+ * "normal" functions:
+ */
+ 
+#define grub_isspace isspace
+#define grub_memcmp memcmp
+#define grub_memmove memmove
+#define grub_memset memset
+#define grub_strcpy strcpy
+#define grub_strstr strstr
+#define grub_strcmp strcmp
+#define grub_strlen strlen
+#define grub_strncat strncat
+#define grub_sprintf sprintf
+
+#define grub_open file_open
+#define grub_read file_read
+#define grub_seek file_seek
+#define grub_close file_close
+#endif /* WITHOUT_LIBC_STUBS */
+
+#ifndef ASM_FILE
+/*
+ *  Below this should be ONLY defines and other constructs for C code.
+ */
+
+/* multiboot stuff */
+
+#include "grub/mb_header.h"
+#include "grub/mb_info.h"
+
+/* For the Linux/i386 boot protocol version 2.03.  */
+struct linux_kernel_header
+{
+  char code1[0x0020];
+  unsigned short cl_magic;		/* Magic number 0xA33F */
+  unsigned short cl_offset;		/* The offset of command line */
+  char code2[0x01F1 - 0x0020 - 2 - 2];
+  unsigned char setup_sects;		/* The size of the setup in sectors */
+  unsigned short root_flags;		/* If the root is mounted readonly */
+  unsigned short syssize;		/* obsolete */
+  unsigned short swap_dev;		/* obsolete */
+  unsigned short ram_size;		/* obsolete */
+  unsigned short vid_mode;		/* Video mode control */
+  unsigned short root_dev;		/* Default root device number */
+  unsigned short boot_flag;		/* 0xAA55 magic number */
+  unsigned short jump;			/* Jump instruction */
+  unsigned long header;			/* Magic signature "HdrS" */
+  unsigned short version;		/* Boot protocol version supported */
+  unsigned long realmode_swtch;		/* Boot loader hook */
+  unsigned long start_sys;		/* Points to kernel version string */
+  unsigned char type_of_loader;		/* Boot loader identifier */
+  unsigned char loadflags;		/* Boot protocol option flags */
+  unsigned short setup_move_size;	/* Move to high memory size */
+  unsigned long code32_start;		/* Boot loader hook */
+  unsigned long ramdisk_image;		/* initrd load address */
+  unsigned long ramdisk_size;		/* initrd size */
+  unsigned long bootsect_kludge;	/* obsolete */
+  unsigned short heap_end_ptr;		/* Free memory after setup end */
+  unsigned short pad1;			/* Unused */
+  char *cmd_line_ptr;			/* Points to the kernel command line */
+  unsigned long initrd_addr_max;	/* The highest address of initrd */
+} __attribute__ ((packed));
+
+/* Memory map address range descriptor used by GET_MMAP_ENTRY. */
+struct mmar_desc
+{
+  unsigned long desc_len;	/* Size of this descriptor. */
+  unsigned long long addr;	/* Base address. */
+  unsigned long long length;	/* Length in bytes. */
+  unsigned long type;		/* Type of address range. */
+} __attribute__ ((packed));
+
+/* VBE controller information.  */
+struct vbe_controller
+{
+  unsigned char signature[4];
+  unsigned short version;
+  unsigned long oem_string;
+  unsigned long capabilities;
+  unsigned long video_mode;
+  unsigned short total_memory;
+  unsigned short oem_software_rev;
+  unsigned long oem_vendor_name;
+  unsigned long oem_product_name;
+  unsigned long oem_product_rev;
+  unsigned char reserved[222];
+  unsigned char oem_data[256];
+} __attribute__ ((packed));
+
+/* VBE mode information.  */
+struct vbe_mode
+{
+  unsigned short mode_attributes;
+  unsigned char win_a_attributes;
+  unsigned char win_b_attributes;
+  unsigned short win_granularity;
+  unsigned short win_size;
+  unsigned short win_a_segment;
+  unsigned short win_b_segment;
+  unsigned long win_func;
+  unsigned short bytes_per_scanline;
+
+  /* >=1.2 */
+  unsigned short x_resolution;
+  unsigned short y_resolution;
+  unsigned char x_char_size;
+  unsigned char y_char_size;
+  unsigned char number_of_planes;
+  unsigned char bits_per_pixel;
+  unsigned char number_of_banks;
+  unsigned char memory_model;
+  unsigned char bank_size;
+  unsigned char number_of_image_pages;
+  unsigned char reserved0;
+
+  /* direct color */
+  unsigned char red_mask_size;
+  unsigned char red_field_position;
+  unsigned char green_mask_size;
+  unsigned char green_field_position;
+  unsigned char blue_mask_size;
+  unsigned char blue_field_position;
+  unsigned char reserved_mask_size;
+  unsigned char reserved_field_position;
+  unsigned char direct_color_mode_info;
+
+  /* >=2.0 */
+  unsigned long phys_base;
+  unsigned long reserved1;
+  unsigned short reversed2;
+
+  /* >=3.0 */
+  unsigned short linear_bytes_per_scanline;
+  unsigned char banked_number_of_image_pages;
+  unsigned char linear_number_of_image_pages;
+  unsigned char linear_red_mask_size;
+  unsigned char linear_red_field_position;
+  unsigned char linear_green_mask_size;
+  unsigned char linear_green_field_position;
+  unsigned char linear_blue_mask_size;
+  unsigned char linear_blue_field_position;
+  unsigned char linear_reserved_mask_size;
+  unsigned char linear_reserved_field_position;
+  unsigned long max_pixel_clock;
+
+  unsigned char reserved3[189];
+} __attribute__ ((packed));
+
+
+#undef NULL
+#define NULL         ((void *) 0)
+
+/* Error codes (descriptions are in common.c) */
+typedef enum
+{
+  ERR_NONE = 0,
+  ERR_BAD_FILENAME,
+  ERR_BAD_FILETYPE,
+  ERR_BAD_GZIP_DATA,
+  ERR_BAD_GZIP_HEADER,
+  ERR_BAD_PART_TABLE,
+  ERR_BAD_VERSION,
+  ERR_BELOW_1MB,
+  ERR_BOOT_COMMAND,
+  ERR_BOOT_FAILURE,
+  ERR_BOOT_FEATURES,
+  ERR_DEV_FORMAT,
+  ERR_DEV_VALUES,
+  ERR_EXEC_FORMAT,
+  ERR_FILELENGTH,
+  ERR_FILE_NOT_FOUND,
+  ERR_FSYS_CORRUPT,
+  ERR_FSYS_MOUNT,
+  ERR_GEOM,
+  ERR_NEED_LX_KERNEL,
+  ERR_NEED_MB_KERNEL,
+  ERR_NO_DISK,
+  ERR_NO_PART,
+  ERR_NUMBER_PARSING,
+  ERR_OUTSIDE_PART,
+  ERR_READ,
+  ERR_SYMLINK_LOOP,
+  ERR_UNRECOGNIZED,
+  ERR_WONT_FIT,
+  ERR_WRITE,
+  ERR_BAD_ARGUMENT,
+  ERR_UNALIGNED,
+  ERR_PRIVILEGED,
+  ERR_DEV_NEED_INIT,
+  ERR_NO_DISK_SPACE,
+  ERR_NUMBER_OVERFLOW,
+
+  MAX_ERR_NUM
+} grub_error_t;
+
+extern unsigned long install_partition;
+extern unsigned long boot_drive;
+extern unsigned long install_second_sector;
+extern struct apm_info apm_bios_info;
+extern unsigned long boot_part_addr;
+extern int saved_entryno;
+extern unsigned char force_lba;
+extern char version_string[];
+extern char config_file[];
+extern unsigned long linux_text_len;
+extern char *linux_data_tmp_addr;
+extern char *linux_data_real_addr;
+
+#ifdef GRUB_UTIL
+/* If not using config file, this variable is set to zero,
+   otherwise non-zero.  */
+extern int use_config_file;
+/* If using the preset menu, this variable is set to non-zero,
+   otherwise zero.  */
+extern int use_preset_menu;
+/* If not using curses, this variable is set to zero, otherwise non-zero.  */
+extern int use_curses;
+/* The flag for verbose messages.  */
+extern int verbose;
+/* The flag for read-only.  */
+extern int read_only;
+/* The number of floppies to be probed.  */
+extern int floppy_disks;
+/* The map between BIOS drives and UNIX device file names.  */
+extern char **device_map;
+/* The filename which stores the information about a device map.  */
+extern char *device_map_file;
+/* The array of geometries.  */
+extern struct geometry *disks;
+/* Assign DRIVE to a device name DEVICE.  */
+extern void assign_device_name (int drive, const char *device);
+#endif
+
+#ifndef STAGE1_5
+/* GUI interface variables. */
+# define MAX_FALLBACK_ENTRIES	8
+extern int fallback_entries[MAX_FALLBACK_ENTRIES];
+extern int fallback_entryno;
+extern int default_entry;
+extern int current_entryno;
+
+/* The constants for password types.  */
+typedef enum
+{
+  PASSWORD_PLAIN,
+  PASSWORD_MD5,
+  PASSWORD_UNSUPPORTED
+}
+password_t;
+
+extern char *password;
+extern password_t password_type;
+extern int auth;
+extern char commands[];
+
+/* For `more'-like feature.  */
+extern int max_lines;
+extern int count_lines;
+extern int use_pager;
+#endif
+
+#ifndef NO_DECOMPRESSION
+extern int no_decompression;
+extern int compressed_file;
+#endif
+
+/* instrumentation variables */
+extern void (*disk_read_hook) (int, int, int);
+extern void (*disk_read_func) (int, int, int);
+
+#ifndef STAGE1_5
+/* The flag for debug mode.  */
+extern int debug;
+#endif /* STAGE1_5 */
+
+extern unsigned long current_drive;
+extern unsigned long current_partition;
+
+extern int fsys_type;
+
+/* The information for a disk geometry. The CHS information is only for
+   DOS/Partition table compatibility, and the real number of sectors is
+   stored in TOTAL_SECTORS.  */
+struct geometry
+{
+  /* The number of cylinders */
+  unsigned long cylinders;
+  /* The number of heads */
+  unsigned long heads;
+  /* The number of sectors */
+  unsigned long sectors;
+  /* The total number of sectors */
+  unsigned long total_sectors;
+  /* Device sector size */
+  unsigned long sector_size;
+  /* Flags */
+  unsigned long flags;
+};
+
+extern unsigned long part_start;
+extern unsigned long part_length;
+
+extern int current_slice;
+
+extern int buf_drive;
+extern int buf_track;
+extern struct geometry buf_geom;
+
+/* these are the current file position and maximum file position */
+extern int filepos;
+extern int filemax;
+
+/*
+ *  Common BIOS/boot data.
+ */
+
+extern struct multiboot_info mbi;
+extern unsigned long saved_drive;
+extern unsigned long saved_partition;
+extern unsigned long cdrom_drive;
+#ifndef STAGE1_5
+extern unsigned long saved_mem_upper;
+extern unsigned long extended_memory;
+#endif
+
+/*
+ *  Error variables.
+ */
+
+extern grub_error_t errnum;
+extern char *err_list[];
+
+/* Simplify declaration of entry_addr. */
+typedef void (*entry_func) (int, int, int, int, int, int)
+     __attribute__ ((noreturn));
+
+extern entry_func entry_addr;
+
+/* Enter the stage1.5/stage2 C code after the stack is set up. */
+void cmain (void);
+
+/* Halt the processor (called after an unrecoverable error). */
+void stop (void) __attribute__ ((noreturn));
+
+/* Reboot the system.  */
+void grub_reboot (void) __attribute__ ((noreturn));
+
+/* Halt the system, using APM if possible. If NO_APM is true, don't use
+   APM even if it is available.  */
+void grub_halt (int no_apm) __attribute__ ((noreturn));
+
+/* Copy MAP to the drive map and set up int13_handler.  */
+void set_int13_handler (unsigned short *map);
+
+/* Set up int15_handler.  */
+void set_int15_handler (void);
+
+/* Restore the original int15 handler.  */
+void unset_int15_handler (void);
+
+/* Track the int13 handler to probe I/O address space.  */
+void track_int13 (int drive);
+
+/* The key map.  */
+extern unsigned short bios_key_map[];
+extern unsigned short ascii_key_map[];
+extern unsigned short io_map[];
+
+/* calls for direct boot-loader chaining */
+void chain_stage1 (unsigned long segment, unsigned long offset,
+		   unsigned long part_table_addr)
+     __attribute__ ((noreturn));
+void chain_stage2 (unsigned long segment, unsigned long offset,
+		   int second_sector)
+     __attribute__ ((noreturn));
+
+/* do some funky stuff, then boot linux */
+void linux_boot (void) __attribute__ ((noreturn));
+
+/* do some funky stuff, then boot bzImage linux */
+void big_linux_boot (void) __attribute__ ((noreturn));
+
+/* booting a multiboot executable */
+void multi_boot (int start, int mb_info) __attribute__ ((noreturn));
+
+/* If LINEAR is nonzero, then set the Intel processor to linear mode.
+   Otherwise, bit 20 of all memory accesses is always forced to zero,
+   causing a wraparound effect for bugwards compatibility with the
+   8086 CPU. */
+void gateA20 (int linear);
+
+/* memory probe routines */
+int get_memsize (int type);
+int get_eisamemsize (void);
+
+/* Fetch the next entry in the memory map and return the continuation
+   value.  DESC is a pointer to the descriptor buffer, and CONT is the
+   previous continuation value (0 to get the first entry in the
+   map). */
+int get_mmap_entry (struct mmar_desc *desc, int cont);
+
+/* Get the linear address of a ROM configuration table. Return zero,
+   if fails.  */
+unsigned long get_rom_config_table (void);
+
+/* Get APM BIOS information.  */
+void get_apm_info (void);
+
+/* Get VBE controller information.  */
+int get_vbe_controller_info (struct vbe_controller *controller);
+
+/* Get VBE mode information.  */
+int get_vbe_mode_info (int mode_number, struct vbe_mode *mode);
+
+/* Set VBE mode.  */
+int set_vbe_mode (int mode_number);
+
+/* Return the data area immediately following our code. */
+int get_code_end (void);
+
+/* low-level timing info */
+int getrtsecs (void);
+unsigned long currticks(void);
+//int currticks (void);
+
+/* Clear the screen. */
+void cls (void);
+
+/* Turn on/off cursor. */
+int setcursor (int on);
+
+/* Get the current cursor position (where 0,0 is the top left hand
+   corner of the screen).  Returns packed values, (RET >> 8) is x,
+   (RET & 0xff) is y. */
+int getxy (void);
+
+/* Set the cursor position. */
+void gotoxy (int x, int y);
+
+/* Displays an ASCII character.  IBM displays will translate some
+   characters to special graphical ones (see the DISP_* constants). */
+void grub_putchar (int c);
+
+/* Wait for a keypress, and return its packed BIOS/ASCII key code.
+   Use ASCII_CHAR(ret) to extract the ASCII code. */
+int getkey (void);
+
+/* Like GETKEY, but doesn't block, and returns -1 if no keystroke is
+   available. */
+int checkkey (void);
+
+/* Low-level disk I/O */
+int get_diskinfo (int drive, struct geometry *geometry);
+int biosdisk (int subfunc, int drive, struct geometry *geometry,
+	      int sector, int nsec, int segment);
+void stop_floppy (void);
+
+/* Command-line interface functions. */
+#ifndef STAGE1_5
+
+/* The flags for the builtins.  */
+#define BUILTIN_CMDLINE		0x1	/* Run in the command-line.  */
+#define BUILTIN_MENU		0x2	/* Run in the menu.  */
+#define BUILTIN_TITLE		0x4	/* Only for the command title.  */
+#define BUILTIN_SCRIPT		0x8	/* Run in the script.  */
+#define BUILTIN_NO_ECHO		0x10	/* Don't print command on booting. */
+#define BUILTIN_HELP_LIST	0x20	/* Show help in listing.  */
+
+/* The table for a builtin.  */
+struct builtin
+{
+  /* The command name.  */
+  char *name;
+  /* The callback function.  */
+  int (*func) (char *, int);
+  /* The combination of the flags defined above.  */
+  int flags;
+  /* The short version of the documentation.  */
+  char *short_doc;
+  /* The long version of the documentation.  */
+  char *long_doc;
+};
+
+/* All the builtins are registered in this.  */
+extern struct builtin *builtin_table[];
+
+/* The constants for kernel types.  */
+typedef enum
+{
+  KERNEL_TYPE_NONE,		/* None is loaded.  */
+  KERNEL_TYPE_MULTIBOOT,	/* Multiboot.  */
+  KERNEL_TYPE_LINUX,		/* Linux.  */
+  KERNEL_TYPE_BIG_LINUX,	/* Big Linux.  */
+  KERNEL_TYPE_FREEBSD,		/* FreeBSD.  */
+  KERNEL_TYPE_NETBSD,		/* NetBSD.  */
+  KERNEL_TYPE_CHAINLOADER	/* Chainloader.  */
+}
+kernel_t;
+
+extern kernel_t kernel_type;
+extern int show_menu;
+extern int grub_timeout;
+
+void init_builtins (void);
+void init_config (void);
+char *skip_to (int after_equal, char *cmdline);
+struct builtin *find_command (char *command);
+void enter_cmdline (char *heap, int forever);
+int run_script (char *script, char *heap);
+
+/* the flags for the cmdline message */
+#define CMDLINE_FOREVER_MODE 0x0
+#define CMDLINE_NORMAL_MODE 0x1
+#define CMDLINE_EDIT_MODE 0x2
+
+void print_cmdline_message (int type);
+#endif
+
+/* C library replacement functions with identical semantics. */
+void grub_printf (const char *format,...);
+//int grub_sprintf (char *buffer, const char *format, ...);
+//int grub_tolower (int c);
+//int grub_isspace (int c);
+//int grub_strncat (char *s1, const char *s2, int n);
+//void *grub_memmove (void *to, const void *from, int len);
+//void *grub_memset (void *start, int c, int len);
+//int grub_strncat (char *s1, const char *s2, int n);
+//char *grub_strstr (const char *s1, const char *s2);
+//int grub_memcmp (const char *s1, const char *s2, int n);
+//int grub_strcmp (const char *s1, const char *s2);
+//int grub_strlen (const char *str);
+//char *grub_strcpy (char *dest, const char *src);
+
+#ifndef GRUB_UTIL
+typedef unsigned long grub_jmp_buf[6];
+#else
+/* In the grub shell, use the libc jmp_buf instead.  */
+# include <setjmp.h>
+# define grub_jmp_buf jmp_buf
+#endif
+
+#ifdef GRUB_UTIL
+# define grub_setjmp	setjmp
+# define grub_longjmp	longjmp
+#else /* ! GRUB_UTIL */
+int grub_setjmp (grub_jmp_buf env);
+void grub_longjmp (grub_jmp_buf env, int val);
+#endif /* ! GRUB_UTIL */
+
+/* The environment for restarting Stage 2.  */
+extern grub_jmp_buf restart_env;
+/* The environment for restarting the command-line interface.  */
+extern grub_jmp_buf restart_cmdline_env;
+
+/* misc */
+void init_page (void);
+void print_error (void);
+char *convert_to_ascii (char *buf, int c, ...);
+int get_cmdline (char *prompt, char *cmdline, int maxlen,
+		 int echo_char, int history);
+int substring (const char *s1, const char *s2);
+int nul_terminate (char *str);
+int get_based_digit (int c, int base);
+int safe_parse_maxint (char **str_ptr, int *myint_ptr);
+int memcheck (int start, int len);
+void grub_putstr (const char *str);
+
+#ifndef NO_DECOMPRESSION
+/* Compression support. */
+int gunzip_test_header (void);
+int gunzip_read (char *buf, int len);
+#endif /* NO_DECOMPRESSION */
+
+int rawread (int drive, int sector, int byte_offset, int byte_len, char *buf);
+int devread (int sector, int byte_offset, int byte_len, char *buf);
+int rawwrite (int drive, int sector, char *buf);
+int devwrite (int sector, int sector_len, char *buf);
+
+/* Parse a device string and initialize the global parameters. */
+char *set_device (char *device);
+int open_device (void);
+int real_open_partition (int flags);
+int open_partition (void);
+int next_partition (unsigned long drive, unsigned long dest,
+		    unsigned long *partition, int *type,
+		    unsigned long *start, unsigned long *len,
+		    unsigned long *offset, int *entry,
+		    unsigned long *ext_offset, char *buf);
+
+/* Sets device to the one represented by the SAVED_* parameters. */
+int make_saved_active (void);
+
+/* Set or clear the current root partition's hidden flag.  */
+int set_partition_hidden_flag (int hidden);
+
+#if 0
+/* Open a file or directory on the active device, using GRUB's
+   internal filesystem support. */
+int grub_open (char *filename);
+
+/* Read LEN bytes into BUF from the file that was opened with
+   GRUB_OPEN.  If LEN is -1, read all the remaining data in the file.  */
+int grub_read (char *buf, int len);
+
+/* Reposition a file offset.  */
+int grub_seek (int offset);
+
+/* Close a file.  */
+void grub_close (void);
+#endif
+
+/* List the contents of the directory that was opened with GRUB_OPEN,
+   printing all completions. */
+int dir (char *dirname);
+
+int set_bootdev (int hdbias);
+
+/* Display statistics on the current active device. */
+void print_fsys_type (void);
+
+/* Display device and filename completions. */
+void print_a_completion (char *filename);
+int print_completions (int is_filename, int is_completion);
+
+/* Copies the current partition data to the desired address. */
+void copy_current_part_entry (char *buf);
+
+#ifndef STAGE1_5
+void bsd_boot (kernel_t type, int bootdev, char *arg)
+     __attribute__ ((noreturn));
+
+/* Define flags for load_image here.  */
+/* Don't pass a Linux's mem option automatically.  */
+#define KERNEL_LOAD_NO_MEM_OPTION	(1 << 0)
+
+kernel_t load_image (char *kernel, char *arg, kernel_t suggested_type,
+		     unsigned long load_flags);
+
+int load_module (char *module, char *arg);
+int load_initrd (char *initrd);
+
+int check_password(char *entered, char* expected, password_t type);
+#endif
+
+void init_bios_info (void);
+
+#endif /* ASM_FILE */
+
+#endif /* ! GRUB_SHARED_HEADER */

Added: trunk/filo/include/grub/term.h
===================================================================
--- trunk/filo/include/grub/term.h	                        (rev 0)
+++ trunk/filo/include/grub/term.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,115 @@
+/* term.h - definitions for terminal handling */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002  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.
+ */
+
+#ifndef GRUB_TERM_HEADER
+#define GRUB_TERM_HEADER	1
+
+/* These are used to represent the various color states we use */
+typedef enum
+{
+  /* represents the color used to display all text that does not use the user
+   * defined colors below
+   */
+  COLOR_STATE_STANDARD,
+  /* represents the user defined colors for normal text */
+  COLOR_STATE_NORMAL,
+  /* represents the user defined colors for highlighted text */
+  COLOR_STATE_HIGHLIGHT
+} color_state;
+
+#ifndef STAGE1_5
+
+/* Flags for representing the capabilities of a terminal.  */
+/* Some notes about the flags:
+   - These flags are used by higher-level functions but not terminals
+   themselves.
+   - If a terminal is dumb, you may assume that only putchar, getkey and
+   checkkey are called.
+   - Some fancy features (nocursor, setcolor, and highlight) can be set to
+   NULL.  */
+
+/* Set when input characters shouldn't be echoed back.  */
+#define TERM_NO_ECHO		(1 << 0)
+/* Set when the editing feature should be disabled.  */
+#define TERM_NO_EDIT		(1 << 1)
+/* Set when the terminal cannot do fancy things.  */
+#define TERM_DUMB		(1 << 2)
+/* Set when the terminal needs to be initialized.  */
+#define TERM_NEED_INIT		(1 << 16)
+
+struct term_entry
+{
+  /* The name of a terminal.  */
+  const char *name;
+  /* The feature flags defined above.  */
+  unsigned long flags;
+  /* Put a character.  */
+  void (*putchar) (int c);
+  /* Check if any input character is available.  */
+  int (*checkkey) (void);
+  /* Get a character.  */
+  int (*getkey) (void);
+  /* Get the cursor position. The return value is ((X << 8) | Y).  */
+  int (*getxy) (void);
+  /* Go to the position (X, Y).  */
+  void (*gotoxy) (int x, int y);
+  /* Clear the screen.  */
+  void (*cls) (void);
+  /* Set the current color to be used */
+  void (*setcolorstate) (color_state state);
+  /* Set the normal color and the highlight color. The format of each
+     color is VGA's.  */
+  void (*setcolor) (int normal_color, int highlight_color);
+  /* Turn on/off the cursor.  */
+  int (*setcursor) (int on);
+};
+
+/* This lists up available terminals.  */
+extern struct term_entry term_table[];
+/* This points to the current terminal. This is useful, because only
+   a single terminal is enabled normally.  */
+extern struct term_entry *current_term;
+
+#endif /* ! STAGE1_5 */
+
+/* The console stuff.  */
+//extern int console_current_color;
+void console_putchar (int c);
+
+#ifndef STAGE1_5
+int console_checkkey (void);
+int console_getkey (void);
+int console_getxy (void);
+void console_gotoxy (int x, int y);
+void console_cls (void);
+void console_setcolorstate (color_state state);
+void console_setcolor (int normal_color, int highlight_color);
+int console_setcursor (int on);
+#endif
+
+void grub_serial_putchar (int c);
+int serial_checkkey (void);
+int serial_getkey (void);
+int serial_getxy (void);
+void serial_gotoxy (int x, int y);
+void serial_cls (void);
+void serial_setcolorstate (color_state state);
+
+#endif /* ! GRUB_TERM_HEADER */

Added: trunk/filo/include/grub/terminfo.h
===================================================================
--- trunk/filo/include/grub/terminfo.h	                        (rev 0)
+++ trunk/filo/include/grub/terminfo.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,51 @@
+/* terminfo.h - read a terminfo entry from the command line */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004  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.
+ */
+
+#ifndef GRUB_TERMCAP_HEADER
+#define GRUB_TERMCAP_HEADER	1
+
+#define TERMINFO_LEN 40
+
+typedef struct terminfo
+{
+  char name[TERMINFO_LEN];
+  char cursor_address[TERMINFO_LEN];
+  char clear_screen[TERMINFO_LEN];
+  char enter_standout_mode[TERMINFO_LEN];
+  char exit_standout_mode[TERMINFO_LEN];
+}
+terminfo;
+
+
+/* Function prototypes.  */
+char *ti_escape_memory (const char *in, const char *end);
+char *ti_escape_string (const char *in);
+char *ti_unescape_memory (const char *in, const char *end);
+char *ti_unescape_string (const char *in);
+
+void ti_set_term (const struct terminfo *new);
+void ti_get_term (struct terminfo *copy);
+
+void ti_cursor_address (int x, int y);
+void ti_clear_screen (void);
+void ti_enter_standout_mode (void);
+void ti_exit_standout_mode (void);
+
+#endif /* ! GRUB_TERMCAP_HEADER */

Added: trunk/filo/include/grub/tparm.h
===================================================================
--- trunk/filo/include/grub/tparm.h	                        (rev 0)
+++ trunk/filo/include/grub/tparm.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,28 @@
+/* tparm.h - parameter formatting of terminfo */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002  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.
+ */
+
+#ifndef GRUB_TPARM_HEADER
+#define GRUB_TPARM_HEADER	1
+
+
+/* Function prototypes.  */
+char *grub_tparm (const char *string, ...);
+
+#endif /* ! GRUB_TERMCAP_HEADER */

Added: trunk/filo/include/ipchecksum.h
===================================================================
--- trunk/filo/include/ipchecksum.h	                        (rev 0)
+++ trunk/filo/include/ipchecksum.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,25 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef IPCHECKSUM_H
+#define IPCHECKSUM_H
+
+unsigned short ipchksum(const void *data, unsigned long length);
+unsigned short add_ipchksums(unsigned long offset, unsigned short sum, unsigned short new);
+
+#endif /* IPCHECKSUM_H */

Added: trunk/filo/include/lib.h
===================================================================
--- trunk/filo/include/lib.h	                        (rev 0)
+++ trunk/filo/include/lib.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,65 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef LIB_H
+#define LIB_H
+
+#include <libpayload.h>
+#include <config.h>
+
+// from libpayload.
+int getline(char *buf, int max);
+
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
+unsigned long long strtoull_with_suffix(const char *cp,char **endp,unsigned int base);
+
+u32 get_le32(const unsigned char *);
+u16 get_le16(const unsigned char *);
+
+void hexdump(const void *p, unsigned int len);
+
+long long simple_strtoll(const char *cp,char **endp,unsigned int base);
+
+void halt(void) __attribute__((noreturn));
+
+#define abort() halt()
+
+#define LOADER_NOT_SUPPORT 0xbadf11e
+
+struct sys_info;
+int elf_load(const char *filename, const char *cmdline);
+
+#if CONFIG_LINUX_LOADER
+int linux_load(const char *filename, const char *cmdline);
+#else
+#define linux_load(x,y) LOADER_NOT_SUPPORT /* nop */
+#endif
+
+#if CONFIG_WINCE_LOADER
+int wince_load(const char *filename, const char *cmdline);
+#else
+#define wince_load(x,y) LOADER_NOT_SUPPORT /* nop */
+#endif
+
+#if CONFIG_ARTEC_BOOT
+int artecboot_load(const char *filename, const char *cmdline);
+#else
+#define artecboot_load(x,y) LOADER_NOT_SUPPORT /* nop */
+#endif
+
+#endif /* LIB_H */

Added: trunk/filo/include/sound.h
===================================================================
--- trunk/filo/include/sound.h	                        (rev 0)
+++ trunk/filo/include/sound.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,60 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef SOUND_H
+#define SOUND_H
+
+#include <libpayload.h>
+
+/*
+ * Application interface
+ */
+int sound_init(void);
+void sound_set_rate(int rate);
+void sound_set_volume(int volume);
+int sound_write(const void *buf, int size);
+void sound_start(void);
+void sound_stop(void);
+int sound_is_active(void);
+
+/*
+ * Driver interface
+ */
+
+struct sound_ops {
+    int (*init)(pcidev_t);
+    void (*set_rate)(int rate);
+    void (*set_volume)(int volume);
+    int (*write)(const void *buf, int size);
+    int (*is_active)(void);
+    void (*stop)(void);
+};
+
+struct sound_driver {
+    u16 vendor;
+    u16 device;
+    struct sound_ops *ops;
+};
+
+#define __sound_driver __attribute__((unused, section(".rodata.sound_drivers")))
+
+/* defined by the linker */
+extern struct sound_driver sound_drivers_start[];
+extern struct sound_driver sound_drivers_end[];
+
+#endif /* SOUND_H */

Added: trunk/filo/include/sys_info.h
===================================================================
--- trunk/filo/include/sys_info.h	                        (rev 0)
+++ trunk/filo/include/sys_info.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,49 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#ifndef SYS_INFO_H
+#define SYS_INFO_H
+
+/* Information collected from firmware/bootloader */
+
+struct sys_info {
+    /* Values passed by bootloader */
+    unsigned long boot_type;
+    unsigned long boot_data;
+    unsigned long boot_arg;
+
+    char *firmware; /* "PCBIOS", "LinuxBIOS", etc. */
+    char *command_line; /* command line given to us */
+#if 0
+    /* memory map */
+    int n_memranges;
+    struct memrange {
+	unsigned long long base;
+	unsigned long long size;
+    } *memrange;
+#endif
+};
+
+void collect_sys_info(struct sys_info *info);
+void collect_elfboot_info(struct sys_info *info);
+void collect_linuxbios_info(struct sys_info *info);
+
+/* Our name and version. I want to see single instance of these in the image */
+extern const char *program_name, *program_version;
+
+#endif /* SYS_INFO_H */

Added: trunk/filo/main/Makefile.inc
===================================================================
--- trunk/filo/main/Makefile.inc	                        (rev 0)
+++ trunk/filo/main/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+TARGETS-y += main/filo.o main/elfload.o main/elfnote.o main/ipchecksum.o main/strtox.o
+TARGETS-$(CONFIG_SUPPORT_SOUND) += main/sound.o
+TARGETS-$(CONFIG_USE_GRUB) += main/grub.o
+

Added: trunk/filo/main/elfload.c
===================================================================
--- trunk/filo/main/elfload.c	                        (rev 0)
+++ trunk/filo/main/elfload.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,395 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* ELF Boot loader
+ * As we have seek, this implementation can be straightforward.
+ * 2003-07 by SONE Takeshi
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <arch/timer.h>
+#include <sys_info.h>
+#include <elf.h>
+#include <arch/elf.h>
+#include <elf_boot.h>
+#include <ipchecksum.h>
+#include <fs.h>
+#define DEBUG_THIS CONFIG_DEBUG_ELFBOOT
+#include <debug.h>
+
+extern unsigned int start_elf(unsigned long entry_point, unsigned long param);
+extern char _start, _end;
+
+static char *image_name, *image_version;
+
+static int check_mem_ranges(Elf_phdr *phdr, int phnum)
+{
+    int i, j;
+    unsigned long start, end;
+    unsigned long prog_start, prog_end;
+    struct memrange *mem;
+    struct sysinfo_t *info = &lib_sysinfo;
+
+    prog_start = virt_to_phys(&_start);
+    prog_end = virt_to_phys(&_end);
+
+    for (i = 0; i < phnum; i++) {
+	if (phdr[i].p_type != PT_LOAD)
+	    continue;
+	start = phdr[i].p_paddr;
+	end = start + phdr[i].p_memsz;
+	if (start < prog_start && end > prog_start)
+	    goto conflict;
+	if (start < prog_end && end > prog_end)
+	    goto conflict;
+	for (j = 0; j < info->n_memranges; j++) {
+	    mem = &info->memrange[j];
+	    if (mem->base <= start && mem->base + mem->size >= end)
+		break;
+	}
+	if (j >= info->n_memranges)
+	    goto badseg;
+    }
+    return 1;
+
+conflict:
+    printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
+
+badseg:
+    printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
+    return 0;
+}
+
+static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
+	unsigned short *sum_ptr)
+{
+    int i;
+    char *buf = NULL;
+    int retval = 0;
+    unsigned long addr, end;
+    Elf_Nhdr *nhdr;
+    const char *name;
+    void *desc;
+
+    for (i = 0; i < phnum; i++) {
+	if (phdr[i].p_type != PT_NOTE)
+	    continue;
+	buf = malloc(phdr[i].p_filesz);
+	file_seek(phdr[i].p_offset);
+	if (file_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) {
+	    printf("Can't read note segment\n");
+	    goto out;
+	}
+	addr = (unsigned long) buf;
+	end = addr + phdr[i].p_filesz;
+	while (addr < end) {
+	    nhdr = (Elf_Nhdr *) addr;
+	    addr += sizeof(Elf_Nhdr);
+	    name = (const char *) addr;
+	    addr += (nhdr->n_namesz+3) & ~3;
+	    desc = (void *) addr;
+	    addr += (nhdr->n_descsz+3) & ~3;
+
+	    if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT)
+		    && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) {
+		if (nhdr->n_type == EIN_PROGRAM_NAME) {
+		    image_name = calloc(1, nhdr->n_descsz + 1);
+		    memcpy(image_name, desc, nhdr->n_descsz);
+		}
+		if (nhdr->n_type == EIN_PROGRAM_VERSION) {
+		    image_version = calloc(1, nhdr->n_descsz + 1);
+		    memcpy(image_version, desc, nhdr->n_descsz);
+		}
+		if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) {
+		    *sum_ptr = *(unsigned short *) desc;
+		    debug("Image checksum: %#04x\n", *sum_ptr);
+		    /* Where in the file */
+		    retval = phdr[i].p_offset
+			+ (unsigned long) desc - (unsigned long) buf;
+		}
+	    }
+	}
+    }
+out:
+    if (buf)
+	free(buf);
+    return retval;
+}
+
+static int load_segments(Elf_phdr *phdr, int phnum,
+	unsigned long checksum_offset)
+{
+    unsigned long bytes;
+    unsigned int start_time, time;
+    int i;
+
+    bytes = 0;
+    start_time = currticks();
+    for (i = 0; i < phnum; i++) {
+	if (phdr[i].p_type != PT_LOAD)
+	    continue;
+	debug("segment %d addr:%#x file:%#x mem:%#x ",
+		i, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz);
+	file_seek(phdr[i].p_offset);
+	debug("loading... ");
+	if (file_read(phys_to_virt(phdr[i].p_paddr), phdr[i].p_filesz)
+		!= phdr[i].p_filesz) {
+	    printf("Can't read program segment %d\n", i);
+	    return 0;
+	}
+	bytes += phdr[i].p_filesz;
+	debug("clearing... ");
+	memset(phys_to_virt(phdr[i].p_paddr + phdr[i].p_filesz), 0, 
+		phdr[i].p_memsz - phdr[i].p_filesz);
+	if (phdr[i].p_offset <= checksum_offset
+		&& phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) {
+	    debug("clearing checksum... ");
+	    memset(phys_to_virt(phdr[i].p_paddr + checksum_offset
+			- phdr[i].p_offset), 0, 2);
+	}
+	debug("ok\n");
+
+    }
+    time = currticks() - start_time;
+    debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time,
+	    time? bytes/time : 0);
+    return 1;
+}
+
+static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
+	unsigned short image_sum)
+{
+    unsigned short sum, part_sum;
+    unsigned long offset;
+    int i;
+
+    sum = 0;
+    offset = 0;
+
+    part_sum = ipchksum(ehdr, sizeof *ehdr);
+    sum = add_ipchksums(offset, sum, part_sum);
+    offset += sizeof *ehdr;
+
+    part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
+    sum = add_ipchksums(offset, sum, part_sum);
+    offset += phnum * sizeof(*phdr);
+
+    for (i = 0; i < phnum; i++) {
+	if (phdr[i].p_type != PT_LOAD)
+	    continue;
+	part_sum = ipchksum(phys_to_virt(phdr[i].p_paddr), phdr[i].p_memsz);
+	sum = add_ipchksums(offset, sum, part_sum);
+	offset += phdr[i].p_memsz;
+    }
+
+    if (sum != image_sum) {
+	printf("Verify FAILED (image:%#04x vs computed:%#04x)\n",
+		image_sum, sum);
+	return 0;
+    }
+    return 1;
+}
+
+static inline unsigned int padded(unsigned int s)
+{
+    return ((s + 3) & ~3);
+}
+
+static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
+	unsigned type, const char *desc, unsigned descsz)
+{
+    Elf_Nhdr nhdr;
+    unsigned ent_size, new_size, pad;
+    char *addr;
+
+    if (!bhdr)
+	return NULL;
+
+    nhdr.n_namesz = name? strlen(name)+1 : 0;
+    nhdr.n_descsz = descsz;
+    nhdr.n_type = type;
+    ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz);
+    if (bhdr->b_size + ent_size > 0xffff) {
+	printf("Boot notes too big\n");
+	free(bhdr);
+	return NULL;
+    }
+    if (bhdr->b_size + ent_size > bhdr->b_checksum) {
+	do {
+	    new_size = bhdr->b_checksum * 2;
+	} while (new_size < bhdr->b_size + ent_size);
+	if (new_size > 0xffff)
+	    new_size = 0xffff;
+	debug("expanding boot note size to %u\n", new_size);
+	bhdr = realloc(bhdr, new_size);
+	bhdr->b_checksum = new_size;
+    }
+
+    addr = (char *) bhdr;
+    addr += bhdr->b_size;
+    memcpy(addr, &nhdr, sizeof(nhdr));
+    addr += sizeof(nhdr);
+
+    memcpy(addr, name, nhdr.n_namesz);
+    addr += nhdr.n_namesz;
+    pad = padded(nhdr.n_namesz) - nhdr.n_namesz;
+    memset(addr, 0, pad);
+    addr += pad;
+
+    memcpy(addr, desc, nhdr.n_descsz);
+    addr += nhdr.n_descsz;
+    pad = padded(nhdr.n_descsz) - nhdr.n_descsz;
+    memset(addr, 0, pad);
+    addr += pad;
+
+    bhdr->b_size += ent_size;
+    bhdr->b_records++;
+    return bhdr;
+}
+
+static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
+	unsigned type, const char *desc)
+{
+    return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
+}
+
+static Elf_Bhdr *build_boot_notes(const char *cmdline)
+{
+    Elf_Bhdr *bhdr;
+    extern struct sys_info sys_info;
+
+    bhdr = malloc(256);
+    bhdr->b_signature = ELF_BHDR_MAGIC;
+    bhdr->b_size = sizeof *bhdr;
+    bhdr->b_checksum = 256; /* XXX cache the current buffer size here */
+    bhdr->b_records = 0;
+
+    if (sys_info.firmware)
+    bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, sys_info.firmware);
+    bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name);
+    bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version);
+    if (cmdline)
+	bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
+    if (!bhdr)
+	return bhdr;
+    bhdr->b_checksum = 0;
+    bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
+    return bhdr;
+}
+
+int elf_load(const char *filename, const char *cmdline)
+{
+    Elf_ehdr ehdr;
+    Elf_phdr *phdr = NULL;
+    unsigned long phdr_size;
+    unsigned long checksum_offset;
+    unsigned short checksum=0;
+    Elf_Bhdr *boot_notes = NULL;
+    int retval = -1;
+    int image_retval;
+#ifdef CONFIG_PCMCIA_CF
+    unsigned char *cf_bar;
+    int i;
+#endif
+
+    image_name = image_version = 0;
+
+    if (!file_open(filename))
+	goto out;
+
+    if (file_read(&ehdr, sizeof ehdr) != sizeof ehdr) {
+	debug("Can't read ELF header\n");
+	retval = LOADER_NOT_SUPPORT;
+	goto out;
+    }
+
+    if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+	    || ehdr.e_ident[EI_MAG1] != ELFMAG1
+	    || ehdr.e_ident[EI_MAG2] != ELFMAG2
+	    || ehdr.e_ident[EI_MAG3] != ELFMAG3
+	    || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS
+	    || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA
+	    || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+	    || ehdr.e_type != ET_EXEC
+	    || !ARCH_ELF_MACHINE_OK(ehdr.e_machine)
+	    || ehdr.e_version != EV_CURRENT
+	    || ehdr.e_phentsize != sizeof(Elf_phdr)) {
+	debug("Not a bootable ELF image\n");
+	retval = LOADER_NOT_SUPPORT;
+	goto out;
+    }
+
+    phdr_size = ehdr.e_phnum * sizeof *phdr;
+    phdr = malloc(phdr_size);
+    file_seek(ehdr.e_phoff);
+    if (file_read(phdr, phdr_size) != phdr_size) {
+	printf("Can't read program header\n");
+	goto out;
+    }
+
+    if (!check_mem_ranges(phdr, ehdr.e_phnum))
+	goto out;
+
+    checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum);
+
+    printf("Loading %s", image_name ? image_name : "image");
+    if (image_version)
+	printf(" version %s", image_version);
+    printf("...\n");
+
+    if (!load_segments(phdr, ehdr.e_phnum, checksum_offset))
+	goto out;
+
+    if (checksum_offset) {
+	if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
+	    goto out;
+    }
+
+    file_close();
+    
+    boot_notes = build_boot_notes(cmdline);
+
+#if CONFIG_PCMCIA_CF
+    cf_bar = phys_to_virt(pci_read_config32(PCI_DEV(0, 0xa, 1), 0x10));
+    for( i = 0x836 ; i < 0x840 ; i++){
+        cf_bar[i] = 0;
+    }
+#endif
+
+    debug("current time: %lu\n", currticks());
+
+    debug("entry point is %#x\n", ehdr.e_entry);
+    printf("Jumping to entry point...\n");
+    image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes));
+
+    console_init();
+    printf("Image returned with return value %#x\n", image_retval);
+    retval = 0;
+
+out:
+    if (phdr)
+	free(phdr);
+    if (boot_notes)
+	free(boot_notes);
+    if (image_name)
+	free(image_name);
+    if (image_version)
+	free(image_version);
+    file_close();
+    return retval;
+}

Added: trunk/filo/main/elfnote.c
===================================================================
--- trunk/filo/main/elfnote.c	                        (rev 0)
+++ trunk/filo/main/elfnote.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,170 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Support for ELF Boot Proposal as a boot image */
+#include <libpayload.h>
+#include <config.h>
+#include <elf_boot.h>
+#include <sys_info.h>
+#include <stddef.h>
+#include <ipchecksum.h>
+#include <version.h>
+#define DEBUG_THIS CONFIG_DEBUG_ELFNOTE
+#include <debug.h>
+
+/* ELF image notes provide information to the loader who boots us */
+
+/* This compiles and generates correct PT_NOTE segment for me.
+ * If it doesn't, use assembly version below. */
+
+struct elf_image_note {
+    Elf_Nhdr hdr0;
+    char name0[sizeof(ELF_NOTE_BOOT)];
+    char prog_name[sizeof(PROGRAM_NAME)];
+
+    Elf_Nhdr hdr1;
+    char name1[sizeof(ELF_NOTE_BOOT)];
+    char version[sizeof(PROGRAM_VERSION_FULL)];
+
+    Elf_Nhdr hdr2;
+    char name2[sizeof(ELF_NOTE_BOOT)];
+    unsigned short checksum;
+};
+
+const struct elf_image_note elf_image_notes
+	__attribute__ ((section (".note.ELFBoot"))) =
+{
+    .hdr0 = {
+	.n_namesz = sizeof(ELF_NOTE_BOOT),
+	.n_descsz = sizeof(PROGRAM_NAME),
+	.n_type = EIN_PROGRAM_NAME,
+    },
+    .name0 = ELF_NOTE_BOOT,
+    .prog_name = PROGRAM_NAME,
+
+    .hdr1 = {
+	.n_namesz = sizeof(ELF_NOTE_BOOT),
+	.n_descsz = sizeof(PROGRAM_VERSION_FULL),
+	.n_type = EIN_PROGRAM_VERSION,
+    },
+    .name1 = ELF_NOTE_BOOT,
+    .version = PROGRAM_VERSION_FULL,
+
+    .hdr2 = {
+	.n_namesz = sizeof(ELF_NOTE_BOOT),
+	.n_descsz = sizeof(unsigned short),
+	.n_type = EIN_PROGRAM_CHECKSUM,
+    },
+    .name2 = ELF_NOTE_BOOT,
+    .checksum = 0, /* to be computed by external tool */
+};
+
+/* This is refered by other files */
+const char *program_name = elf_image_notes.prog_name;
+const char *program_version = elf_image_notes.version;
+
+#if 0
+
+	/* This tells the linker to make a PT_NOTE segment.
+	 * If the section is named just ".note", it will be
+	 * mixed up with useless .version notes generated by GCC.
+	 */
+	.section ".note.ELFBoot", "a"
+
+	.align 4
+	.int 2f - 1f
+	.int 4f - 3f
+	.int EIN_PROGRAM_NAME
+1:	.asciz "ELFBoot"
+2:	.align 4
+3:	.asciz PROGRAM_NAME
+4:
+
+	.align 4
+	.int 2f - 1f
+	.int 4f - 3f
+	.int EIN_PROGRAM_VERSION
+1:	.asciz "ELFBoot"
+2:	.align 4
+3:	.asciz PROGRAM_VERSION
+4:
+
+	.align 4
+	.int 2f - 1f
+	.int 4f - 3f
+	.int EIN_PROGRAM_CHECKSUM
+1:	.asciz "ELFBoot"
+2:	.align 4
+3:	.short 0
+4:
+#endif
+
+/* Collect information from the ELF bootloader
+ * Note that we have to copy them to our own memory,
+ * otherwise they might be overwritten afterward. */
+void collect_elfboot_info(struct sys_info *info)
+{
+    Elf_Bhdr *hdr = NULL;
+    char *addr, *end;
+    Elf_Nhdr *nhdr;
+    char *name, *desc;
+
+    if (info->boot_type == ELF_BHDR_MAGIC)
+	hdr = phys_to_virt(info->boot_data);
+    else
+	hdr = phys_to_virt(info->boot_arg);
+
+    if (hdr->b_signature != ELF_BHDR_MAGIC)
+	return;
+
+    if (ipchksum(hdr, hdr->b_size) != 0) {
+	printf("Broken ELF boot notes\n");
+	return;
+    }
+
+    addr = (char *) (hdr + 1);
+    end = addr + hdr->b_size;
+    while (addr <  end) {
+	nhdr = (Elf_Nhdr *) addr;
+	addr += sizeof(Elf_Nhdr);
+	name = addr;
+	addr += (nhdr->n_namesz + 3) & ~3;
+	desc = addr;
+	addr += (nhdr->n_descsz + 3) & ~3;
+
+	if (nhdr->n_namesz == 0) {
+	    /* Standard notes */
+	    switch (nhdr->n_type) {
+	    case EBN_FIRMWARE_TYPE:
+		info->firmware = strdup(desc);
+		break;
+	    case EBN_BOOTLOADER_NAME:
+		debug("Bootloader: %s\n", desc);
+		break;
+	    case EBN_BOOTLOADER_VERSION:
+		debug("Version: %s\n", desc);
+		break;
+	    case EBN_COMMAND_LINE:
+		info->command_line = strdup(desc);
+		break;
+	    case EBN_LOADED_IMAGE:
+		debug("Image name: %s\n", desc);
+		break;
+	    }
+	}
+    }
+}

Added: trunk/filo/main/filo.c
===================================================================
--- trunk/filo/main/filo.c	                        (rev 0)
+++ trunk/filo/main/filo.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,187 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <config.h>
+#include <version.h>
+#include <lib.h>
+#include <fs.h>
+#include <sys_info.h>
+#include <sound.h>
+#include <arch/timer.h>
+
+PAYLOAD_INFO(name, PROGRAM_NAME " " PROGRAM_VERSION);
+PAYLOAD_INFO(listname, PROGRAM_NAME);
+PAYLOAD_INFO(desc, "Bootloader");
+
+#define ENTER '\r'
+#define ESCAPE '\x1b'
+
+#if !defined(CONFIG_AUTOBOOT_FILE)
+#define autoboot() ((void) 0) /* nop */
+#endif
+
+#ifndef CONFIG_AUTOBOOT_DELAY
+#define autoboot_delay() 0 /* success */
+#endif
+
+struct sys_info sys_info;
+
+void relocate(void);
+
+static void init(void)
+{
+    /* Set up the consoles. */
+    console_init();
+#ifdef CONFIG_VIDEO_CONSOLE
+    video_console_init();
+#endif
+
+    /* Gather system information, and implicitly sets up timers */
+    lib_get_sysinfo();
+
+    printf("%s version %s\n", program_name, program_version);
+    collect_sys_info(&sys_info);
+    relocate();
+    usb_initialize();
+
+#ifdef CONFIG_SUPPORT_SOUND
+    sound_init();
+#endif
+#ifdef CONFIG_SLOW_SATA
+    delay(5);
+#endif
+}
+
+void boot(const char *line)
+{
+    char *file, *param;
+
+    /* Split filename and parameter */
+    file = strdup(line);
+    param = strchr(file, ' ');
+    if (param) {
+	*param = '\0';
+	param++;
+    }
+
+	if (artecboot_load(file, param) == LOADER_NOT_SUPPORT)
+    if (elf_load(file, param) == LOADER_NOT_SUPPORT)
+	if (linux_load(file, param) == LOADER_NOT_SUPPORT)
+	if (wince_load(file, param) == LOADER_NOT_SUPPORT)
+	    printf("Unsupported image format\n");
+    free(file);
+}
+
+#if CONFIG_USE_GRUB
+/* The main routine */
+int main(void)
+{
+    void grub_main(void);
+    
+    /* Initialize */
+    init();
+    grub_main();
+    return 0;   
+}
+
+#else // ! CONFIG_USE_GRUB
+
+#ifdef CONFIG_AUTOBOOT_FILE
+#if CONFIG_AUTOBOOT_DELAY
+static inline int autoboot_delay(void)
+{
+    unsigned int timeout;
+    int sec, tmp;
+    char key;
+    
+    key = 0;
+
+    printf("Press <Enter> for default boot, or <Esc> for boot prompt... ");
+    for (sec = CONFIG_AUTOBOOT_DELAY; sec>0 && key==0; sec--) {
+	printf("%d", sec);
+	timeout = currticks() + TICKS_PER_SEC;
+	while (currticks() < timeout) {
+	    if (havechar()) {
+		key = getchar();
+		if (key==ENTER || key==ESCAPE)
+		    break;
+	    }
+	}
+	for (tmp = sec; tmp; tmp /= 10)
+	    printf("\b \b");
+    }
+    if (key == 0) {
+	printf("timed out\n");
+	return 0; /* success */
+    } else {
+	putchar('\n');
+	if (key == ESCAPE)
+	    return -1; /* canceled */
+	else
+	    return 0; /* default accepted */
+    }
+}
+#endif /* CONFIG_AUTOBOOT_DELAY */
+
+static void autoboot(void)
+{
+    /* If Escape key is pressed already, skip autoboot */
+    if (havechar() && getchar()==ESCAPE)
+	return;
+
+    if (autoboot_delay()==0) {
+	printf("boot: %s\n", CONFIG_AUTOBOOT_FILE);
+	boot(CONFIG_AUTOBOOT_FILE);
+    }
+}
+#endif /* AUTOBOOT_FILE */
+
+/* The main routine */
+int main(void)
+{
+    char line[256];
+
+    /* Initialize */
+    init();
+    
+    /* Try default image */
+    autoboot();
+
+    /* The above didn't work, ask user */
+    while (havechar())
+	getchar();
+#ifdef CONFIG_AUTOBOOT_FILE
+    strncpy(line, CONFIG_AUTOBOOT_FILE, sizeof(line)-1);
+    line[sizeof(line)-1] = '\0';
+#else
+    line[0] = '\0';
+#endif
+    for (;;) {
+	printf("boot: ");
+	getline(line, sizeof line);
+
+	if (strcmp(line,"quit")==0) break;
+
+	if (line[0])
+	    boot(line);
+    }
+
+    return 0;
+}
+
+#endif /* CONFIG_USE_GRUB */

Added: trunk/filo/main/grub/Makefile.inc
===================================================================
--- trunk/filo/main/grub/Makefile.inc	                        (rev 0)
+++ trunk/filo/main/grub/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2008 by coresystems GmbH 
+# 
+# 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.
+#
+
+
+TARGETS-$(CONFIG_USE_GRUB) += main/grub/stage2.o main/grub/builtins.o 
+TARGETS-$(CONFIG_USE_GRUB) += main/grub/cmdline.o main/grub/char_io.o 
+TARGETS-$(CONFIG_USE_GRUB) += main/grub/grubcons.o main/grub/serial.o
+TARGETS-$(CONFIG_USE_GRUB) += main/grub/terminfo.o main/grub/tparm.o 
+TARGETS-$(CONFIG_USE_GRUB) += main/grub/asmstub.o main/grub/completions.o
+TARGETS-$(CONFIG_USE_MD5_PASSWORDS) += main/grub/md5.o
+

Added: trunk/filo/main/grub/asmstub.c
===================================================================
--- trunk/filo/main/grub/asmstub.c	                        (rev 0)
+++ trunk/filo/main/grub/asmstub.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,24 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+unsigned long install_partition = 0x20000;
+unsigned long boot_drive = 0;
+int saved_entryno = 0;
+char version_string[] = "1.0";
+char config_file[128] = "\0"; 
+

Added: trunk/filo/main/grub/builtins.c
===================================================================
--- trunk/filo/main/grub/builtins.c	                        (rev 0)
+++ trunk/filo/main/grub/builtins.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1285 @@
+/*
+ * This file is part of FILO.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#include <libpayload.h>
+#include <config.h>
+#define printf grub_printf
+#include <grub/shared.h>
+#include <grub/term.h>
+#include <grub/terminfo.h>
+#include <grub/serial.h>
+#ifdef CONFIG_USE_MD5_PASSWORDS
+#include <grub/md5.h>
+#endif
+
+/* The default entry.  */
+int default_entry = 0;
+
+int current_entryno;
+
+// from disk_io:
+int buf_drive = -1;
+unsigned long current_drive = GRUB_INVALID_DRIVE;
+// from common.c:
+unsigned long saved_drive;
+unsigned long saved_partition;
+unsigned long saved_mem_upper;
+
+
+kernel_t kernel_type;
+
+/* The fallback entry.  */
+int fallback_entryno;
+int fallback_entries[MAX_FALLBACK_ENTRIES];
+
+int grub_timeout = -1;
+
+
+/* The password.  */
+char *password;
+/* The password type.  */
+password_t password_type;
+/* The flag for indicating that the user is authoritative.  */
+int auth = 0;
+
+/* -------- FILO logic -------- */
+char boot_line[1024]={0};
+char root_device[16]={0};
+/* ---------------------------- */
+
+int show_menu = 1;
+
+/* Initialize the data for builtins.  */
+void
+init_builtins (void)
+{
+  kernel_type = KERNEL_TYPE_NONE;
+  /* BSD and chainloading evil hacks!  */
+  //bootdev = set_bootdev (0);
+  //mb_cmdline = (char *) MB_CMDLINE_BUF;
+}
+
+/* Initialize the data for the configuration file.  */
+void
+init_config (void)
+{
+  default_entry = 0;
+  password = 0;
+  fallback_entryno = -1;
+  fallback_entries[0] = -1;
+  grub_timeout = -1;
+}
+
+
+int
+check_password (char *entered, char* expected, password_t type)
+{
+  switch (type)
+    {
+    case PASSWORD_PLAIN:
+      return strcmp (entered, expected);
+
+#ifdef CONFIG_USE_MD5_PASSWORDS
+    case PASSWORD_MD5:
+      return check_md5_password (entered, expected);
+#endif
+    default:
+      /* unsupported password type: be secure */
+      return 1;
+    }
+}
+
+/* boot */
+static int
+boot_func (char *arg, int flags)
+{
+  void boot(const char *line);
+  cls();
+  grub_printf("\nBooting '%s'\n", boot_line);
+  boot(boot_line);
+  return 1;
+}
+
+static struct builtin builtin_boot =
+{
+  "boot",
+  boot_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "boot",
+  "Boot the OS/chain-loader which has been loaded."
+};
+
+
+/* color */
+/* Set new colors used for the menu interface. Support two methods to
+ *    specify a color name: a direct integer representation and a symbolic
+ *       color name. An example of the latter is "blink-light-gray/blue".  */
+static int
+color_func (char *arg, int flags)
+{
+  char *normal;
+  char *highlight;
+  int new_normal_color;
+  int new_highlight_color;
+  static char *color_list[16] =
+  {
+    "black",
+    "blue",
+    "green",
+    "cyan",
+    "red",
+    "magenta",
+    "brown",
+    "light-gray",
+    "dark-gray",
+    "light-blue",
+    "light-green",
+    "light-cyan",
+    "light-red",
+    "light-magenta",
+    "yellow",
+    "white"
+  };
+
+  auto int color_number (char *str);
+
+  /* Convert the color name STR into the magical number.  */
+  auto int color_number (char *str)
+    {
+      char *ptr;
+      int i;
+      int color = 0;
+
+      /* Find the separator.  */
+      for (ptr = str; *ptr && *ptr != '/'; ptr++)
+        ;
+
+      /* If not found, return -1.  */
+      if (! *ptr)
+        return -1;
+
+      /* Terminate the string STR.  */
+      *ptr++ = 0;
+
+      /* If STR contains the prefix "blink-", then set the `blink' bit in COLOR.  */
+      if (substring ("blink-", str) <= 0)
+        {
+          color = 0x80;
+          str += 6;
+        }
+
+      /* Search for the color name.  */
+      for (i = 0; i < 16; i++)
+        if (grub_strcmp (color_list[i], str) == 0)
+          {
+            color |= i;
+            break;
+          }
+
+      if (i == 16)
+        return -1;
+
+      str = ptr;
+      nul_terminate (str);
+
+      /* Search for the color name.  */
+      for (i = 0; i < 8; i++)
+        if (grub_strcmp (color_list[i], str) == 0)
+          {
+            color |= i << 4;
+            break;
+          }
+
+      if (i == 8)
+        return -1;
+
+      return color;
+    }
+
+  normal = arg;
+  highlight = skip_to (0, arg);
+
+  new_normal_color = color_number (normal);
+  if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
+    return 1;
+
+  /* The second argument is optional, so set highlight_color to inverted NORMAL_COLOR.  */
+  if (! *highlight)
+    new_highlight_color = ((new_normal_color >> 4)
+                           | ((new_normal_color & 0xf) << 4));
+  else
+    {
+      new_highlight_color = color_number (highlight);
+      if (new_highlight_color < 0
+          && ! safe_parse_maxint (&highlight, &new_highlight_color))
+        return 1;
+    }
+
+  if (current_term->setcolor)
+    current_term->setcolor (new_normal_color, new_highlight_color);
+
+  return 0;
+}
+
+static struct builtin builtin_color =
+{
+  "color",
+  color_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "color NORMAL [HIGHLIGHT]",
+  "Change the menu colors. The color NORMAL is used for most"
+  " lines in the menu, and the color HIGHLIGHT is used to highlight the"
+  " line where the cursor points. If you omit HIGHLIGHT, then the"
+  " inverted color of NORMAL is used for the highlighted line."
+  " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
+  " A symbolic color name must be one of these: black, blue, green,"
+  " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
+  " light-green, light-cyan, light-red, light-magenta, yellow and white."
+  " But only the first eight names can be used for BG. You can prefix"
+  " \"blink-\" to FG if you want a blinking foreground color."
+};
+
+/* default */
+static int
+default_func (char *arg, int flags)
+{
+  if (! safe_parse_maxint (&arg, &default_entry))
+    return 1;
+
+  return 0;
+}
+
+static struct builtin builtin_default =
+{
+  "default",
+  default_func,
+  BUILTIN_MENU,
+#if 0
+  "default [NUM]",
+  "Set the default entry to entry number NUM (if not specified, it is"
+  " 0, the first entry) or the entry number saved by savedefault."
+#endif
+};
+
+/* nvram-default */
+static int
+nvram_default_func (char *arg, int flags)
+{
+  u8 boot_default;
+
+  if (get_option(&boot_default, "boot_default"))
+    return 1;
+
+  default_entry = boot_default;
+
+  return 0;
+}
+
+static struct builtin builtin_nvram_default =
+{
+  "nvram-default",
+  nvram_default_func,
+  BUILTIN_MENU,
+#if 0
+  "default [NUM]",
+  "Set the default entry to entry number NUM (if not specified, it is"
+  " 0, the first entry) or the entry number saved by savedefault."
+#endif
+};
+
+#if CONFIG_EXPERIMENTAL
+#warning "FIND not implemented yet."
+/* find */
+/* Search for the filename ARG in all of partitions.  */
+static int
+find_func (char *arg, int flags)
+{
+  char *filename = arg;
+  int got_file = 0;
+
+  // the grub find works like this:
+  // 
+  // for all disks
+  //   for all partitions on disk
+  //     open file
+  //     if file exists
+  //        print partition name
+  //        set got_file to 1
+  //
+  // dont they search all subdirectories? Thats a dumb find then.. :(
+
+  /* We want to ignore any error here.  */
+  errnum = ERR_NONE;
+  
+  if (got_file)
+    {
+      errnum = ERR_NONE;
+      return 0;
+    }
+
+  errnum = ERR_FILE_NOT_FOUND;
+  return 1;
+}
+
+static struct builtin builtin_find =
+{
+  "find",
+  find_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "find FILENAME",
+  "Search for the filename FILENAME in all of partitions and print the list of"
+  " the devices which contain the file."
+};
+#endif
+
+/* help */
+#define MAX_SHORT_DOC_LEN       39
+#define MAX_LONG_DOC_LEN        66
+
+static int
+help_func (char *arg, int flags)
+{
+  int all = 0;
+
+  if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
+    {
+      all = 1;
+      arg = skip_to (0, arg);
+    }
+
+  if (! *arg)
+    {
+      /* Invoked with no argument. Print the list of the short docs.  */
+      struct builtin **builtin;
+      int left = 1;
+
+      for (builtin = builtin_table; *builtin != 0; builtin++)
+        {
+          int len;
+          int i;
+
+          /* If this cannot be used in the command-line interface,
+               skip this.  */
+          if (! ((*builtin)->flags & BUILTIN_CMDLINE))
+            continue;
+
+          /* If this doesn't need to be listed automatically and "--all"
+               is not specified, skip this.  */
+          if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
+            continue;
+
+          len = grub_strlen ((*builtin)->short_doc);
+          /* If the length of SHORT_DOC is too long, truncate it.  */
+          if (len > MAX_SHORT_DOC_LEN - 1)
+            len = MAX_SHORT_DOC_LEN - 1;
+
+          for (i = 0; i < len; i++)
+            grub_putchar ((*builtin)->short_doc[i]);
+
+          for (; i < MAX_SHORT_DOC_LEN; i++)
+            grub_putchar (' ');
+
+
+          if (! left)
+            grub_putchar ('\n');
+
+          left = ! left;
+        }
+
+      /* If the last entry was at the left column, no newline was printed
+           at the end.  */
+      if (! left)
+        grub_putchar ('\n');
+    }
+  else
+    {
+      /* Invoked with one or more patterns.  */
+      do
+        {
+          struct builtin **builtin;
+          char *next_arg;
+
+          /* Get the next argument.  */
+          next_arg = skip_to (0, arg);
+
+          /* Terminate ARG.  */
+          nul_terminate (arg);
+
+          for (builtin = builtin_table; *builtin; builtin++)
+            {
+              /* Skip this if this is only for the configuration file.  */
+              if (! ((*builtin)->flags & BUILTIN_CMDLINE))
+                continue;
+
+              if (substring (arg, (*builtin)->name) < 1)
+                {
+                  char *doc = (*builtin)->long_doc;
+
+                  /* At first, print the name and the short doc.  */
+                  grub_printf ("%s: %s\n",
+                               (*builtin)->name, (*builtin)->short_doc);
+
+                  /* Print the long doc.  */
+                  while (*doc)
+                    {
+                      int len = grub_strlen (doc);
+                      int i;
+
+                      /* If LEN is too long, fold DOC.  */
+                      if (len > MAX_LONG_DOC_LEN)
+                        {
+                          /* Fold this line at the position of a space.  */
+                          for (len = MAX_LONG_DOC_LEN; len > 0; len--)
+                            if (doc[len - 1] == ' ')
+                              break;
+                        }
+
+                      grub_printf ("    ");
+                      for (i = 0; i < len; i++)
+                        grub_putchar (*doc++);
+                      grub_putchar ('\n');
+                    }
+                }
+            }
+
+          arg = next_arg;
+        }
+      while (*arg);
+    }
+
+  return 0;
+}
+
+static struct builtin builtin_help =
+{
+  "help",
+  help_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "help [--all] [PATTERN ...]",
+  "Display helpful information about builtin commands. Not all commands"
+  " aren't shown without the option `--all'."
+};
+
+/* hiddenmenu */
+static int
+hiddenmenu_func (char *arg, int flags)
+{
+  show_menu = 0;
+  return 0;
+}
+
+static struct builtin builtin_hiddenmenu =
+{
+  "hiddenmenu",
+  hiddenmenu_func,
+  BUILTIN_MENU,
+#if 0
+  "hiddenmenu",
+  "Hide the menu."
+#endif
+};
+
+
+/* initrd */
+static int
+initrd_func (char *arg, int flags)
+{
+	char dummy[16]={0};
+	int disk, part;
+	if(arg[0]=='(' && arg[1]=='h' && arg[2]=='d') {
+		disk=arg[3]-'0';
+		part=arg[5]-'0';
+		arg+=7; // FIXME only 9 disks with 9 partitions for booting
+		sprintf(dummy, "hd%c%c:", disk+'a', part+'1');
+	}
+	strncat(boot_line," initrd=", 1000);
+	if(dummy[0]) strncat(boot_line,dummy, 1000);
+	grub_strncat(boot_line,arg, 1000);
+	
+	return 0;
+}
+
+static struct builtin builtin_initrd =
+{
+  "initrd",
+  initrd_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "initrd FILE [ARG ...]",
+  "Load an initial ramdisk FILE for a Linux format boot image and set the"
+  " appropriate parameters in the Linux setup area in memory."
+};
+
+
+
+
+/* kernel */
+static int
+kernel_func (char *arg, int flags)
+{
+	int disk,part;
+	/* Needed to pass grub checks */
+	kernel_type=KERNEL_TYPE_LINUX;
+	if(arg[0]=='(' && arg[1]=='h' && arg[2]=='d') {
+		disk=arg[3]-'0';
+		part=arg[5]-'0';
+		arg+=7; // FIXME only 9 disks with 9 partitions for booting
+		sprintf(boot_line, "hd%c%c:", disk+'a', part+'1');
+	} else if (root_device[0]=='h' && root_device[1]=='d') {
+		strcpy(boot_line, root_device);
+	}
+	
+	strncat(boot_line, arg, 1000);
+	
+	return 0;
+}
+
+static struct builtin builtin_kernel =
+{
+  "kernel",
+  kernel_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
+  "Attempt to load the primary boot image from FILE. The rest of the"
+  " line is passed verbatim as the \"kernel command line\".  Any modules"
+  " must be reloaded after using this command. The option --type is used"
+  " to suggest what type of kernel to be loaded. TYPE must be either of"
+  " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
+  " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
+  " Linux's mem option automatically."
+};
+
+/* lock */
+static int
+lock_func (char *arg, int flags)
+{
+  if (! auth && password)
+    {
+      errnum = ERR_PRIVILEGED;
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct builtin builtin_lock =
+{
+  "lock",
+  lock_func,
+  BUILTIN_CMDLINE,
+  "lock",
+  "Break a command execution unless the user is authenticated."
+};
+
+#ifdef CONFIG_USE_MD5_PASSWORDS
+/* md5crypt */
+static int
+md5crypt_func (char *arg, int flags)
+{
+  char crypted[36];
+  char key[32];
+  unsigned int seed;
+  int i;
+  const char *const seedchars =
+    "./0123456789ABCDEFGHIJKLMNOPQRST"
+    "UVWXYZabcdefghijklmnopqrstuvwxyz";
+
+  /* First create a salt.  */
+
+  /* The magical prefix.  */
+  memset (crypted, 0, sizeof (crypted));
+  memmove (crypted, "$1$", 3);
+
+  /* Create the length of a salt.  */
+  seed = currticks ();
+
+  /* Generate a salt.  */
+  for (i = 0; i < 8 && seed; i++)
+    {
+      /* FIXME: This should be more random.  */
+      crypted[3 + i] = seedchars[seed & 0x3f];
+      seed >>= 6;
+    }
+
+  /* A salt must be terminated with `$', if it is less than 8 chars.  */
+  crypted[3 + i] = '$';
+
+#ifdef CONFIG_DEBUG_MD5CRYPT
+  grub_printf ("salt = %s\n", crypted);
+#endif
+
+  /* Get a password.  */
+  memset (key, 0, sizeof (key));
+  get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
+
+  /* Crypt the key.  */
+  make_md5_password (key, crypted);
+
+  grub_printf ("Encrypted: %s\n", crypted);
+  return 0;
+}
+
+static struct builtin builtin_md5crypt =
+{
+  "md5crypt",
+  md5crypt_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "md5crypt",
+  "Generate a password in MD5 format."
+};
+#endif /* CONFIG_USE_MD5_PASSWORDS */
+
+/* password */
+static int
+password_func (char *arg, int flags)
+{
+  int len;
+  password_t type = PASSWORD_PLAIN;
+
+#ifdef CONFIG_USE_MD5_PASSWORDS
+  if (grub_memcmp (arg, "--md5", 5) == 0)
+    {
+      type = PASSWORD_MD5;
+      arg = skip_to (0, arg);
+    }
+#endif
+  if (grub_memcmp (arg, "--", 2) == 0)
+    {
+      type = PASSWORD_UNSUPPORTED;
+      arg = skip_to (0, arg);
+    }
+
+  if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
+    {
+      /* Do password check! */
+      char entered[32];
+
+      /* Wipe out any previously entered password */
+      entered[0] = 0;
+      get_cmdline ("Password: ", entered, 31, '*', 0);
+
+      nul_terminate (arg);
+      if (check_password (entered, arg, type) != 0)
+        {
+          errnum = ERR_PRIVILEGED;
+          return 1;
+        }
+    }
+  else
+    {
+      len = grub_strlen (arg);
+
+      /* PASSWORD NUL NUL ... */
+      if (len + 2 > PASSWORD_BUFLEN)
+        {
+          errnum = ERR_WONT_FIT;
+          return 1;
+        }
+
+      /* Copy the password and clear the rest of the buffer.  */
+      password = (char *) PASSWORD_BUF;
+      memmove (password, arg, len);
+      memset (password + len, 0, PASSWORD_BUFLEN - len);
+      password_type = type;
+    }
+  return 0;
+}
+
+static struct builtin builtin_password =
+{
+  "password",
+  password_func,
+  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
+  "password [--md5] PASSWD [FILE]",
+  "If used in the first section of a menu file, disable all"
+  " interactive editing control (menu entry editor and"
+  " command line). If the password PASSWD is entered, it loads the"
+  " FILE as a new config file and restarts the GRUB Stage 2. If you"
+  " omit the argument FILE, then GRUB just unlocks privileged"
+  " instructions.  You can also use it in the script section, in"
+  " which case it will ask for the password, before continueing."
+  " The option --md5 tells GRUB that PASSWD is encrypted with"
+  " md5crypt."
+};
+
+/* pause */
+static int
+pause_func (char *arg, int flags)
+{
+  printf("%s\n", arg);
+
+  /* If ESC is returned, then abort this entry.  */
+  if (ASCII_CHAR (getkey ()) == 27)
+    return 1;
+
+  return 0;
+}
+
+static struct builtin builtin_pause =
+{
+  "pause",
+  pause_func,
+  BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
+  "pause [MESSAGE ...]",
+  "Print MESSAGE, then wait until a key is pressed."
+};
+
+
+static int
+root_func (char *arg, int flags)
+{
+  int disk, part;
+
+  if(arg[0]!='(') return 1;
+  if(arg[1]!='h') return 1;
+  if(arg[2]!='d') return 1;
+  disk=arg[3]-'0';
+  part=arg[5]-'0';
+  sprintf(root_device, "hd%c%c:", disk+'a', part+'1');
+  return 0;
+}
+
+static struct builtin builtin_root =
+{
+  "root",
+  root_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "root [DEVICE [HDBIAS]]",
+  "Set the current \"root device\" to the device DEVICE, then"
+  " attempt to mount it to get the partition size (for passing the"
+  " partition descriptor in `ES:ESI', used by some chain-loaded"
+  " bootloaders), the BSD drive-type (for booting BSD kernels using"
+  " their native boot format), and correctly determine "
+  " the PC partition where a BSD sub-partition is located. The"
+  " optional HDBIAS parameter is a number to tell a BSD kernel"
+  " how many BIOS drive numbers are on controllers before the current"
+  " one. For example, if there is an IDE disk and a SCSI disk, and your"
+  " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
+};
+
+/* serial */
+static int
+serial_func (char *arg, int flags)
+{
+  unsigned short port = serial_hw_get_port (0);
+  unsigned int speed = 9600;
+  int word_len = UART_8BITS_WORD;
+  int parity = UART_NO_PARITY;
+  int stop_bit_len = UART_1_STOP_BIT;
+
+  /* Process GNU-style long options.
+     FIXME: We should implement a getopt-like function, to avoid
+     duplications.  */
+  while (1)
+    {
+      if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--unit=") - 1;
+	  int unit;
+	  
+	  if (! safe_parse_maxint (&p, &unit))
+	    return 1;
+	  
+	  if (unit < 0 || unit > 3)
+	    {
+	      errnum = ERR_DEV_VALUES;
+	      return 1;
+	    }
+
+	  port = serial_hw_get_port (unit);
+	}
+      else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--speed=") - 1;
+	  int num;
+	  
+	  if (! safe_parse_maxint (&p, &num))
+	    return 1;
+
+	  speed = (unsigned int) num;
+	}
+      else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--port=") - 1;
+	  int num;
+	  
+	  if (! safe_parse_maxint (&p, &num))
+	    return 1;
+
+	  port = (unsigned short) num;
+	}
+      else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--word=") - 1;
+	  int len;
+	  
+	  if (! safe_parse_maxint (&p, &len))
+	    return 1;
+
+	  switch (len)
+	    {
+	    case 5: word_len = UART_5BITS_WORD; break;
+	    case 6: word_len = UART_6BITS_WORD; break;
+	    case 7: word_len = UART_7BITS_WORD; break;
+	    case 8: word_len = UART_8BITS_WORD; break;
+	    default:
+	      errnum = ERR_BAD_ARGUMENT;
+	      return 1;
+	    }
+	}
+      else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--stop=") - 1;
+	  int len;
+	  
+	  if (! safe_parse_maxint (&p, &len))
+	    return 1;
+
+	  switch (len)
+	    {
+	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
+	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
+	    default:
+	      errnum = ERR_BAD_ARGUMENT;
+	      return 1;
+	    }
+	}
+      else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--parity=") - 1;
+
+	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
+	    parity = UART_NO_PARITY;
+	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
+	    parity = UART_ODD_PARITY;
+	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
+	    parity = UART_EVEN_PARITY;
+	  else
+	    {
+	      errnum = ERR_BAD_ARGUMENT;
+	      return 1;
+	    }
+	}
+# ifdef GRUB_UTIL
+      /* In the grub shell, don't use any port number but open a tty
+	 device instead.  */
+      else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
+	{
+	  char *p = arg + sizeof ("--device=") - 1;
+	  char dev[256];	/* XXX */
+	  char *q = dev;
+	  
+	  while (*p && ! grub_isspace (*p))
+	    *q++ = *p++;
+	  
+	  *q = 0;
+	  serial_set_device (dev);
+	}
+# endif /* GRUB_UTIL */
+      else
+	break;
+
+      arg = skip_to (0, arg);
+    }
+
+  /* Initialize the serial unit.  */
+  if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
+    {
+      errnum = ERR_BAD_ARGUMENT;
+      return 1;
+    }
+  
+  return 0;
+}
+
+static struct builtin builtin_serial =
+{
+  "serial",
+  serial_func,
+  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO,
+  "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
+  "Initialize a serial device. UNIT is a digit that specifies which serial"
+  " device is used (e.g. 0 == COM1). If you need to specify the port number,"
+  " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
+  " PARITY is the type of parity, which is one of `no', `odd' and `even'."
+  " STOP is the length of stop bit(s). The option --device can be used only"
+  " in the grub shell, which specifies the file name of a tty device. The"
+  " default values are COM1, 9600, 8N1."
+};
+
+
+
+/* terminal */
+static int
+terminal_func (char *arg, int flags)
+{
+  /* The index of the default terminal in TERM_TABLE.  */
+  int default_term = -1;
+  struct term_entry *prev_term = current_term;
+  int to = -1;
+  int lines = 0;
+  int no_message = 0;
+  unsigned long term_flags = 0;
+  /* XXX: Assume less than 32 terminals.  */
+  unsigned long term_bitmap = 0;
+
+  /* Get GNU-style long options.  */
+  while (1)
+    {
+      if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
+        term_flags |= TERM_DUMB;
+      else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
+        /* ``--no-echo'' implies ``--no-edit''.  */
+        term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
+      else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
+        term_flags |= TERM_NO_EDIT;
+      else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
+        {
+          char *val = arg + sizeof ("--timeout=") - 1;
+
+          if (! safe_parse_maxint (&val, &to))
+            return 1;
+        }
+      else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
+        {
+          char *val = arg + sizeof ("--lines=") - 1;
+
+          if (! safe_parse_maxint (&val, &lines))
+            return 1;
+
+          /* Probably less than four is meaningless....  */
+          if (lines < 4)
+            {
+              errnum = ERR_BAD_ARGUMENT;
+              return 1;
+            }
+        }
+      else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
+        no_message = 1;
+      else {
+        while (*arg)
+          {
+            int i;
+            char *next = skip_to (0, arg);
+      
+            nul_terminate (arg);
+	    
+            for (i = 0; term_table[i].name; i++)
+              {
+                if (grub_strcmp (arg, term_table[i].name) == 0)
+                  {
+                    if (term_table[i].flags & TERM_NEED_INIT)
+                      {
+                        errnum = ERR_DEV_NEED_INIT;
+                        return 1;
+                      }
+      
+                    if (default_term < 0)
+                      default_term = i;
+      
+                    term_bitmap |= (1 << i);
+                    break;
+                  }
+              }
+      
+            if (! term_table[i].name)
+              {
+                errnum = ERR_BAD_ARGUMENT;
+                return 1;
+              }
+      
+            arg = next;
+            break;
+          }
+	if (!*arg) break;
+	continue;
+      }
+
+      arg = skip_to (0, arg);
+    }
+
+  /* If no argument is specified, show current setting.  */
+  // if (! *arg)
+  if (! term_bitmap)
+    {
+      grub_printf ("%s%s%s%s\n",
+                   current_term->name,
+                   current_term->flags & TERM_DUMB ? " (dumb)" : "",
+                   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
+                   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
+      return 0;
+    }
+
+  /* If multiple terminals are specified, wait until the user pushes any key on one of the terminals.  */
+  if (term_bitmap & ~(1 << default_term))
+    {
+      int time1, time2 = -1;
+
+      /* XXX: Disable the pager.  */
+      count_lines = -1;
+
+      /* Get current time.  */
+      while ((time1 = getrtsecs ()) == 0xFF)
+        ;
+
+      /* Wait for a key input.  */
+      while (to)
+        {
+          int i;
+
+          for (i = 0; term_table[i].name; i++)
+            {
+              if (term_bitmap & (1 << i))
+                {
+                  if (term_table[i].checkkey () >= 0)
+                    {
+                      (void) term_table[i].getkey ();
+                      default_term = i;
+
+                      goto end;
+                    }
+                }
+            }
+
+          /* Prompt the user, once per sec.  */
+          if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
+            {
+              if (! no_message)
+                {
+                  /* Need to set CURRENT_TERM to each of selected terminals.  */
+                  for (i = 0; term_table[i].name; i++)
+                    if (term_bitmap & (1 << i))
+                      {
+                        current_term = term_table + i;
+                        grub_printf ("\rPress any key to continue.\n");
+                      }
+
+                  /* Restore CURRENT_TERM.  */
+                  current_term = prev_term;
+                }
+
+              time2 = time1;
+              if (to > 0)
+                to--;
+            }
+        }
+    } 
+
+ end:
+  current_term = term_table + default_term;
+  current_term->flags = term_flags;
+
+  if (lines)
+    max_lines = lines;
+  else
+    /* 24 would be a good default value.  */
+    max_lines = 24;
+
+  /* If the interface is currently the command-line, restart it to repaint the screen. */
+  //if (current_term != prev_term && (flags & BUILTIN_CMDLINE))
+  //  grub_longjmp (restart_cmdline_env, 0);
+
+  return 0;
+}
+
+static struct builtin builtin_terminal =
+{
+  "terminal",
+  terminal_func,
+  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_NO_ECHO,
+  "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial]",
+  "Select a terminal. When multiple terminals are specified, wait until"
+  " you push any key to continue. If both console and serial are specified,"
+  " the terminal to which you input a key first will be selected. If no"
+  " argument is specified, print current setting. The option --dumb"
+  " specifies that your terminal is dumb, otherwise, vt100-compatibility"
+  " is assumed. If you specify --no-echo, input characters won't be echoed."
+  " If you specify --no-edit, the BASH-like editing feature will be disabled."
+  " If --timeout is present, this command will wait at most for SECS"
+  " seconds. The option --lines specifies the maximum number of lines."
+  " The option --silent is used to suppress messages."
+};
+
+static int
+terminfo_func (char *arg, int flags)
+{
+  struct terminfo term;
+
+  if (*arg)
+    {
+      struct
+      {
+        const char *name;
+        char *var;
+      }
+      options[] =
+        {
+          {"--name=", term.name},
+          {"--cursor-address=", term.cursor_address},
+          {"--clear-screen=", term.clear_screen},
+          {"--enter-standout-mode=", term.enter_standout_mode},
+          {"--exit-standout-mode=", term.exit_standout_mode}
+        };
+
+      memset (&term, 0, sizeof (term));
+
+      while (*arg)
+        {
+          int i;
+          char *next = skip_to (0, arg);
+
+          nul_terminate (arg);
+
+          for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
+            {
+              const char *name = options[i].name;
+              int len = grub_strlen (name);
+
+              if (! grub_memcmp (arg, name, len))
+                {
+                  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
+                  break;
+                }
+            }
+          if (i == sizeof (options) / sizeof (options[0]))
+            {
+              errnum = ERR_BAD_ARGUMENT;
+              return errnum;
+            }
+
+          arg = next;
+        }
+
+      if (term.name[0] == 0 || term.cursor_address[0] == 0)
+        {
+          errnum = ERR_BAD_ARGUMENT;
+          return errnum;
+        }
+
+      ti_set_term (&term);
+    }
+  else
+    {
+      /* No option specifies printing out current settings.  */
+      ti_get_term (&term);
+
+      grub_printf ("name=%s\n",
+                   ti_escape_string (term.name));
+      grub_printf ("cursor_address=%s\n",
+                   ti_escape_string (term.cursor_address));
+      grub_printf ("clear_screen=%s\n",
+                   ti_escape_string (term.clear_screen));
+      grub_printf ("enter_standout_mode=%s\n",
+                   ti_escape_string (term.enter_standout_mode));
+      grub_printf ("exit_standout_mode=%s\n",
+                   ti_escape_string (term.exit_standout_mode));
+    }
+
+  return 0;
+}
+
+
+static struct builtin builtin_terminfo =
+{
+  "terminfo",
+  terminfo_func,
+  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
+  " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
+
+  "Define the capabilities of your terminal. Use this command to"
+  " define escape sequences, if it is not vt100-compatible."
+  " You may use \\e for ESC and ^X for a control character."
+  " If no option is specified, the current settings are printed."
+};
+
+
+
+/* timeout */
+static int
+timeout_func (char *arg, int flags)
+{
+  if (! safe_parse_maxint (&arg, &grub_timeout))
+    return 1;
+
+  return 0;
+}
+
+static struct builtin builtin_timeout =
+{
+  "timeout",
+  timeout_func,
+  BUILTIN_MENU,
+#if 0
+  "timeout SEC",
+  "Set a timeout, in SEC seconds, before automatically booting the"
+  " default entry (normally the first entry defined)."
+#endif
+};
+
+
+
+static int
+title_func (char *arg, int flags)
+{
+  /* This function is not actually used at least currently.  */
+  return 0;
+}
+
+static struct builtin builtin_title =
+{
+  "title",
+  title_func,
+  BUILTIN_TITLE,
+#if 0
+  "title [NAME ...]",
+  "Start a new boot entry, and set its name to the contents of the"
+  " rest of the line, starting with the first non-space character."
+#endif
+};
+
+
+/* README !!! XXX !!! This list has to be alphabetically ordered !!! */
+
+struct builtin *builtin_table[] =
+{
+	&builtin_boot,
+	&builtin_color,
+	&builtin_default,
+#ifdef CONFIG_EXPERIMENTAL
+	&builtin_find,
+#endif
+	&builtin_help,
+	&builtin_hiddenmenu,
+	&builtin_initrd,
+	&builtin_kernel,
+	&builtin_lock,
+#ifdef CONFIG_USE_MD5_PASSWORDS
+	&builtin_md5crypt,
+#endif
+	&builtin_nvram_default,
+	&builtin_password,
+	&builtin_pause,
+	&builtin_root,
+	&builtin_serial,
+	&builtin_terminal,
+	&builtin_terminfo,
+	&builtin_timeout,
+	&builtin_title,
+	0
+};
+

Added: trunk/filo/main/grub/char_io.c
===================================================================
--- trunk/filo/main/grub/char_io.c	                        (rev 0)
+++ trunk/filo/main/grub/char_io.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1018 @@
+/* char_io.c - basic console input and output */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004  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 <libpayload.h>
+#include <config.h>
+#include <version.h>
+#include <grub/shared.h>
+#include <grub/term.h>
+#include <grub/serial.h>
+
+char *err_list[] =
+{
+  [ERR_NONE] = 0,
+  [ERR_BAD_ARGUMENT] = "Invalid argument",
+  [ERR_BAD_FILENAME] = "Filename must be either an absolute pathname or blocklist",
+  [ERR_BAD_FILETYPE] = "Bad file or directory type",
+  [ERR_BAD_GZIP_DATA] = "Bad or corrupt data while decompressing file",
+  [ERR_BAD_GZIP_HEADER] = "Bad or incompatible header in compressed file",
+  [ERR_BAD_PART_TABLE] = "Partition table invalid or corrupt",
+  [ERR_BAD_VERSION] = "Mismatched or corrupt version of stage1/stage2",
+  [ERR_BELOW_1MB] = "Loading below 1MB is not supported",
+  [ERR_BOOT_COMMAND] = "Kernel must be loaded before booting",
+  [ERR_BOOT_FAILURE] = "Unknown boot failure",
+  [ERR_BOOT_FEATURES] = "Unsupported Multiboot features requested",
+  [ERR_DEV_FORMAT] = "Unrecognized device string",
+  [ERR_DEV_NEED_INIT] = "Device not initialized yet",
+  [ERR_DEV_VALUES] = "Invalid device requested",
+  [ERR_EXEC_FORMAT] = "Invalid or unsupported executable format",
+  [ERR_FILELENGTH] = "Filesystem compatibility error, cannot read whole file",
+  [ERR_FILE_NOT_FOUND] = "File not found",
+  [ERR_FSYS_CORRUPT] = "Inconsistent filesystem structure",
+  [ERR_FSYS_MOUNT] = "Cannot mount selected partition",
+  [ERR_GEOM] = "Selected cylinder exceeds maximum supported by BIOS",
+  [ERR_NEED_LX_KERNEL] = "Linux kernel must be loaded before initrd",
+  [ERR_NEED_MB_KERNEL] = "Multiboot kernel must be loaded before modules",
+  [ERR_NO_DISK] = "Selected disk does not exist",
+  [ERR_NO_DISK_SPACE] = "No spare sectors on the disk",
+  [ERR_NO_PART] = "No such partition",
+  [ERR_NUMBER_OVERFLOW] = "Overflow while parsing number",
+  [ERR_NUMBER_PARSING] = "Error while parsing number",
+  [ERR_OUTSIDE_PART] = "Attempt to access block outside partition",
+  [ERR_PRIVILEGED] = "Must be authenticated",
+  [ERR_READ] = "Disk read error",
+  [ERR_SYMLINK_LOOP] = "Too many symbolic links",
+  [ERR_UNALIGNED] = "File is not sector aligned",
+  [ERR_UNRECOGNIZED] = "Unrecognized command",
+  [ERR_WONT_FIT] = "Selected item cannot fit into memory",
+  [ERR_WRITE] = "Disk write error",
+};
+
+
+
+#ifndef STAGE1_5
+struct term_entry term_table[] =
+  {
+#if CONFIG_VGA_CONSOLE == 1 && CONFIG_PC_KEYBOARD ==1
+    {
+      "console",
+      0,
+      console_putchar,
+      console_checkkey,
+      console_getkey,
+      console_getxy,
+      console_gotoxy,
+      console_cls,
+      console_setcolorstate,
+      console_setcolor,
+      console_setcursor
+    },
+#endif
+    {
+      "serial",
+      /* A serial device must be initialized.  */
+      TERM_NEED_INIT,
+      grub_serial_putchar,
+      serial_checkkey,
+      serial_getkey,
+      serial_getxy,
+      serial_gotoxy,
+      serial_cls,
+      serial_setcolorstate,
+      0,
+      0
+    },
+    /* This must be the last entry.  */
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+  };
+
+/* This must be console.  */
+struct term_entry *current_term = term_table;
+
+int max_lines = 24;
+int count_lines = -1;
+int use_pager = 1;
+#endif
+
+void
+print_error (void)
+{
+  if (errnum > ERR_NONE && errnum < MAX_ERR_NUM)
+#ifndef STAGE1_5
+    /* printf("\7\n %s\n", err_list[errnum]); */
+    printf ("\nError %u: %s\n", errnum, err_list[errnum]);
+#else /* STAGE1_5 */
+    printf ("Error %u\n", errnum);
+#endif /* STAGE1_5 */
+}
+
+char *
+convert_to_ascii (char *buf, int c,...)
+{
+  unsigned long num = *((&c) + 1), mult = 10;
+  char *ptr = buf;
+
+#ifndef STAGE1_5
+  if (c == 'x' || c == 'X')
+    mult = 16;
+
+  if ((num & 0x80000000uL) && c == 'd')
+    {
+      num = (~num) + 1;
+      *(ptr++) = '-';
+      buf++;
+    }
+#endif
+
+  do
+    {
+      int dig = num % mult;
+      *(ptr++) = ((dig > 9) ? dig + 'a' - 10 : '0' + dig);
+    }
+  while (num /= mult);
+
+  /* reorder to correct direction!! */
+  {
+    char *ptr1 = ptr - 1;
+    char *ptr2 = buf;
+    while (ptr1 > ptr2)
+      {
+	int tmp = *ptr1;
+	*ptr1 = *ptr2;
+	*ptr2 = tmp;
+	ptr1--;
+	ptr2++;
+      }
+  }
+
+  return ptr;
+}
+
+void
+grub_putstr (const char *str)
+{
+  while (*str)
+    grub_putchar (*str++);
+}
+
+void
+grub_printf (const char *format,...)
+{
+  int *dataptr = (int *) &format;
+  char c, str[16];
+  
+  dataptr++;
+
+  while ((c = *(format++)) != 0)
+    {
+      if (c != '%')
+	grub_putchar (c);
+      else
+	switch (c = *(format++))
+	  {
+#ifndef STAGE1_5
+	  case 'd':
+	  case 'x':
+	  case 'X':
+#endif
+	  case 'u':
+	    *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0;
+	    grub_putstr (str);
+	    break;
+
+#ifndef STAGE1_5
+	  case 'c':
+	    grub_putchar ((*(dataptr++)) & 0xff);
+	    break;
+
+	  case 's':
+	    grub_putstr ((char *) *(dataptr++));
+	    break;
+#endif
+	  }
+    }
+}
+
+#ifndef STAGE1_5
+void
+init_page (void)
+{
+  cls ();
+  grub_printf ("\n                                  %s %s\n\n", PROGRAM_NAME, PROGRAM_VERSION);
+}
+
+/* The number of the history entries.  */
+static int num_history = 0;
+
+/* Get the NOth history. If NO is less than zero or greater than or
+   equal to NUM_HISTORY, return NULL. Otherwise return a valid string.  */
+static char *
+get_history (int no)
+{
+  if (no < 0 || no >= num_history)
+    return 0;
+
+  return (char *) HISTORY_BUF + MAX_CMDLINE * no;
+}
+
+/* Add CMDLINE to the history buffer.  */
+static void
+add_history (const char *cmdline, int no)
+{
+  grub_memmove ((char *) HISTORY_BUF + MAX_CMDLINE * (no + 1),
+		(char *) HISTORY_BUF + MAX_CMDLINE * no,
+		MAX_CMDLINE * (num_history - no));
+  grub_strcpy ((char *) HISTORY_BUF + MAX_CMDLINE * no, cmdline);
+  if (num_history < HISTORY_SIZE)
+    num_history++;
+}
+
+static int
+real_get_cmdline (char *prompt, char *cmdline, int maxlen,
+		  int echo_char, int readline)
+{
+  /* This is a rather complicated function. So explain the concept.
+     
+     A command-line consists of ``section''s. A section is a part of the
+     line which may be displayed on the screen, but a section is never
+     displayed with another section simultaneously.
+
+     Each section is basically 77 or less characters, but the exception
+     is the first section, which is 78 or less characters, because the
+     starting point is special. See below.
+
+     The first section contains a prompt and a command-line (or the
+     first part of a command-line when it is too long to be fit in the
+     screen). So, in the first section, the number of command-line
+     characters displayed is 78 minus the length of the prompt (or
+     less). If the command-line has more characters, `>' is put at the
+     position 78 (zero-origin), to inform the user of the hidden
+     characters.
+
+     Other sections always have `<' at the first position, since there
+     is absolutely a section before each section. If there is a section
+     after another section, this section consists of 77 characters and
+     `>' at the last position. The last section has 77 or less
+     characters and doesn't have `>'.
+
+     Each section other than the last shares some characters with the
+     previous section. This region is called ``margin''. If the cursor
+     is put at the magin which is shared by the first section and the
+     second, the first section is displayed. Otherwise, a displayed
+     section is switched to another section, only if the cursor is put
+     outside that section.  */
+
+  /* XXX: These should be defined in shared.h, but I leave these here,
+     until this code is freezed.  */
+#define CMDLINE_WIDTH	78
+#define CMDLINE_MARGIN	10
+  
+  int xpos, lpos, c, section;
+  /* The length of PROMPT.  */
+  int plen;
+  /* The length of the command-line.  */
+  int llen;
+  /* The index for the history.  */
+  int history = -1;
+  /* The working buffer for the command-line.  */
+  char *buf = (char *) CMDLINE_BUF;
+  /* The kill buffer.  */
+  char *kill_buf = (char *) KILL_BUF;
+  
+  /* Nested function definitions for code simplicity.  */
+
+  /* The forward declarations of nested functions are prefixed
+     with `auto'.  */
+  auto void cl_refresh (int full, int len);
+  auto void cl_backward (int count);
+  auto void cl_forward (int count);
+  auto void cl_insert (const char *str);
+  auto void cl_delete (int count);
+  auto void cl_init (void);
+  
+  /* Move the cursor backward.  */
+  void cl_backward (int count)
+    {
+      lpos -= count;
+      
+      /* If the cursor is in the first section, display the first section
+	 instead of the second.  */
+      if (section == 1 && plen + lpos < CMDLINE_WIDTH)
+	cl_refresh (1, 0);
+      else if (xpos - count < 1)
+	cl_refresh (1, 0);
+      else
+	{
+	  xpos -= count;
+
+	  if (current_term->flags & TERM_DUMB)
+	    {
+	      int i;
+	      
+	      for (i = 0; i < count; i++)
+		grub_putchar ('\b');
+	    }
+	  else
+	    gotoxy (xpos, getxy () & 0xFF);
+	}
+    }
+
+  /* Move the cursor forward.  */
+  void cl_forward (int count)
+    {
+      lpos += count;
+
+      /* If the cursor goes outside, scroll the screen to the right.  */
+      if (xpos + count >= CMDLINE_WIDTH)
+	cl_refresh (1, 0);
+      else
+	{
+	  xpos += count;
+
+	  if (current_term->flags & TERM_DUMB)
+	    {
+	      int i;
+	      
+	      for (i = lpos - count; i < lpos; i++)
+		{
+		  if (! echo_char)
+		    grub_putchar (buf[i]);
+		  else
+		    grub_putchar (echo_char);
+		}
+	    }
+	  else
+	    gotoxy (xpos, getxy () & 0xFF);
+	}
+    }
+
+  /* Refresh the screen. If FULL is true, redraw the full line, otherwise,
+     only LEN characters from LPOS.  */
+  void cl_refresh (int full, int len)
+    {
+      int i;
+      int start;
+      int pos = xpos;
+      
+      if (full)
+	{
+	  /* Recompute the section number.  */
+	  if (lpos + plen < CMDLINE_WIDTH)
+	    section = 0;
+	  else
+	    section = ((lpos + plen - CMDLINE_WIDTH)
+		       / (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + 1);
+
+	  /* From the start to the end.  */
+	  len = CMDLINE_WIDTH;
+	  pos = 0;
+	  grub_putchar ('\r');
+
+	  /* If SECTION is the first section, print the prompt, otherwise,
+	     print `<'.  */
+	  if (section == 0)
+	    {
+	      grub_printf ("%s", prompt);
+	      len -= plen;
+	      pos += plen;
+	    }
+	  else
+	    {
+	      grub_putchar ('<');
+	      len--;
+	      pos++;
+	    }
+	}
+
+      /* Compute the index to start writing BUF and the resulting position
+	 on the screen.  */
+      if (section == 0)
+	{
+	  int offset = 0;
+	  
+	  if (! full)
+	    offset = xpos - plen;
+	  
+	  start = 0;
+	  xpos = lpos + plen;
+	  start += offset;
+	}
+      else
+	{
+	  int offset = 0;
+	  
+	  if (! full)
+	    offset = xpos - 1;
+	  
+	  start = ((section - 1) * (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN)
+		   + CMDLINE_WIDTH - plen - CMDLINE_MARGIN);
+	  xpos = lpos + 1 - start;
+	  start += offset;
+	}
+
+      /* Print BUF. If ECHO_CHAR is not zero, put it instead.  */
+      for (i = start; i < start + len && i < llen; i++)
+	{
+	  if (! echo_char)
+	    grub_putchar (buf[i]);
+	  else
+	    grub_putchar (echo_char);
+
+	  pos++;
+	}
+      
+      // FIXME
+#if 1
+      /* Fill up the rest of the line with spaces.  */
+      for (; i < start + len; i++)
+	{
+	  grub_putchar (' ');
+	  pos++;
+	}
+      /* If the cursor is at the last position, put `>' or a space,
+	 depending on if there are more characters in BUF.  */
+      if (pos == CMDLINE_WIDTH)
+	{
+	  if (start + len < llen)
+	    grub_putchar ('>');
+	  else
+	    grub_putchar (' ');
+	  
+	  pos++;
+	}
+      
+      /* Back to XPOS.  */
+      if (current_term->flags & TERM_DUMB)
+	{
+	  for (i = 0; i < pos - xpos; i++)
+	    grub_putchar ('\b');
+	}
+      else
+	gotoxy (xpos, getxy () & 0xFF);
+
+#endif
+    }
+
+  /* Initialize the command-line.  */
+  void cl_init (void)
+    {
+#ifdef CONFIG_NEWLINE_BEFORE_EACH_PROMPT
+      /* Distinguish us from other lines and error messages!  */
+      grub_putchar ('\n');
+#endif
+
+      /* Print full line and set position here.  */
+      cl_refresh (1, 0);
+    }
+
+  /* Insert STR to BUF.  */
+  void cl_insert (const char *str)
+    {
+      int l = grub_strlen (str);
+
+      if (llen + l < maxlen)
+	{
+	  if (lpos == llen)
+	    grub_memmove (buf + lpos, str, l + 1);
+	  else
+	    {
+	      grub_memmove (buf + lpos + l, buf + lpos, llen - lpos + 1);
+	      grub_memmove (buf + lpos, str, l);
+	    }
+	  
+	  llen += l;
+	  lpos += l;
+	  if (xpos + l >= CMDLINE_WIDTH)
+	    cl_refresh (1, 0);
+	  else if (xpos + l + llen - lpos > CMDLINE_WIDTH)
+	    cl_refresh (0, CMDLINE_WIDTH - xpos);
+	  else
+	    cl_refresh (0, l + llen - lpos);
+	}
+    }
+
+  /* Delete COUNT characters in BUF.  */
+  void cl_delete (int count)
+    {
+      grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1);
+      llen -= count;
+      
+      if (xpos + llen + count - lpos > CMDLINE_WIDTH)
+	cl_refresh (0, CMDLINE_WIDTH - xpos);
+      else
+	cl_refresh (0, llen + count - lpos);
+    }
+
+  plen = grub_strlen (prompt);
+  llen = grub_strlen (cmdline);
+
+  if (maxlen > MAX_CMDLINE)
+    {
+      maxlen = MAX_CMDLINE;
+      if (llen >= MAX_CMDLINE)
+	{
+	  llen = MAX_CMDLINE - 1;
+	  cmdline[MAX_CMDLINE] = 0;
+	}
+    }
+  lpos = llen;
+  grub_strcpy (buf, cmdline);
+
+  cl_init ();
+
+  while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
+    {
+      /* If READLINE is non-zero, handle readline-like key bindings.  */
+      if (readline)
+	{
+	  switch (c)
+	    {
+	    case 9:		/* TAB lists completions */
+	      {
+		int i;
+		/* POS points to the first space after a command.  */
+		int pos = 0;
+		int ret;
+		char *completion_buffer = (char *) COMPLETION_BUF;
+		int equal_pos = -1;
+		int is_filename;
+
+		/* Find the first word.  */
+		while (buf[pos] == ' ')
+		  pos++;
+		while (buf[pos] && buf[pos] != '=' && buf[pos] != ' ')
+		  pos++;
+
+		is_filename = (lpos > pos);
+
+		/* Find the position of the equal character after a
+		   command, and replace it with a space.  */
+		for (i = pos; buf[i] && buf[i] != ' '; i++)
+		  if (buf[i] == '=')
+		    {
+		      equal_pos = i;
+		      buf[i] = ' ';
+		      break;
+		    }
+
+		/* Find the position of the first character in this
+		   word.  */
+		for (i = lpos; i > 0 && buf[i - 1] != ' '; i--)
+		  ;
+
+		/* Invalidate the cache, because the user may exchange
+		   removable disks.  */
+		buf_drive = -1;
+
+		/* Copy this word to COMPLETION_BUFFER and do the
+		   completion.  */
+		grub_memmove (completion_buffer, buf + i, lpos - i);
+		completion_buffer[lpos - i] = 0;
+		ret = print_completions (is_filename, 1);
+		errnum = ERR_NONE;
+
+		if (ret >= 0)
+		  {
+		    /* Found, so insert COMPLETION_BUFFER.  */
+		    cl_insert (completion_buffer + lpos - i);
+
+		    if (ret > 0)
+		      {
+			/* There are more than one candidates, so print
+			   the list.  */
+			grub_putchar ('\n');
+			print_completions (is_filename, 0);
+			errnum = ERR_NONE;
+		      }
+		  }
+
+		/* Restore the command-line.  */
+		if (equal_pos >= 0)
+		  buf[equal_pos] = '=';
+
+		if (ret)
+		  cl_init ();
+	      }
+	      
+	      break;
+	    case 1:		/* C-a go to beginning of line */
+	      cl_backward (lpos);
+	      break;
+	    case 5:		/* C-e go to end of line */
+	      cl_forward (llen - lpos);
+	      break;
+	    case 6:		/* C-f forward one character */
+	      if (lpos < llen)
+		cl_forward (1);
+	      break;
+	    case 2:		/* C-b backward one character */
+	      if (lpos > 0)
+		cl_backward (1);
+	      break;
+	    case 21:		/* C-u kill to beginning of line */
+	      if (lpos == 0)
+		break;
+	      /* Copy the string being deleted to KILL_BUF.  */
+	      grub_memmove (kill_buf, buf, lpos);
+	      kill_buf[lpos] = 0;
+	      {
+		/* XXX: Not very clever.  */
+		
+		int count = lpos;
+		
+		cl_backward (lpos);
+		cl_delete (count);
+	      }
+	      break;
+	    case 11:		/* C-k kill to end of line */
+	      if (lpos == llen)
+		break;
+	      /* Copy the string being deleted to KILL_BUF.  */
+	      grub_memmove (kill_buf, buf + lpos, llen - lpos + 1);
+	      cl_delete (llen - lpos);
+	      break;
+	    case 25:		/* C-y yank the kill buffer */
+	      cl_insert (kill_buf);
+	      break;
+	    case 16:		/* C-p fetch the previous command */
+	      {
+		char *p;
+
+		if (history < 0)
+		  /* Save the working buffer.  */
+		  grub_strcpy (cmdline, buf);
+		else if (grub_strcmp (get_history (history), buf) != 0)
+		  /* If BUF is modified, add it into the history list.  */
+		  add_history (buf, history);
+
+		history++;
+		p = get_history (history);
+		if (! p)
+		  {
+		    history--;
+		    break;
+		  }
+
+		grub_strcpy (buf, p);
+		llen = grub_strlen (buf);
+		lpos = llen;
+		cl_refresh (1, 0);
+	      }
+	      break;
+	    case 14:		/* C-n fetch the next command */
+	      {
+		char *p;
+
+		if (history < 0)
+		  {
+		    break;
+		  }
+		else if (grub_strcmp (get_history (history), buf) != 0)
+		  /* If BUF is modified, add it into the history list.  */
+		  add_history (buf, history);
+
+		history--;
+		p = get_history (history);
+		if (! p)
+		  p = cmdline;
+
+		grub_strcpy (buf, p);
+		llen = grub_strlen (buf);
+		lpos = llen;
+		cl_refresh (1, 0);
+	      }
+	      break;
+	    }
+	}
+
+      /* ESC, C-d and C-h are always handled. Actually C-d is not
+	 functional if READLINE is zero, as the cursor cannot go
+	 backward, but that's ok.  */
+      switch (c)
+	{
+	case 27:	/* ESC immediately return 1 */
+	  return 1;
+	case 4:		/* C-d delete character under cursor */
+	  if (lpos == llen)
+	    break;
+	  cl_delete (1);
+	  break;
+	case 8:		/* C-h backspace */
+	case 127:	/* also backspace */
+	  if (lpos > 0)
+	    {
+	      cl_backward (1);
+	      cl_delete (1);
+	    }
+	  break;
+	default:		/* insert printable character into line */
+	  if (c >= ' ' && c <= '~')
+	    {
+	      char str[2];
+
+	      str[0] = c;
+	      str[1] = 0;
+	      cl_insert (str);
+	    }
+	}
+    }
+
+  grub_putchar ('\n');
+
+  /* If ECHO_CHAR is NUL, remove the leading spaces.  */
+  lpos = 0;
+  if (! echo_char)
+    while (buf[lpos] == ' ')
+      lpos++;
+
+  /* Copy the working buffer to CMDLINE.  */
+  grub_memmove (cmdline, buf + lpos, llen - lpos + 1);
+
+  /* If the readline-like feature is turned on and CMDLINE is not
+     empty, add it into the history list.  */
+  if (readline && lpos < llen)
+    add_history (cmdline, 0);
+
+  return 0;
+}
+
+/* Don't use this with a MAXLEN greater than 1600 or so!  The problem
+   is that GET_CMDLINE depends on the everything fitting on the screen
+   at once.  So, the whole screen is about 2000 characters, minus the
+   PROMPT, and space for error and status lines, etc.  MAXLEN must be
+   at least 1, and PROMPT and CMDLINE must be valid strings (not NULL
+   or zero-length).
+
+   If ECHO_CHAR is nonzero, echo it instead of the typed character. */
+int
+get_cmdline (char *prompt, char *cmdline, int maxlen,
+	     int echo_char, int readline)
+{
+  int old_cursor;
+  int ret;
+
+  old_cursor = setcursor (1);
+  
+  /* Because it is hard to deal with different conditions simultaneously,
+     less functional cases are handled here. Assume that TERM_NO_ECHO
+     implies TERM_NO_EDIT.  */
+  if (current_term->flags & (TERM_NO_ECHO | TERM_NO_EDIT))
+    {
+      char *p = cmdline;
+      int c;
+      
+      /* Make sure that MAXLEN is not too large.  */
+      if (maxlen > MAX_CMDLINE)
+	maxlen = MAX_CMDLINE;
+
+      /* Print only the prompt. The contents of CMDLINE is simply discarded,
+	 even if it is not empty.  */
+      grub_printf ("%s", prompt);
+
+      /* Gather characters until a newline is gotten.  */
+      while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
+	{
+	  /* Return immediately if ESC is pressed.  */
+	  if (c == 27)
+	    {
+	      setcursor (old_cursor);
+	      return 1;
+	    }
+
+	  /* Printable characters are added into CMDLINE.  */
+	  if (c >= ' ' && c <= '~')
+	    {
+	      if (! (current_term->flags & TERM_NO_ECHO))
+		grub_putchar (c);
+
+	      /* Preceding space characters must be ignored.  */
+	      if (c != ' ' || p != cmdline)
+		*p++ = c;
+	    }
+	}
+
+      *p = 0;
+
+      if (! (current_term->flags & TERM_NO_ECHO))
+	grub_putchar ('\n');
+
+      setcursor (old_cursor);
+      return 0;
+    }
+
+  /* Complicated features are left to real_get_cmdline.  */
+  ret = real_get_cmdline (prompt, cmdline, maxlen, echo_char, readline);
+  setcursor (old_cursor);
+  return ret;
+}
+
+int
+safe_parse_maxint (char **str_ptr, int *myint_ptr)
+{
+  char *ptr = *str_ptr;
+  int myint = 0;
+  int mult = 10, found = 0;
+
+  /*
+   *  Is this a hex number?
+   */
+  if (*ptr == '0' && tolower (*(ptr + 1)) == 'x')
+    {
+      ptr += 2;
+      mult = 16;
+    }
+
+  while (1)
+    {
+      /* A bit tricky. This below makes use of the equivalence:
+	 (A >= B && A <= C) <=> ((A - B) <= (C - B))
+	 when C > B and A is unsigned.  */
+      unsigned int digit;
+
+      digit = tolower (*ptr) - '0';
+      if (digit > 9)
+	{
+	  digit -= 'a' - '0';
+	  if (mult == 10 || digit > 5)
+	    break;
+	  digit += 10;
+	}
+
+      found = 1;
+      if (myint > ((MAXINT - digit) / mult))
+	{
+	  errnum = ERR_NUMBER_OVERFLOW;
+	  return 0;
+	}
+      myint = (myint * mult) + digit;
+      ptr++;
+    }
+
+  if (!found)
+    {
+      errnum = ERR_NUMBER_PARSING;
+      return 0;
+    }
+
+  *str_ptr = ptr;
+  *myint_ptr = myint;
+
+  return 1;
+}
+#endif /* STAGE1_5 */
+
+/* Wait for a keypress and return its code.  */
+int
+getkey (void)
+{
+  return current_term->getkey ();
+}
+
+/* Check if a key code is available.  */
+int
+checkkey (void)
+{
+  return current_term->checkkey ();
+}
+
+/* Display an ASCII character.  */
+void
+grub_putchar (int c)
+{
+  if (c == '\n')
+    grub_putchar ('\r');
+  else if (c == '\t' && current_term->getxy)
+    {
+      int n;
+      
+      n = 8 - ((current_term->getxy () >> 8) & 3);
+      while (n--)
+	grub_putchar (' ');
+      
+      return;
+    }
+  
+  if (c == '\n')
+    {
+      /* Internal `more'-like feature.  */
+      if (count_lines >= 0)
+	{
+	  count_lines++;
+	  if (count_lines >= max_lines - 2)
+	    {
+	      int tmp;
+	      
+	      /* It's important to disable the feature temporarily, because
+		 the following grub_printf call will print newlines.  */
+	      count_lines = -1;
+
+	      if (current_term->setcolorstate)
+		current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
+	      
+	      grub_printf ("\n[Hit return to continue]");
+
+	      if (current_term->setcolorstate)
+		current_term->setcolorstate (COLOR_STATE_NORMAL);
+	      
+	      do
+		{
+		  tmp = ASCII_CHAR (getkey ());
+		}
+	      while (tmp != '\n' && tmp != '\r');
+	      grub_printf ("\r                        \r");
+	      
+	      /* Restart to count lines.  */
+	      count_lines = 0;
+	      return;
+	    }
+	}
+    }
+
+  current_term->putchar (c);
+  
+}
+
+void
+gotoxy (int x, int y)
+{
+  current_term->gotoxy (x, y);
+}
+
+int
+getxy (void)
+{
+  return current_term->getxy ();
+}
+
+void
+cls (void)
+{
+  /* If the terminal is dumb, there is no way to clean the terminal.  */
+  if (current_term->flags & TERM_DUMB)
+    grub_putchar ('\n');
+  else
+    current_term->cls ();
+}
+
+int
+setcursor (int on)
+{
+  if (current_term->setcursor)
+    return current_term->setcursor (on);
+
+  return 1;
+}
+
+int
+substring (const char *s1, const char *s2)
+{
+  while (*s1 == *s2)
+    {
+      /* The strings match exactly. */
+      if (! *(s1++))
+        return 0;
+      s2 ++;
+    }
+
+  /* S1 is a substring of S2. */
+  if (*s1 == 0)
+    return -1;
+
+  /* S1 isn't a substring. */
+  return 1;
+}
+
+
+
+
+/* Terminate the string STR with NUL.  */
+int
+nul_terminate (char *str)
+{
+  int ch;
+
+  while (*str && ! grub_isspace (*str))
+    str++;
+
+  ch = *str;
+  *str = 0;
+  return ch;
+}
+

Added: trunk/filo/main/grub/cmdline.c
===================================================================
--- trunk/filo/main/grub/cmdline.c	                        (rev 0)
+++ trunk/filo/main/grub/cmdline.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,259 @@
+/* cmdline.c - the device-independent GRUB text command line */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004  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 <libpayload.h>
+#include <config.h>
+#include <grub/shared.h>
+
+/* Find the next word from CMDLINE and return the pointer. If
+   AFTER_EQUAL is non-zero, assume that the character `=' is treated as
+   a space. Caution: this assumption is for backward compatibility.  */
+char *
+skip_to (int after_equal, char *cmdline)
+{
+  /* Skip until we hit whitespace, or maybe an equal sign. */
+  while (*cmdline && *cmdline != ' ' && *cmdline != '\t' &&
+	 ! (after_equal && *cmdline == '='))
+    cmdline ++;
+
+  /* Skip whitespace, and maybe equal signs. */
+  while (*cmdline == ' ' || *cmdline == '\t' ||
+	 (after_equal && *cmdline == '='))
+    cmdline ++;
+
+  return cmdline;
+}
+
+/* Print a helpful message for the command-line interface.  */
+void
+print_cmdline_message (int type)
+{
+  printf (" [ Minimal BASH-like line editing is supported.  For the first word, TAB\n"
+	  "   lists possible command completions.  Anywhere else TAB lists the possible\n"
+	  "   completions of a device/filename.");
+  if (type == CMDLINE_NORMAL_MODE)
+    printf("  ESC at any time exits.");
+  if (type == CMDLINE_EDIT_MODE)
+    printf("  ESC at any time cancels.  ENTER \n"
+           "   at any time accepts your changes.");
+  printf("]\n");
+#ifndef CONFIG_NEWLINE_BEFORE_EACH_PROMPT
+  printf("\n");
+#endif
+}
+
+/* Find the builtin whose command name is COMMAND and return the
+   pointer. If not found, return 0.  */
+struct builtin *
+find_command (char *command)
+{
+  char *ptr;
+  char c;
+  struct builtin **builtin;
+
+  /* Find the first space and terminate the command name.  */
+  ptr = command;
+  while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '=')
+    ptr ++;
+
+  c = *ptr;
+  *ptr = 0;
+
+  /* Seek out the builtin whose command name is COMMAND.  */
+  for (builtin = builtin_table; *builtin != 0; builtin++)
+    {
+      int ret = grub_strcmp (command, (*builtin)->name);
+
+      if (ret == 0)
+	{
+	  /* Find the builtin for COMMAND.  */
+	  *ptr = c;
+	  return *builtin;
+	}
+      else if (ret < 0)
+	break;
+    }
+
+  /* Cannot find COMMAND.  */
+  errnum = ERR_UNRECOGNIZED;
+  *ptr = c;
+  return 0;
+}
+
+/* Initialize the data for the command-line.  */
+static void
+init_cmdline (void)
+{
+  /* Initialization.  */
+  saved_drive = boot_drive;
+  saved_partition = install_partition;
+  current_drive = GRUB_INVALID_DRIVE;
+  errnum = 0;
+  count_lines = -1;
+  
+#if 0
+  /* Restore memory probe state.  */
+  mbi.mem_upper = saved_mem_upper;
+  if (mbi.mmap_length)
+    mbi.flags |= MB_INFO_MEM_MAP;
+#endif
+  
+  /* Initialize the data for the builtin commands.  */
+  init_builtins ();
+}
+
+/* Enter the command-line interface. HEAP is used for the command-line
+   buffer. Return only if FOREVER is nonzero and get_cmdline returns
+   nonzero (ESC is pushed).  */
+void
+enter_cmdline (char *heap, int forever)
+{
+  /* Initialize the data and print a message.  */
+  init_cmdline ();
+
+  init_page ();
+  
+  print_cmdline_message (forever ? CMDLINE_FOREVER_MODE : CMDLINE_NORMAL_MODE );
+  
+  while (1)
+    {
+      struct builtin *builtin;
+      char *arg;
+
+      *heap = 0;
+      print_error ();
+      errnum = ERR_NONE;
+
+      /* Get the command-line with the minimal BASH-like interface.  */
+      if (get_cmdline (CONFIG_PROMPT "> ", heap, 2048, 0, 1))
+	return;
+
+      /* If there was no command, grab a new one. */
+      if (! heap[0])
+	continue;
+
+      /* Find a builtin.  */
+      builtin = find_command (heap);
+      if (! builtin)
+	continue;
+
+      /* If BUILTIN cannot be run in the command-line, skip it.  */
+      if (! (builtin->flags & BUILTIN_CMDLINE))
+	{
+	  errnum = ERR_UNRECOGNIZED;
+	  continue;
+	}
+
+      /* Invalidate the cache, because the user may exchange removable
+	 disks.  */
+      buf_drive = -1;
+
+      /* Start to count lines, only if the internal pager is in use.  */
+      if (use_pager)
+	count_lines = 0;
+      
+      /* Run BUILTIN->FUNC.  */
+      arg = skip_to (1, heap);
+      (builtin->func) (arg, BUILTIN_CMDLINE);
+
+      /* Finish the line count.  */
+      count_lines = -1;
+    }
+}
+
+/* Run an entry from the script SCRIPT. HEAP is used for the
+   command-line buffer. If an error occurs, return non-zero, otherwise
+   return zero.  */
+int
+run_script (char *script, char *heap)
+{
+  char *old_entry;
+  char *cur_entry = script;
+
+  /* Initialize the data.  */
+  init_cmdline ();
+
+  while (1)
+    {
+      struct builtin *builtin;
+      char *arg;
+
+      print_error ();
+
+      if (errnum)
+	{
+	  errnum = ERR_NONE;
+
+	  /* If a fallback entry is defined, don't prompt a user's
+	     intervention.  */
+	  if (fallback_entryno < 0)
+	    {
+	      grub_printf ("\nPress any key to continue...");
+	      (void) getkey ();
+	    }
+	  
+	  return 1;
+	}
+
+      /* Copy the first string in CUR_ENTRY to HEAP.  */
+      old_entry = cur_entry;
+      while (*cur_entry++)
+	;
+
+      grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry);
+      if (! *heap)
+	{
+	  /* If there is no more command in SCRIPT...  */
+
+	  /* If any kernel is not loaded, just exit successfully.  */
+	  if (kernel_type == KERNEL_TYPE_NONE)
+	    return 0;
+
+	  /* Otherwise, the command boot is run implicitly.  */
+	  grub_memmove (heap, "boot", 5);
+	}
+
+      /* Find a builtin.  */
+      builtin = find_command (heap);
+      if (! builtin)
+	{
+	  grub_printf ("%s\n", old_entry);
+	  continue;
+	}
+
+      if (! (builtin->flags & BUILTIN_NO_ECHO))
+	grub_printf ("%s\n", old_entry);
+
+      /* If BUILTIN cannot be run in the command-line, skip it.  */
+      if (! (builtin->flags & BUILTIN_CMDLINE))
+	{
+	  errnum = ERR_UNRECOGNIZED;
+	  continue;
+	}
+
+      /* Invalidate the cache, because the user may exchange removable
+	 disks.  */
+      buf_drive = -1;
+
+      /* Run BUILTIN->FUNC.  */
+      arg = skip_to (1, heap);
+      (builtin->func) (arg, BUILTIN_SCRIPT);
+    }
+}

Added: trunk/filo/main/grub/completions.c
===================================================================
--- trunk/filo/main/grub/completions.c	                        (rev 0)
+++ trunk/filo/main/grub/completions.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,95 @@
+/* Parts are : */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004  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 <libpayload.h>
+#include <config.h>
+#include <grub/shared.h>
+
+static int do_completion;
+static int unique;
+static char *unique_string;
+
+
+/* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
+   part into UNIQUE_STRING.  */
+void
+print_a_completion (char *name)
+{
+  /* If NAME is "." or "..", do not count it.  */
+  if (grub_strcmp (name, ".") == 0 || grub_strcmp (name, "..") == 0)
+    return;
+
+  if (do_completion)
+    {
+      char *buf = unique_string;
+
+      if (! unique)
+        while ((*buf++ = *name++))
+          ;
+      else
+        {
+          while (*buf && (*buf == *name))
+            {
+              buf++;
+              name++;
+            }
+          /* mismatch, strip it.  */
+          *buf = '\0';
+        }
+    }
+  else
+    grub_printf (" %s", name);
+
+  unique++;
+}
+
+/*
+ *  This lists the possible completions of a device string, filename, or
+ *  any sane combination of the two.
+ */
+
+int print_completions (int is_filename, int is_completion)
+{
+#if CONFIG_EXPERIMENTAL
+  char *buf = (char *) COMPLETION_BUF;
+  char *ptr = buf;
+
+  unique_string = (char *) UNIQUE_BUF;
+  *unique_string = 0;
+  unique = 0;
+  do_completion = is_completion;
+
+  #warning FIXME implement print_completions
+  // FIXME: This function is a dummy, returning an error.
+  errnum = ERR_BAD_FILENAME;
+  
+
+  print_error ();
+  do_completion = 0;
+  if (errnum)
+    return -1;
+  else
+    return unique - 1;
+#else
+  errnum = ERR_BAD_FILENAME;
+  print_error ();
+  return -1;
+#endif
+}

Added: trunk/filo/main/grub/grubcons.c
===================================================================
--- trunk/filo/main/grub/grubcons.c	                        (rev 0)
+++ trunk/filo/main/grub/grubcons.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,105 @@
+/* term_console.c - console input and output */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002  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 <libpayload.h>
+#include <config.h>
+
+#if (CONFIG_VGA_CONSOLE == 1) && (CONFIG_PC_KEYBOARD == 1)
+
+#include <grub/shared.h>
+#include <grub/term.h>
+
+static int console_current_color = A_NORMAL;
+static int console_standard_color = A_NORMAL;
+static int console_normal_color = A_NORMAL;
+static int console_highlight_color = A_REVERSE;
+static color_state console_color_state = COLOR_STATE_STANDARD;
+
+void console_setcolorstate (color_state state)
+{
+	switch (state) {
+	case COLOR_STATE_STANDARD:
+		console_current_color = console_standard_color;
+		break;
+	case COLOR_STATE_NORMAL:
+		console_current_color = console_normal_color;
+		break;
+	case COLOR_STATE_HIGHLIGHT:
+		console_current_color = console_highlight_color;
+		break;
+	default:
+		console_current_color = console_standard_color;
+		break;
+	}
+
+	console_color_state = state;
+}
+
+void console_setcolor (int normal_color, int highlight_color)
+{
+	console_normal_color = normal_color;
+	console_highlight_color = highlight_color;
+
+	console_setcolorstate (console_color_state);
+}
+
+int console_checkkey (void)
+{
+	if(keyboard_havechar()) 
+		return 0;
+	return -1;
+}
+
+int console_getkey (void)
+{
+	return keyboard_getchar();
+}
+
+int console_getxy (void)
+{
+	unsigned int x, y, en;
+	video_console_get_cursor(&x, &y, &en);
+	return (x<<8)|(y);
+}
+
+void console_gotoxy (int x, int y)
+{
+	video_console_set_cursor(x, y);
+}
+
+void console_cls (void)
+{
+	video_console_clear();
+}
+
+int console_setcursor (int on)
+{
+	video_console_cursor_enable(on);
+	return 0;
+}
+
+void console_putchar (int c)
+{
+	c|=(console_current_color<<8);
+	video_console_putchar(c);
+}
+
+#endif
+

Added: trunk/filo/main/grub/md5.c
===================================================================
--- trunk/filo/main/grub/md5.c	                        (rev 0)
+++ trunk/filo/main/grub/md5.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,386 @@
+/* md5.c - an implementation of the MD5 algorithm and MD5 crypt */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000, 2001  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.
+ */
+
+/* See RFC 1321 for a description of the MD5 algorithm.
+ */
+
+#include <libpayload.h>
+#include <config.h>
+
+#include <grub/md5.h>
+#ifndef TEST
+# include <grub/shared.h>
+#endif
+
+#ifdef TEST
+# include <string.h>
+# define CONFIG_USE_MD5_PASSWORDS
+# define USE_MD5
+#endif
+
+#ifdef CONFIG_USE_MD5_PASSWORDS
+# define USE_MD5
+#endif
+
+#ifdef USE_MD5
+
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+typedef unsigned int UINT4;
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
+
+static UINT4 initstate[4] =
+{
+  0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 
+};
+
+static char s1[4] = {  7, 12, 17, 22 };
+static char s2[4] = {  5,  9, 14, 20 };
+static char s3[4] = {  4, 11, 16, 23 };
+static char s4[4] = {  6, 10, 15, 21 };
+
+static UINT4 T[64] =
+{
+  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+  0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+  0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+  0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+  0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+  0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+  0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+  0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+  0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+  0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static const char *b64t =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static UINT4 state[4];
+static unsigned int length;
+static unsigned char buffer[64];
+
+static void
+md5_transform (const unsigned char block[64])
+{
+  int i, j;
+  UINT4 a,b,c,d,tmp;
+  const UINT4 *x = (UINT4 *) block;
+
+  a = state[0];
+  b = state[1];
+  c = state[2];
+  d = state[3];
+
+  /* Round 1 */
+  for (i = 0; i < 16; i++)
+    {
+      tmp = a + F (b, c, d) + le32_to_cpu (x[i]) + T[i];
+      tmp = ROTATE_LEFT (tmp, s1[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 2 */
+  for (i = 0, j = 1; i < 16; i++, j += 5)
+    {
+      tmp = a + G (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+16];
+      tmp = ROTATE_LEFT (tmp, s2[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 3 */
+  for (i = 0, j = 5; i < 16; i++, j += 3)
+    {
+      tmp = a + H (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+32];
+      tmp = ROTATE_LEFT (tmp, s3[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 4 */
+  for (i = 0, j = 0; i < 16; i++, j += 7)
+    {
+      tmp = a + I (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+48];
+      tmp = ROTATE_LEFT (tmp, s4[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+}
+
+static void
+md5_init(void)
+{
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+}
+
+static void
+md5_update (const char *input, int inputlen)
+{
+  int buflen = length & 63;
+  length += inputlen;
+  if (buflen + inputlen < 64) 
+    {
+      memcpy (buffer + buflen, input, inputlen);
+      buflen += inputlen;
+      return;
+    }
+  
+  memcpy (buffer + buflen, input, 64 - buflen);
+  md5_transform (buffer);
+  input += 64 - buflen;
+  inputlen -= 64 - buflen;
+  while (inputlen >= 64)
+    {
+      md5_transform ((const unsigned char *)input);
+      input += 64;
+      inputlen -= 64;
+    }
+  memcpy (buffer, input, inputlen);
+  buflen = inputlen;
+}
+
+static unsigned char *
+md5_final()
+{
+  int i, buflen = length & 63;
+
+  buffer[buflen++] = 0x80;
+  memset (buffer+buflen, 0, 64 - buflen);
+  if (buflen > 56)
+    {
+      md5_transform (buffer);
+      memset (buffer, 0, 64);
+      buflen = 0;
+    }
+  
+  *(UINT4 *) (buffer + 56) = cpu_to_le32 (8 * length);
+  *(UINT4 *) (buffer + 60) = 0;
+  md5_transform (buffer);
+
+  for (i = 0; i < 4; i++)
+    state[i] = cpu_to_le32 (state[i]);
+  return (unsigned char *) state;
+}
+
+#ifdef CONFIG_USE_MD5_PASSWORDS
+/* If CHECK is true, check a password for correctness. Returns 0
+   if password was correct, and a value != 0 for error, similarly
+   to strcmp.
+   If CHECK is false, crypt KEY and save the result in CRYPTED.
+   CRYPTED must have a salt.  */
+int
+md5_password (const char *key, char *crypted, int check)
+{
+  int keylen = strlen (key);
+  char *salt = crypted + 3; /* skip $1$ header */
+  char *p; 
+  int saltlen;
+  int i, n;
+  char alt_result[16];
+  unsigned char *digest;
+
+  if (check)
+    {
+      /* If our crypted password isn't 3 chars, then it can't be md5
+	 crypted. So, they don't match.  */
+      if (strlen(crypted) <= 3)
+	return 1;
+      
+      saltlen = strstr (salt, "$") - salt;
+    }
+  else
+    {
+      char *end = strstr (salt, "$");
+      if (end && end - salt < 8)
+	saltlen = end - salt;
+      else
+	saltlen = 8;
+
+      salt[saltlen] = '$';
+    }
+  
+  md5_init ();
+  md5_update (key, keylen);
+  md5_update (salt, saltlen);
+  md5_update (key, keylen);
+  digest = md5_final ();
+  memcpy (alt_result, digest, 16);
+  
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+  md5_update (key, keylen);
+  md5_update (crypted, 3 + saltlen); /* include the $1$ header */
+  for (i = keylen; i > 16; i -= 16)
+    md5_update (alt_result, 16);
+  md5_update (alt_result, i);
+
+  for (i = keylen; i > 0; i >>= 1)
+    md5_update (key + ((i & 1) ? keylen : 0), 1);
+  digest = md5_final ();
+
+  for (i = 0; i < 1000; i++)
+    {
+      memcpy (alt_result, digest, 16);
+
+      memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+      length = 0;
+      if ((i & 1) != 0)
+	md5_update (key, keylen);
+      else
+	md5_update (alt_result, 16);
+      
+      if (i % 3 != 0)
+	md5_update (salt, saltlen);
+
+      if (i % 7 != 0)
+	md5_update (key, keylen);
+
+      if ((i & 1) != 0)
+	md5_update (alt_result, 16);
+      else
+	md5_update (key, keylen);
+      digest = md5_final ();
+    }
+
+  p = salt + saltlen + 1;
+  for (i = 0; i < 5; i++)
+    {
+      unsigned int w = 
+	digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16);
+      for (n = 4; n-- > 0;)
+	{
+	  if (check)
+	    {
+	      if (*p++ != b64t[w & 0x3f])
+		return 1;
+	    }
+	  else
+	    {
+	      *p++ = b64t[w & 0x3f];
+	    }
+	  
+	  w >>= 6;
+	}
+    }
+  {
+    unsigned int w = digest[11];
+    for (n = 2; n-- > 0;)
+      {
+	if (check)
+	  {
+	    if (*p++ != b64t[w & 0x3f])
+	      return 1;
+	  }
+	else
+	  {
+	    *p++ = b64t[w & 0x3f];
+	  }
+	
+	w >>= 6;
+      }
+  }
+
+  if (! check)
+    *p = '\0';
+  
+  return *p;
+}
+#endif
+
+#ifdef TEST
+static char *
+md5 (const char *input) 
+{
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+  md5_update (input, strlen (input));
+  return md5_final ();
+}
+
+static void
+test (char *buffer, char *expected) 
+{
+  char result[16 * 3 +1];
+  unsigned char* digest = md5 (buffer);
+  int i;
+
+  for (i=0; i < 16; i++)
+    sprintf (result+2*i, "%02x", digest[i]);
+
+  if (strcmp (result, expected))
+    printf ("MD5(%s) failed: %s\n", buffer, result);
+  else
+    printf ("MD5(%s) OK\n", buffer);
+}
+
+int
+main (void)
+{
+  test ("", "d41d8cd98f00b204e9800998ecf8427e");
+  test ("a", "0cc175b9c0f1b6a831c399e269772661");
+  test ("abc", "900150983cd24fb0d6963f7d28e17f72");
+  test ("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+  test ("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	"d174ab98d277d9f5a5611c2c9f419d9f");
+  test ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	"57edf4a22be3c955ac49da2e2107b67a");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz3456",
+	"6831fa90115bb9a54fbcd4f9fee0b5c4");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345",
+	"bc40505cc94a43b7ff3e2ac027325233");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567",
+	"fa94b73a6f072a0239b52acacfbcf9fa");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345678901234",
+	"bd201eae17f29568927414fa326f1267");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123",
+	"80063db1e6b70a2e91eac903f0e46b85");
+
+  if (check_md5_password ("Hello world!",
+			  "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"))
+    printf ("Password differs\n");
+  else
+    printf ("Password OK\n");
+  return 0;
+}
+#endif
+
+#endif

Added: trunk/filo/main/grub/serial.c
===================================================================
--- trunk/filo/main/grub/serial.c	                        (rev 0)
+++ trunk/filo/main/grub/serial.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,345 @@
+/* serial.c - serial device interface */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2002  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 <libpayload.h>
+#include <config.h>
+#include <grub/shared.h>
+#include <grub/term.h>
+#include <grub/terminfo.h>
+
+/* An input buffer.  */
+static char input_buf[8];
+static int npending = 0;
+
+static int serial_x;
+static int serial_y;
+
+static int keep_track = 1;
+
+#ifndef GRUB_UTIL
+
+/* Fetch a key.  */
+int
+serial_hw_fetch (void)
+{
+#if CONFIG_SERIAL_CONSOLE
+  if(serial_havechar())
+	  return serial_getchar();
+#endif
+  return -1;
+}
+
+/* Put a chararacter.  */
+void
+serial_hw_put (int c)
+{
+#if CONFIG_SERIAL_CONSOLE
+	serial_putchar(c);
+#endif
+}
+
+/* Return the port number for the UNITth serial device.  */
+unsigned short
+serial_hw_get_port (int unit)
+{
+#if CONFIG_SERIAL_CONSOLE
+  return CONFIG_SERIAL_IOBASE;
+#else
+  return 0;
+#endif
+}
+
+/* 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.  */
+int
+serial_hw_init (unsigned short port, unsigned int speed,
+		int word_len, int parity, int stop_bit_len)
+{
+#if CONFIG_CONSOLE_SERIAL
+  int i;
+  /* Drain the input buffer.  */
+  while (serial_checkkey () != -1) {
+    (void) serial_getkey ();
+  }
+
+  /* Get rid of TERM_NEED_INIT from the serial terminal.  */
+  for (i = 0; term_table[i].name; i++)
+    if (grub_strcmp (term_table[i].name, "serial") == 0)
+      {
+	term_table[i].flags &= ~TERM_NEED_INIT;
+	break;
+      }
+#endif
+  return 1;
+}
+#endif /* ! GRUB_UTIL */
+
+
+/* Generic definitions.  */
+
+#if CONFIG_SERIAL_CONSOLE
+static void
+serial_translate_key_sequence (void)
+{
+  const struct
+  {
+    char key;
+    char ascii;
+  }
+  three_code_table[] =
+    {
+      {'A', 16},
+      {'B', 14},
+      {'C', 6},
+      {'D', 2},
+      {'F', 5},
+      {'H', 1},
+      {'4', 4}
+    };
+
+  const struct
+  {
+    short key;
+    char ascii;
+  }
+  four_code_table[] =
+    {
+      {('1' | ('~' << 8)), 1},
+      {('3' | ('~' << 8)), 4},
+      {('5' | ('~' << 8)), 7},
+      {('6' | ('~' << 8)), 3},
+    };
+  
+  /* The buffer must start with ``ESC [''.  */
+  if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
+    return;
+  
+  if (npending >= 3)
+    {
+      int i;
+
+      for (i = 0;
+	   i < sizeof (three_code_table) / sizeof (three_code_table[0]);
+	   i++)
+	if (three_code_table[i].key == input_buf[2])
+	  {
+	    input_buf[0] = three_code_table[i].ascii;
+	    npending -= 2;
+	    memmove (input_buf + 1, input_buf + 3, npending - 1);
+	    return;
+	  }
+    }
+
+  if (npending >= 4)
+    {
+      int i;
+      short key = *((short *) (input_buf + 2));
+
+      for (i = 0;
+	   i < sizeof (four_code_table) / sizeof (four_code_table[0]);
+	   i++)
+	if (four_code_table[i].key == key)
+	  {
+	    input_buf[0] = four_code_table[i].ascii;
+	    npending -= 3;
+	    memmove (input_buf + 1, input_buf + 4, npending - 1);
+	    return;
+	  }
+    }
+}
+   
+static
+int fill_input_buf (int nowait)
+{
+  int i;
+
+  for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
+    {
+      int c;
+
+      c = serial_hw_fetch ();
+      if (c >= 0)
+	{
+	  input_buf[npending++] = c;
+
+	  /* Reset the counter to zero, to wait for the same interval.  */
+	  i = 0;
+	}
+      
+      if (nowait)
+	break;
+    }
+
+  /* Translate some key sequences.  */
+  serial_translate_key_sequence ();
+	  
+  return npending;
+}
+#endif
+
+/* The serial version of getkey.  */
+int
+serial_getkey (void)
+{
+  int c;
+#if CONFIG_SERIAL_CONSOLE
+  while (! fill_input_buf (0))
+    ;
+#endif
+
+  c = input_buf[0];
+  npending--;
+  memmove (input_buf, input_buf + 1, npending);
+  
+  return c;
+}
+
+/* The serial version of checkkey.  */
+int
+serial_checkkey (void)
+{
+#if CONFIG_SERIAL_CONSOLE
+  if (fill_input_buf (1))
+    return input_buf[0];
+#endif
+
+  return -1;
+}
+
+/* The serial version of grub_putchar.  */
+void
+grub_serial_putchar (int c)
+{
+  /* Keep track of the cursor.  */
+  if (keep_track)
+    {
+      /* The serial terminal doesn't have VGA fonts.  */
+      switch (c)
+	{
+	case DISP_UL:
+	  c = ACS_ULCORNER;
+	  break;
+	case DISP_UR:
+	  c = ACS_URCORNER;
+	  break;
+	case DISP_LL:
+	  c = ACS_LLCORNER;
+	  break;
+	case DISP_LR:
+	  c = ACS_LRCORNER;
+	  break;
+	case DISP_HORIZ:
+	  c = ACS_HLINE;
+	  break;
+	case DISP_VERT:
+	  c = ACS_VLINE;
+	  break;
+	case DISP_LEFT:
+	  c = ACS_LARROW;
+	  break;
+	case DISP_RIGHT:
+	  c = ACS_RARROW;
+	  break;
+	case DISP_UP:
+	  c = ACS_UARROW;
+	  break;
+	case DISP_DOWN:
+	  c = ACS_DARROW;
+	  break;
+	default:
+	  break;
+	}
+      
+      switch (c)
+	{
+	case '\r':
+	  serial_x = 0;
+	  break;
+	  
+	case '\n':
+	  serial_y++;
+	  break;
+	  
+	case '\b':
+	case 127:
+	  if (serial_x > 0)
+	    serial_x--;
+	  break;
+	  
+	case '\a':
+	  break;
+	  
+	default:
+	  if (serial_x >= 79)
+	    {
+	      grub_serial_putchar ('\r');
+	      grub_serial_putchar ('\n');
+	    }
+	  serial_x++;
+	  break;
+	}
+    }
+  
+  serial_hw_put (c);
+}
+
+int
+serial_getxy (void)
+{
+  return (serial_x << 8) | serial_y;
+}
+
+void
+serial_gotoxy (int x, int y)
+{
+  keep_track = 0;
+  ti_cursor_address (x, y);
+  keep_track = 1;
+  
+  serial_x = x;
+  serial_y = y;
+}
+
+void
+serial_cls (void)
+{
+  keep_track = 0;
+  ti_clear_screen ();
+  keep_track = 1;
+  
+  serial_x = serial_y = 0;
+}
+
+void
+serial_setcolorstate (color_state state)
+{
+  keep_track = 0;
+  if (state == COLOR_STATE_HIGHLIGHT)
+    ti_enter_standout_mode ();
+  else
+    ti_exit_standout_mode ();
+  keep_track = 1;
+}
+

Added: trunk/filo/main/grub/stage2.c
===================================================================
--- trunk/filo/main/grub/stage2.c	                        (rev 0)
+++ trunk/filo/main/grub/stage2.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1196 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2002,2004,2005  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 <libpayload.h>
+#include <config.h>
+#include <grub/shared.h>
+#include <grub/term.h>
+
+int file_open(const char *filename);
+int file_read(void *buf, unsigned long len);
+int file_seek(unsigned long offset);
+void file_close(void);
+void grub_menulst(void);
+
+struct multiboot_info mbi;
+
+#if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
+
+# if defined(PRESET_MENU_STRING)
+static const char *preset_menu = PRESET_MENU_STRING;
+# elif defined(SUPPORT_DISKLESS)
+/* Execute the command "bootp" automatically.  */
+static const char *preset_menu = "bootp\n";
+# endif /* SUPPORT_DISKLESS */
+
+static int preset_menu_offset;
+
+static int
+open_preset_menu (void)
+{
+#ifdef GRUB_UTIL
+  /* Unless the user explicitly requests to use the preset menu,
+     always opening the preset menu fails in the grub shell.  */
+  if (! use_preset_menu)
+    return 0;
+#endif /* GRUB_UTIL */
+  
+  preset_menu_offset = 0;
+  return preset_menu != 0;
+}
+
+static int
+read_from_preset_menu (char *buf, int maxlen)
+{
+  int len = grub_strlen (preset_menu + preset_menu_offset);
+
+  if (len > maxlen)
+    len = maxlen;
+
+  grub_memmove (buf, preset_menu + preset_menu_offset, len);
+  preset_menu_offset += len;
+
+  return len;
+}
+
+static void
+close_preset_menu (void)
+{
+  /* Disable the preset menu.  */
+  preset_menu = 0;
+}
+
+#else /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
+
+#define open_preset_menu()	0
+#define read_from_preset_menu(buf, maxlen)	0
+#define close_preset_menu()
+
+#endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
+
+static char *
+get_entry (char *list, int num, int nested)
+{
+  int i;
+
+  for (i = 0; i < num; i++)
+    {
+      do
+	{
+	  while (*(list++));
+	}
+      while (nested && *(list++));
+    }
+
+  return list;
+}
+
+/* Print an entry in a line of the menu box.  */
+static void
+print_entry (int y, int highlight, char *entry)
+{
+  int x;
+
+  if (current_term->setcolorstate)
+    current_term->setcolorstate (COLOR_STATE_NORMAL);
+  
+  if (highlight && current_term->setcolorstate)
+    current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
+
+  gotoxy (2, y);
+  grub_putchar (' ');
+  for (x = 3; x < 75; x++)
+    {
+      if (*entry && x <= 72)
+	{
+	  if (x == 72)
+	    grub_putchar (DISP_RIGHT);
+	  else
+	    grub_putchar (*entry++);
+	}
+      else
+	grub_putchar (' ');
+    }
+  gotoxy (74, y);
+
+  if (current_term->setcolorstate)
+    current_term->setcolorstate (COLOR_STATE_STANDARD);
+}
+
+/* Print entries in the menu box.  */
+static void
+print_entries (int y, int size, int first, int entryno, char *menu_entries)
+{
+  int i;
+  
+  gotoxy (77, y + 1);
+
+  if (first)
+    grub_putchar (DISP_UP);
+  else
+    grub_putchar (' ');
+
+  menu_entries = get_entry (menu_entries, first, 0);
+
+  for (i = 0; i < size; i++)
+    {
+      print_entry (y + i + 1, entryno == i, menu_entries);
+
+      while (*menu_entries)
+	menu_entries++;
+
+      if (*(menu_entries - 1))
+	menu_entries++;
+    }
+
+  gotoxy (77, y + size);
+
+  if (*menu_entries)
+    grub_putchar (DISP_DOWN);
+  else
+    grub_putchar (' ');
+
+  gotoxy (74, y + entryno + 1);
+}
+
+static void
+print_entries_raw (int size, int first, char *menu_entries)
+{
+  int i;
+
+#define LINE_LENGTH 67
+
+  for (i = 0; i < LINE_LENGTH; i++)
+    grub_putchar ('-');
+  grub_putchar ('\n');
+
+  for (i = first; i < size; i++)
+    {
+      /* grub's printf can't %02d so ... */
+      if (i < 10)
+	grub_putchar (' ');
+      grub_printf ("%d: %s\n", i, get_entry (menu_entries, i, 0));
+    }
+
+  for (i = 0; i < LINE_LENGTH; i++)
+    grub_putchar ('-');
+  grub_putchar ('\n');
+
+#undef LINE_LENGTH
+}
+
+
+static void
+print_border (int y, int size)
+{
+  int i;
+
+  if (current_term->setcolorstate)
+    current_term->setcolorstate (COLOR_STATE_NORMAL);
+  
+  gotoxy (1, y);
+
+  grub_putchar (DISP_UL);
+  for (i = 0; i < 73; i++)
+    grub_putchar (DISP_HORIZ);
+  grub_putchar (DISP_UR);
+
+  i = 1;
+  while (1)
+    {
+      gotoxy (1, y + i);
+
+      if (i > size)
+	break;
+      
+      grub_putchar (DISP_VERT);
+      gotoxy (75, y + i);
+      grub_putchar (DISP_VERT);
+
+      i++;
+    }
+
+  grub_putchar (DISP_LL);
+  for (i = 0; i < 73; i++)
+    grub_putchar (DISP_HORIZ);
+  grub_putchar (DISP_LR);
+
+  if (current_term->setcolorstate)
+    current_term->setcolorstate (COLOR_STATE_STANDARD);
+}
+
+static void
+run_menu (char *menu_entries, char *config_entries, int num_entries,
+	  char *heap, int entryno)
+{
+  int c, time1, time2 = -1, first_entry = 0;
+  char *cur_entry = 0;
+
+  /*
+   *  Main loop for menu UI.
+   */
+
+restart:
+  /* Dumb terminal always use all entries for display 
+     invariant for TERM_DUMB: first_entry == 0  */
+  if (! (current_term->flags & TERM_DUMB))
+    {
+      while (entryno > 11)
+	{
+	  first_entry++;
+	  entryno--;
+	}
+    }
+
+  /* If the timeout was expired or wasn't set, force to show the menu
+     interface. */
+  if (grub_timeout < 0)
+    show_menu = 1;
+  
+  /* If SHOW_MENU is false, don't display the menu until ESC is pressed.  */
+  if (! show_menu)
+    {
+      /* Get current time.  */
+      while ((time1 = getrtsecs ()) == 0xFF)
+	;
+
+      while (1)
+	{
+	  /* Check if ESC is pressed.  */
+	  if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e')
+	    {
+	      grub_timeout = -1;
+	      show_menu = 1;
+	      break;
+	    }
+
+	  /* If GRUB_TIMEOUT is expired, boot the default entry.  */
+	  if (grub_timeout >=0
+	      && (time1 = getrtsecs ()) != time2
+	      && time1 != 0xFF)
+	    {
+	      if (grub_timeout <= 0)
+		{
+		  grub_timeout = -1;
+		  goto boot_entry;
+		}
+	      
+	      time2 = time1;
+	      grub_timeout--;
+	      
+	      /* Print a message.  */
+	      grub_printf ("\rPress `ESC' to enter the menu... %d   ",
+			   grub_timeout);
+	    }
+	}
+    }
+
+  /* Only display the menu if the user wants to see it. */
+  if (show_menu)
+    {
+      init_page ();
+      setcursor (0);
+
+      if (current_term->flags & TERM_DUMB)
+	print_entries_raw (num_entries, first_entry, menu_entries);
+      else
+	print_border (3, 12);
+
+      grub_printf ("\n\
+      Use the %c and %c keys to select which entry is highlighted.\n",
+		   DISP_UP, DISP_DOWN);
+      
+      if (! auth && password)
+	{
+	  printf ("\
+      Press enter to boot the selected OS or \'p\' to enter a\n\
+      password to unlock the next set of features.");
+	}
+      else
+	{
+	  if (config_entries)
+	    printf ("\
+      Press enter to boot the selected OS, \'e\' to edit the\n\
+      commands before booting, \'a\' to modify the kernel arguments\n\
+      before booting, or \'c\' for a command-line.");
+	  else
+	    printf ("\
+      Press \'b\' to boot, \'e\' to edit the selected command in the\n\
+      boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\
+      after (\'O\' for before) the selected line, \'d\' to remove the\n\
+      selected line, or escape to go back to the main menu.");
+	}
+
+      if (current_term->flags & TERM_DUMB)
+	grub_printf ("\n\nThe selected entry is %d ", entryno);
+      else
+	print_entries (3, 12, first_entry, entryno, menu_entries);
+    }
+
+  /* XX using RT clock now, need to initialize value */
+  while ((time1 = getrtsecs()) == 0xFF);
+
+  while (1)
+    {
+      /* Initialize to NULL just in case...  */
+      cur_entry = NULL;
+
+      if (grub_timeout >= 0 && (time1 = getrtsecs()) != time2 && time1 != 0xFF)
+	{
+	  if (grub_timeout <= 0)
+	    {
+	      grub_timeout = -1;
+	      break;
+	    }
+
+	  /* else not booting yet! */
+	  time2 = time1;
+
+	  if (current_term->flags & TERM_DUMB)
+	      grub_printf ("\r    Entry %d will be booted automatically in %d seconds.   ", 
+			   entryno, grub_timeout);
+	  else
+	    {
+	      gotoxy (3, 22);
+	      grub_printf ("The highlighted entry will be booted automatically in %d seconds.    ",
+			   grub_timeout);
+	      gotoxy (74, 4 + entryno);
+	  }
+	  
+	  grub_timeout--;
+	}
+
+      /* Check for a keypress, however if TIMEOUT has been expired
+	 (GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been
+	 pressed.  
+	 This avoids polling (relevant in the grub-shell and later on
+	 in grub if interrupt driven I/O is done).  */
+      if (checkkey () >= 0 || grub_timeout < 0)
+	{
+	  /* Key was pressed, show which entry is selected before GETKEY,
+	     since we're comming in here also on GRUB_TIMEOUT == -1 and
+	     hang in GETKEY */
+	  if (current_term->flags & TERM_DUMB)
+	    grub_printf ("\r    Highlighted entry is %d: ", entryno);
+
+	  c = ASCII_CHAR (getkey ());
+
+	  if (grub_timeout >= 0)
+	    {
+	      if (current_term->flags & TERM_DUMB)
+		grub_putchar ('\r');
+	      else
+		gotoxy (3, 22);
+	      printf ("                                                                    ");
+	      grub_timeout = -1;
+	      fallback_entryno = -1;
+	      if (! (current_term->flags & TERM_DUMB))
+		gotoxy (74, 4 + entryno);
+	    }
+
+	  /* We told them above (at least in SUPPORT_SERIAL) to use
+	     '^' or 'v' so accept these keys.  */
+	  if (c == 16 || c == '^')
+	    {
+	      if (current_term->flags & TERM_DUMB)
+		{
+		  if (entryno > 0)
+		    entryno--;
+		}
+	      else
+		{
+		  if (entryno > 0)
+		    {
+		      print_entry (4 + entryno, 0,
+				   get_entry (menu_entries,
+					      first_entry + entryno,
+					      0));
+		      entryno--;
+		      print_entry (4 + entryno, 1,
+				   get_entry (menu_entries,
+					      first_entry + entryno,
+					      0));
+		    }
+		  else if (first_entry > 0)
+		    {
+		      first_entry--;
+		      print_entries (3, 12, first_entry, entryno,
+				     menu_entries);
+		    }
+		}
+	    }
+	  else if ((c == 14 || c == 'v')
+		   && first_entry + entryno + 1 < num_entries)
+	    {
+	      if (current_term->flags & TERM_DUMB)
+		entryno++;
+	      else
+		{
+		  if (entryno < 11)
+		    {
+		      print_entry (4 + entryno, 0,
+				   get_entry (menu_entries,
+					      first_entry + entryno,
+					      0));
+		      entryno++;
+		      print_entry (4 + entryno, 1,
+				   get_entry (menu_entries,
+					      first_entry + entryno,
+					      0));
+		  }
+		else if (num_entries > 12 + first_entry)
+		  {
+		    first_entry++;
+		    print_entries (3, 12, first_entry, entryno, menu_entries);
+		  }
+		}
+	    }
+	  else if (c == 7)
+	    {
+	      /* Page Up */
+	      first_entry -= 12;
+	      if (first_entry < 0)
+		{
+		  entryno += first_entry;
+		  first_entry = 0;
+		  if (entryno < 0)
+		    entryno = 0;
+		}
+	      print_entries (3, 12, first_entry, entryno, menu_entries);
+	    }
+	  else if (c == 3)
+	    {
+	      /* Page Down */
+	      first_entry += 12;
+	      if (first_entry + entryno + 1 >= num_entries)
+		{
+		  first_entry = num_entries - 12;
+		  if (first_entry < 0)
+		    first_entry = 0;
+		  entryno = num_entries - first_entry - 1;
+		}
+	      print_entries (3, 12, first_entry, entryno, menu_entries);
+	    }
+
+	  if (config_entries)
+	    {
+	      if ((c == '\n') || (c == '\r') || (c == 6))
+		break;
+	    }
+	  else
+	    {
+	      if ((c == 'd') || (c == 'o') || (c == 'O'))
+		{
+		  if (! (current_term->flags & TERM_DUMB))
+		    print_entry (4 + entryno, 0,
+				 get_entry (menu_entries,
+					    first_entry + entryno,
+					    0));
+
+		  /* insert after is almost exactly like insert before */
+		  if (c == 'o')
+		    {
+		      /* But `o' differs from `O', since it may causes
+			 the menu screen to scroll up.  */
+		      if (entryno < 11 || (current_term->flags & TERM_DUMB))
+			entryno++;
+		      else
+			first_entry++;
+		      
+		      c = 'O';
+		    }
+
+		  cur_entry = get_entry (menu_entries,
+					 first_entry + entryno,
+					 0);
+
+		  if (c == 'O')
+		    {
+		      grub_memmove (cur_entry + 2, cur_entry,
+				    ((int) heap) - ((int) cur_entry));
+
+		      cur_entry[0] = ' ';
+		      cur_entry[1] = 0;
+
+		      heap += 2;
+
+		      num_entries++;
+		    }
+		  else if (num_entries > 0)
+		    {
+		      char *ptr = get_entry(menu_entries,
+					    first_entry + entryno + 1,
+					    0);
+
+		      grub_memmove (cur_entry, ptr,
+				    ((int) heap) - ((int) ptr));
+		      heap -= (((int) ptr) - ((int) cur_entry));
+
+		      num_entries--;
+
+		      if (entryno >= num_entries)
+			entryno--;
+		      if (first_entry && num_entries < 12 + first_entry)
+			first_entry--;
+		    }
+
+		  if (current_term->flags & TERM_DUMB)
+		    {
+		      grub_printf ("\n\n");
+		      print_entries_raw (num_entries, first_entry,
+					 menu_entries);
+		      grub_printf ("\n");
+		    }
+		  else
+		    print_entries (3, 12, first_entry, entryno, menu_entries);
+		}
+
+	      cur_entry = menu_entries;
+	      if (c == 27)
+		return;
+	      if (c == 'b')
+		break;
+	    }
+
+	  if (! auth && password)
+	    {
+	      if (c == 'p')
+		{
+		  /* Do password check here! */
+		  char entered[32];
+		  char *pptr = password;
+
+		  if (current_term->flags & TERM_DUMB)
+		    grub_printf ("\r                                    ");
+		  else
+		    gotoxy (1, 21);
+
+		  /* Wipe out the previously entered password */
+		  grub_memset (entered, 0, sizeof (entered));
+		  get_cmdline (" Password: ", entered, 31, '*', 0);
+
+		  while (! isspace (*pptr) && *pptr)
+		    pptr++;
+
+		  /* Make sure that PASSWORD is NUL-terminated.  */
+		  *pptr++ = 0;
+
+		  if (! check_password (entered, password, password_type))
+		    {
+		      char *new_file = config_file;
+		      while (isspace (*pptr))
+			pptr++;
+
+		      /* If *PPTR is NUL, then allow the user to use
+			 privileged instructions, otherwise, load
+			 another configuration file.  */
+		      if (*pptr != 0)
+			{
+			  while ((*(new_file++) = *(pptr++)) != 0)
+			    ;
+
+			  /* Make sure that the user will not have
+			     authority in the next configuration.  */
+			  auth = 0;
+			  return;
+			}
+		      else
+			{
+			  /* Now the user is superhuman.  */
+			  auth = 1;
+			  goto restart;
+			}
+		    }
+		  else
+		    {
+		      grub_printf ("Failed!\n      Press any key to continue...");
+		      getkey ();
+		      goto restart;
+		    }
+		}
+	    }
+	  else
+	    {
+	      if (c == 'e')
+		{
+		  int new_num_entries = 0, i = 0;
+		  char *new_heap;
+
+		  if (config_entries)
+		    {
+		      new_heap = heap;
+		      cur_entry = get_entry (config_entries,
+					     first_entry + entryno,
+					     1);
+		    }
+		  else
+		    {
+		      /* safe area! */
+		      new_heap = heap + NEW_HEAPSIZE + 1;
+		      cur_entry = get_entry (menu_entries,
+					     first_entry + entryno,
+					     0);
+		    }
+
+		  do
+		    {
+		      while ((*(new_heap++) = cur_entry[i++]) != 0);
+		      new_num_entries++;
+		    }
+		  while (config_entries && cur_entry[i]);
+
+		  /* this only needs to be done if config_entries is non-NULL,
+		     but it doesn't hurt to do it always */
+		  *(new_heap++) = 0;
+
+		  if (config_entries)
+		    run_menu (heap, NULL, new_num_entries, new_heap, 0);
+		  else
+		    {
+		      cls ();
+		      print_cmdline_message (CMDLINE_EDIT_MODE);
+
+		      new_heap = heap + NEW_HEAPSIZE + 1;
+
+		      saved_drive = boot_drive;
+		      saved_partition = install_partition;
+		      current_drive = GRUB_INVALID_DRIVE;
+
+		      if (! get_cmdline (CONFIG_PROMPT " edit> ", new_heap,
+					 NEW_HEAPSIZE + 1, 0, 1))
+			{
+			  int j = 0;
+
+			  /* get length of new command */
+			  while (new_heap[j++])
+			    ;
+
+			  if (j < 2)
+			    {
+			      j = 2;
+			      new_heap[0] = ' ';
+			      new_heap[1] = 0;
+			    }
+
+			  /* align rest of commands properly */
+			  grub_memmove (cur_entry + j, cur_entry + i,
+					(int) heap - ((int) cur_entry + i));
+
+			  /* copy command to correct area */
+			  grub_memmove (cur_entry, new_heap, j);
+
+			  heap += (j - i);
+			}
+		    }
+
+		  goto restart;
+		}
+	      if (c == 'c')
+		{
+		  enter_cmdline (heap, 0);
+		  goto restart;
+		}
+	      if (config_entries && c == 'a')
+		{
+		  int new_num_entries = 0, i = 0, j;
+		  int needs_padding, amount;
+		  char *new_heap;
+		  char * entries;
+		  char * entry_copy;
+		  char * append_line;
+		  char * start;
+
+		  entry_copy = new_heap = heap;
+		  cur_entry = get_entry (config_entries, first_entry + entryno,
+					 1);
+		  
+		  do
+		    {
+		      while ((*(new_heap++) = cur_entry[i++]) != 0);
+		      new_num_entries++;
+		    }
+		  while (config_entries && cur_entry[i]);
+
+		  /* this only needs to be done if config_entries is non-NULL,
+		     but it doesn't hurt to do it always */
+		  *(new_heap++) = 0;
+
+		  new_heap = heap + NEW_HEAPSIZE + 1;
+
+		  entries = entry_copy;
+		  while (*entries) 
+		    {
+		      if ((strstr(entries, "kernel") == entries) &&
+			  isspace(entries[6])) 
+			  break;
+
+		      while (*entries) entries++;
+		      entries++;
+		    }
+
+		  if (!*entries)
+		      goto restart;
+
+		  start = entries + 6;
+
+		  /* skip the white space */
+		  while (*start && isspace(*start)) start++;
+		  /* skip the kernel name */
+		  while (*start && !isspace(*start)) start++;
+
+		  /* skip the white space */
+		  needs_padding = (!*start || !isspace(*start));
+		  while (*start && isspace(*start)) start++;
+
+		  append_line = new_heap;
+		  grub_strcpy(append_line, start);
+
+		  cls();
+		  print_cmdline_message (CMDLINE_EDIT_MODE);
+
+		  if (get_cmdline(CONFIG_PROMPT " append> ", 
+				    append_line, NEW_HEAPSIZE + 1, 
+				    0, 1))
+		      goto restart;
+
+		  /* have new args; append_line points to the
+		     new args and start points to the old
+		     args */
+
+		  i = grub_strlen(start);
+		  j = grub_strlen(append_line);
+
+		  if (i > (j + needs_padding))
+		      amount = i;
+		  else
+		      amount = j + needs_padding;
+
+		  /* align rest of commands properly */
+		  memmove (start + j + needs_padding, start + i,
+		       ((int) append_line) - ((int) start) - (amount));
+
+		  if (needs_padding)
+		      *start = ' ';
+
+		  /* copy command to correct area */
+		  memmove (start + needs_padding, append_line, j);
+
+		  /* set up this entry to boot */
+		  config_entries = NULL;
+		  cur_entry = entry_copy;
+		  heap = new_heap;
+
+		  break;
+		}
+#ifdef GRUB_UTIL
+	      if (c == 'q')
+		{
+		  /* The same as ``quit''.  */
+		  stop ();
+		}
+#endif
+	    }
+	}
+    }
+