[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
+	    }
+	}
+    }
+  
+  /* Attempt to boot an entry.  */
+  
+ boot_entry:
+  
+  cls ();
+  setcursor (1);
+  
+  while (1)
+    {
+      if (config_entries)
+	printf ("  Booting \'%s\'\n\n",
+		get_entry (menu_entries, first_entry + entryno, 0));
+      else
+	printf ("  Booting command-list\n\n");
+
+      if (! cur_entry)
+	cur_entry = get_entry (config_entries, first_entry + entryno, 1);
+
+      /* Set CURRENT_ENTRYNO for the command "savedefault".  */
+      current_entryno = first_entry + entryno;
+      if (run_script (cur_entry, heap))
+	{
+	  if (fallback_entryno >= 0)
+	    {
+	      cur_entry = NULL;
+	      first_entry = 0;
+	      entryno = fallback_entries[fallback_entryno];
+	      fallback_entryno++;
+	      if (fallback_entryno >= MAX_FALLBACK_ENTRIES
+		  || fallback_entries[fallback_entryno] < 0)
+		fallback_entryno = -1;
+	    }
+	  else
+	    break;
+	}
+      else
+	break;
+    }
+
+      for(;;) ;
+  show_menu = 1;
+  goto restart;
+}
+
+
+static int
+get_line_from_config (char *cmdline, int maxlen, int read_from_file)
+{
+  int pos = 0, literal = 0, comment = 0;
+  char c;  /* since we're loading it a byte at a time! */
+  
+  while (1)
+    {
+      if (read_from_file)
+	{
+	  if (! grub_read (&c, 1))
+	    break;
+	}
+      else
+	{
+	  if (! read_from_preset_menu (&c, 1))
+	    break;
+	}
+
+      /* Skip all carriage returns.  */
+      if (c == '\r')
+	continue;
+
+      /* Replace tabs with spaces.  */
+      if (c == '\t')
+	c = ' ';
+
+      /* The previous is a backslash, then...  */
+      if (literal)
+	{
+	  /* If it is a newline, replace it with a space and continue.  */
+	  if (c == '\n')
+	    {
+	      c = ' ';
+	      
+	      /* Go back to overwrite a backslash.  */
+	      if (pos > 0)
+		pos--;
+	    }
+	    
+	  literal = 0;
+	}
+	  
+      /* translate characters first! */
+      if (c == '\\' && ! literal)
+	literal = 1;
+
+      if (comment)
+	{
+	  if (c == '\n')
+	    comment = 0;
+	}
+      else if (! pos)
+	{
+	  if (c == '#')
+	    comment = 1;
+	  else if ((c != ' ') && (c != '\n'))
+	    cmdline[pos++] = c;
+	}
+      else
+	{
+	  if (c == '\n')
+	    break;
+
+	  if (pos < maxlen)
+	    cmdline[pos++] = c;
+	}
+    }
+
+  cmdline[pos] = 0;
+
+  return pos;
+}
+
+static char configs[16384];
+
+/* This is the starting function in C.  */
+void
+grub_main (void)
+{
+  int config_len, menu_len, num_entries;
+  char *config_entries, *menu_entries;
+  char *kill_buf = (char *) KILL_BUF;
+  char myheap[256];
+
+  auto void reset (void);
+  void reset (void)
+    {
+      count_lines = -1;
+      config_len = 0;
+      menu_len = 0;
+      num_entries = 0;
+      config_entries = (char *)configs;// (char *) mbi.drives_addr + mbi.drives_length;
+      menu_entries = (char *) MENU_BUF;
+      init_config ();
+    }
+  
+  // /* Initialize the environment for restarting Stage 2.  */
+  // grub_setjmp (restart_env);
+  
+  /* Initialize the kill buffer.  */
+  *kill_buf = 0;
+  
+#if (defined(CONFIG_SERIAL_CONSOLE) && CONFIG_SERIAL_CONSOLE == 1) 
+  {
+    errnum=0;
+    memset(myheap, 0, 256);
+    run_script("serial --unit=0 --speed=9600\n\0", myheap); // dummy call
+    memset(myheap, 0, 256);
+#if !(defined(CONFIG_VGA_CONSOLE) && CONFIG_VGA_CONSOLE == 1 )
+    run_script("terminal serial\n\0", myheap);
+#endif
+  }
+#endif
+  
+  /* Never return.  */
+  for (;;)
+    {
+      int is_opened=0, is_preset=0;
+
+      reset ();
+      
+      
+      /* Here load the configuration file.  */
+      
+#ifdef GRUB_UTIL
+      if (use_config_file)
+#endif /* GRUB_UTIL */
+	{
+	  char *default_file = (char *) DEFAULT_FILE_BUF;
+	  int i;
+	  
+	  /* Get a saved default entry if possible.  */
+	  saved_entryno = 0;
+	  *default_file = 0;
+#if 0
+	  grub_strncat (default_file, config_file, DEFAULT_FILE_BUFLEN);
+	  for (i = grub_strlen(default_file); i >= 0; i--)
+	    if (default_file[i] == '/')
+	      {
+		i++;
+		break;
+	      }
+	  default_file[i] = 0;
+	  grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i);
+	  if (grub_open (default_file))
+	    {
+	      char buf[10]; /* This is good enough.  */
+	      char *p = buf;
+	      int len;
+	      
+	      len = grub_read (buf, sizeof (buf));
+	      if (len > 0)
+		{
+		  buf[sizeof (buf) - 1] = 0;
+		  safe_parse_maxint (&p, &saved_entryno);
+		}
+
+	      grub_close ();
+	    }
+#endif
+	  errnum = ERR_NONE;
+	  
+	  do
+	    {
+	      /* STATE 0:  Before any title command.
+		 STATE 1:  In a title command.
+		 STATE >1: In a entry after a title command.  */
+	      int state = 0, prev_config_len = 0, prev_menu_len = 0;
+	      char *cmdline;
+
+	      /* Try the preset menu first. This will succeed at most once,
+		 because close_preset_menu disables the preset menu.  */
+	      is_opened = is_preset = open_preset_menu ();
+	      if (! is_opened)
+		{
+		  grub_menulst();
+		  is_opened = grub_open (config_file);
+		  errnum = ERR_NONE;
+		}
+
+	      if (! is_opened) {
+                memset(myheap, 0, 256);
+		printf("Could not open menu.lst file '%s'. Entering command line.\n", config_file);
+#if CONFIG_VGA_CONSOLE && ! CONFIG_SERIAL_CONSOLE
+		run_script("terminal console\n\0", myheap);
+#elif !CONFIG_VGA_CONSOLE && CONFIG_SERIAL_CONSOLE
+		run_script("terminal serial\n\0", myheap);
+#elif CONFIG_VGA_CONSOLE && CONFIG_SERIAL_CONSOLE
+		run_script("terminal serial console\n\0", myheap);
+#endif
+		break;
+	      }
+
+	      /* This is necessary, because the menu must be overrided.  */
+	      reset ();
+	      
+	      cmdline = (char *) CMDLINE_BUF;
+	      while (get_line_from_config (cmdline, NEW_HEAPSIZE,
+					   ! is_preset))
+		{
+		  struct builtin *builtin;
+		  
+		  /* Get the pointer to the builtin structure.  */
+		  builtin = find_command (cmdline);
+		  errnum = 0;
+		  if (! builtin)
+		    /* Unknown command. Just skip now.  */
+		    continue;
+		  
+		  if (builtin->flags & BUILTIN_TITLE)
+		    {
+		      char *ptr;
+		      
+		      /* the command "title" is specially treated.  */
+		      if (state > 1)
+			{
+			  /* The next title is found.  */
+			  num_entries++;
+			  config_entries[config_len++] = 0;
+			  prev_menu_len = menu_len;
+			  prev_config_len = config_len;
+			}
+		      else
+			{
+			  /* The first title is found.  */
+			  menu_len = prev_menu_len;
+			  config_len = prev_config_len;
+			}
+		      
+		      /* Reset the state.  */
+		      state = 1;
+		      
+		      /* Copy title into menu area.  */
+		      ptr = skip_to (1, cmdline);
+		      while ((menu_entries[menu_len++] = *(ptr++)) != 0)
+			;
+		    }
+		  else if (! state)
+		    {
+		      /* Run a command found is possible.  */
+		      if (builtin->flags & BUILTIN_MENU)
+			{
+			  char *arg = skip_to (1, cmdline);
+			  (builtin->func) (arg, BUILTIN_MENU);
+			  errnum = 0;
+			}
+		      else
+			/* Ignored.  */
+			continue;
+		    }
+		  else
+		    {
+		      char *ptr = cmdline;
+		      
+		      state++;
+		      /* Copy config file data to config area.  */
+		      while ((config_entries[config_len++] = *ptr++) != 0)
+			;
+		    }
+		}
+	      
+	      if (state > 1)
+		{
+		  /* Finish the last entry.  */
+		  num_entries++;
+		  config_entries[config_len++] = 0;
+		}
+	      else
+		{
+		  menu_len = prev_menu_len;
+		  config_len = prev_config_len;
+		}
+	      
+	      menu_entries[menu_len++] = 0;
+	      config_entries[config_len++] = 0;
+	      grub_memmove (config_entries + config_len, menu_entries,
+			    menu_len);
+	      menu_entries = config_entries + config_len;
+
+	      /* Make sure that all fallback entries are valid.  */
+	      if (fallback_entryno >= 0)
+		{
+		  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
+		    {
+		      if (fallback_entries[i] < 0)
+			break;
+		      if (fallback_entries[i] >= num_entries)
+			{
+			  grub_memmove (fallback_entries + i,
+					fallback_entries + i + 1,
+					((MAX_FALLBACK_ENTRIES - i - 1)
+					 * sizeof (int)));
+			  i--;
+			}
+		    }
+
+		  if (fallback_entries[0] < 0)
+		    fallback_entryno = -1;
+		}
+	      /* Check if the default entry is present. Otherwise reset
+		 it to fallback if fallback is valid, or to DEFAULT_ENTRY 
+		 if not.  */
+	      if (default_entry >= num_entries)
+		{
+		  if (fallback_entryno >= 0)
+		    {
+		      default_entry = fallback_entries[0];
+		      fallback_entryno++;
+		      if (fallback_entryno >= MAX_FALLBACK_ENTRIES
+			  || fallback_entries[fallback_entryno] < 0)
+			fallback_entryno = -1;
+		    }
+		  else
+		    default_entry = 0;
+		}
+	      
+	      if (is_preset)
+		close_preset_menu ();
+	      else
+		grub_close ();
+	    }
+	  while (is_preset);
+	}
+
+      if (! num_entries)
+	{
+	  /* If no acceptable config file, goto command-line, starting
+	     heap from where the config entries would have been stored
+	     if there were any.  */
+	  enter_cmdline (config_entries, 1);
+	}
+      else
+	{
+	  /* Run menu interface.  */
+	  run_menu (menu_entries, config_entries, num_entries,
+		    menu_entries + menu_len, default_entry);
+	}
+    }
+}

Added: trunk/filo/main/grub/terminfo.c
===================================================================
--- trunk/filo/main/grub/terminfo.c	                        (rev 0)
+++ trunk/filo/main/grub/terminfo.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,259 @@
+/* terminfo.c - read a terminfo entry from the command line */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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.
+ *
+ * ######################################################################
+ *
+ * This file contains various functions dealing with different 
+ * terminal capabilities. It knows the difference between a vt52 and vt100 
+ * terminal (and much more) and is mainly used the terminal emulation
+ * in the serial driver.
+ */
+
+#include <libpayload.h>
+#include <grub/shared.h>
+#include <grub/terminfo.h>
+#include <grub/tparm.h>
+#include <grub/serial.h>
+
+/* Current terminal capabilities. Default is "vt100".  */
+struct terminfo term =
+  {
+    .name                = "vt100",
+    .cursor_address      = "\e[%i%p1%d;%p2%dH",
+    .clear_screen        = "\e[H\e[J",
+    .enter_standout_mode = "\e[7m",
+    .exit_standout_mode  = "\e[m"
+  };
+
+/* A number of escape sequences are provided in the string valued
+   capabilities for easy encoding of characters there.  Both \E and \e
+   map to an ESCAPE character, ^x maps to a control-x for any
+   appropriate x, and the sequences \n \l \r \t \b \f \s give a
+   newline, line-feed, return, tab, backspace, form-feed, and space.
+   Other escapes include \^ for ^, \\ for \, \, for comma, \: for :,
+   and \0 for null.  (\0 will produce \200, which does not terminate a
+   string but behaves as a null character on most terminals, provid­
+   ing CS7 is specified.  See stty(1).)  Finally, characters may be
+   given as three octal digits after a \.  */
+
+char *
+ti_unescape_memory (const char *in, const char *end) 
+{
+  static char out_buffer[256];
+  char c;
+  char *out;
+
+  out = out_buffer;
+  do
+    {
+      c = *(in++);
+      switch (c) 
+	{
+	case '^':
+	  if (*in >= 'A' && *in <= 'Z')
+	    {
+	      *out = (*in) - 'A';
+	      in++;
+	    }
+	  else
+	    {
+	      *out = '^';
+	    }
+	  break;
+	case '\\':
+	  c = *(in++);
+	  if (c >= '0' && c <= '9')
+	    {
+	      // octal number
+	      int n = 0;
+	      do
+		{
+		  n = (n << 4) | (c - '0');
+		  c = *(in++);
+		}
+	      while (c >= '0' && c <= '9');
+	      
+	      *out++ = (char)(n & 0xff);
+	      
+	      // redo last character
+	      in--;
+	      
+	      break;
+	    } 
+
+	  switch (c) 
+	    {
+	    case 'e':
+	    case 'E':
+	      *out++ = '\e';
+	      break;
+	    case 'n':
+	      *out++ = '\n';
+	      break;
+	    case 'r':
+	      *out++ = '\r';
+	      break;
+	    case 't':
+	      *out++ = '\t';
+	      break;
+	    case 'b':
+	      *out++ = '\b';
+	      break;
+	    case 'f':
+	      *out++ = '\f';
+	      break;
+	    case 's':
+	      *out++ = ' ';
+	      break;
+	    case '\\':
+	      *out++ = '\\';
+	      break;
+	    case '^':
+	      *out++ = '^';
+	      break;
+	    case ',':
+	      *out++ = ',';
+	      break;
+	    case ':':
+	      *out++ = ':';
+	      break;
+	    case '0':
+	      *out++ = '\200';
+	      break;
+	    }
+	  break;
+	default:
+	  *out++ = c;
+	  break;
+	}
+    }
+  while (in <= end);
+  
+  return out_buffer;
+}
+
+char *
+ti_unescape_string (const char *in) 
+{
+  return ti_unescape_memory (in, in + grub_strlen (in));
+}
+
+/* convert a memory region containing binary character into an external
+ * ascii representation. The binary characters will be replaced by an
+ * "ecsape notation". E.g. "033" will become "\e". */
+char *
+ti_escape_memory (const char *in, const char *end) 
+{
+  static char out_buffer[256];
+  char c;
+  char *out;
+
+  out = out_buffer;
+  do
+    {
+      c = *(in++);
+      switch (c)
+	{
+	case '\e':
+	  *out++ = '\\'; *out++ = 'e'; break;
+	case ' ':
+	  *out++ = '\\'; *out++ = 's'; break;
+	case '\\':
+	  *out++ = '\\'; *out++ = '\\'; break;
+	case '0' ... '9':
+	case 'a' ... 'z':
+	case 'A' ... 'Z':
+	case '%':
+	case '+':
+	case '-':
+	case '*':
+	case '/':
+	case ';':
+	case ':':
+	case '{':
+	case '}':
+	case '[':
+	case ']':
+	  *out++ = c; break;
+	case 0 ... 25:
+	  *out++ = '^'; *out++ = 'A' + c; break;
+	default:
+	  *out++ = '\\'; 
+	  *out++ = ((c >> 8) & 7) + '0';
+	  *out++ = ((c >> 4) & 7) + '0';
+	  *out++ = ((c >> 0) & 7) + '0';
+	  break;
+	}
+    }
+  while (in < end);
+  
+  *out++ = 0;
+  
+  return out_buffer;
+}
+
+/* convert a string containing binary character into an external ascii
+ * representation. */
+char *
+ti_escape_string (const char *in) 
+{
+  return ti_escape_memory (in, in + grub_strlen (in));
+}
+
+/* move the cursor to the given position starting with "0". */
+void
+ti_cursor_address (int x, int y)
+{
+  grub_putstr (grub_tparm (term.cursor_address, y, x));
+}
+
+/* clear the screen. */
+void 
+ti_clear_screen (void)
+{
+  grub_putstr (grub_tparm (term.clear_screen));
+}
+
+/* enter reverse video */
+void 
+ti_enter_standout_mode (void)
+{
+  grub_putstr (grub_tparm (term.enter_standout_mode));
+}
+
+/* exit reverse video */
+void 
+ti_exit_standout_mode (void)
+{
+  grub_putstr (grub_tparm (term.exit_standout_mode));
+}
+
+/* set the current terminal emulation to use */
+void 
+ti_set_term (const struct terminfo *new)
+{
+  grub_memmove (&term, new, sizeof (struct terminfo));
+}
+
+/* get the current terminal emulation */
+void
+ti_get_term(struct terminfo *copy)
+{
+  grub_memmove (copy, &term, sizeof (struct terminfo));
+}

Added: trunk/filo/main/grub/tparm.c
===================================================================
--- trunk/filo/main/grub/tparm.c	                        (rev 0)
+++ trunk/filo/main/grub/tparm.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,724 @@
+/****************************************************************************
+ * Copyright (c) 1998,2000,2002 Free Software Foundation, Inc.              *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+/**********************************************************************
+ * This code is a modification of lib_tparm.c found in ncurses-5.2. The
+ * modification are for use in grub by replacing all libc function through
+ * special grub functions. This also meant to delete all dynamic memory
+ * allocation and replace it by a number of fixed buffers.
+ *
+ * Modifications by Tilmann Bubeck <t.bubeck at reinform.de> 2002
+ **********************************************************************/
+
+/****************************************************************************
+ *  Author: Zeyd M. Ben-Halim <zmbenhal at netcom.com> 1992,1995               *
+ *     and: Eric S. Raymond <esr at snark.thyrsus.com>                         *
+ ****************************************************************************/
+
+/*
+ *	tparm.c
+ *
+ */
+
+#include <libpayload.h>
+#include <grub/shared.h>
+#include <grub/tparm.h>
+
+/*
+ * Common/troublesome character definitions
+ */
+typedef char grub_bool;
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#ifndef FALSE
+# define FALSE (0)
+#endif
+#ifndef TRUE
+# define TRUE (!FALSE)
+#endif
+#define MAX_FORMAT_LEN 256
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+/*
+ *	char *
+ *	tparm(string, ...)
+ *
+ *	Substitute the given parameters into the given string by the following
+ *	rules (taken from terminfo(5)):
+ *
+ *	     Cursor addressing and other strings  requiring  parame-
+ *	ters in the terminal are described by a parameterized string
+ *	capability, with like escapes %x in  it.   For  example,  to
+ *	address  the  cursor, the cup capability is given, using two
+ *	parameters: the row and column to  address  to.   (Rows  and
+ *	columns  are  numbered  from  zero and refer to the physical
+ *	screen visible to the user, not to any  unseen  memory.)  If
+ *	the terminal has memory relative cursor addressing, that can
+ *	be indicated by
+ *
+ *	     The parameter mechanism uses  a  stack  and  special  %
+ *	codes  to manipulate it.  Typically a sequence will push one
+ *	of the parameters onto the stack and then print it  in  some
+ *	format.  Often more complex operations are necessary.
+ *
+ *	     The % encodings have the following meanings:
+ *
+ *	     %%        outputs `%'
+ *	     %c        print pop() like %c in printf()
+ *	     %s        print pop() like %s in printf()
+ *           %[[:]flags][width[.precision]][doxXs]
+ *                     as in printf, flags are [-+#] and space
+ *                     The ':' is used to avoid making %+ or %-
+ *                     patterns (see below).
+ *
+ *	     %p[1-9]   push ith parm
+ *	     %P[a-z]   set dynamic variable [a-z] to pop()
+ *	     %g[a-z]   get dynamic variable [a-z] and push it
+ *	     %P[A-Z]   set static variable [A-Z] to pop()
+ *	     %g[A-Z]   get static variable [A-Z] and push it
+ *	     %l        push strlen(pop)
+ *	     %'c'      push char constant c
+ *	     %{nn}     push integer constant nn
+ *
+ *	     %+ %- %* %/ %m
+ *	               arithmetic (%m is mod): push(pop() op pop())
+ *	     %& %| %^  bit operations: push(pop() op pop())
+ *	     %= %> %<  logical operations: push(pop() op pop())
+ *	     %A %O     logical and & or operations for conditionals
+ *	     %! %~     unary operations push(op pop())
+ *	     %i        add 1 to first two parms (for ANSI terminals)
+ *
+ *	     %? expr %t thenpart %e elsepart %;
+ *	               if-then-else, %e elsepart is optional.
+ *	               else-if's are possible ala Algol 68:
+ *	               %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
+ *
+ *	For those of the above operators which are binary and not commutative,
+ *	the stack works in the usual way, with
+ *			%gx %gy %m
+ *	resulting in x mod y, not the reverse.
+ */
+
+#define STACKSIZE	20
+
+typedef struct {
+    union {
+	unsigned int num;
+	char *str;
+    } data;
+    grub_bool num_type;
+} stack_frame;
+
+static stack_frame stack[STACKSIZE];
+static int stack_ptr;
+
+static char out_buff[256];
+static int out_size = 256;
+static int out_used;
+
+static inline void
+get_space(int need)
+{
+    need += out_used;
+    if (need > out_size) {
+	// FIX ME! buffer full, what now?
+	;
+    }
+}
+
+static inline void
+save_text(const char *fmt, const char *s, int len)
+{
+    int s_len = grub_strlen(s);
+    if (len > (int) s_len)
+	s_len = len;
+
+    get_space(s_len + 1);
+
+    (void) grub_sprintf(out_buff + out_used, fmt, s);
+    out_used += grub_strlen(out_buff + out_used);
+}
+
+static inline void
+save_number(const char *fmt, int number, int len)
+{
+    if (len < 30)
+	len = 30;		/* actually log10(MAX_INT)+1 */
+
+    get_space(len + 1);
+
+    (void) grub_sprintf(out_buff + out_used, fmt, number);
+    out_used += grub_strlen(out_buff + out_used);
+}
+
+static inline void
+save_char(int c)
+{
+    if (c == 0)
+	c = 0200;
+    get_space(1);
+    out_buff[out_used++] = c;
+}
+
+static inline void
+npush(int x)
+{
+    if (stack_ptr < STACKSIZE) {
+	stack[stack_ptr].num_type = TRUE;
+	stack[stack_ptr].data.num = x;
+	stack_ptr++;
+    }
+}
+
+static inline int
+npop(void)
+{
+    int result = 0;
+    if (stack_ptr > 0) {
+	stack_ptr--;
+	if (stack[stack_ptr].num_type)
+	    result = stack[stack_ptr].data.num;
+    }
+    return result;
+}
+
+static inline void
+spush(char *x)
+{
+    if (stack_ptr < STACKSIZE) {
+	stack[stack_ptr].num_type = FALSE;
+	stack[stack_ptr].data.str = x;
+	stack_ptr++;
+    }
+}
+
+static inline char *
+spop(void)
+{
+    static char dummy[] = "";	/* avoid const-cast */
+    char *result = dummy;
+    if (stack_ptr > 0) {
+	stack_ptr--;
+	if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
+	    result = stack[stack_ptr].data.str;
+    }
+    return result;
+}
+
+static inline const char *
+parse_format(const char *s, char *format, int *len)
+{
+    grub_bool done = FALSE;
+    grub_bool allowminus = FALSE;
+    grub_bool dot = FALSE;
+    grub_bool err = FALSE;
+    char *fmt = format;
+    int prec = 0;
+    int width = 0;
+    int value = 0;
+
+    *len = 0;
+    *format++ = '%';
+    while (*s != '\0' && !done) {
+	switch (*s) {
+	case 'c':		/* FALLTHRU */
+	case 'd':		/* FALLTHRU */
+	case 'o':		/* FALLTHRU */
+	case 'x':		/* FALLTHRU */
+	case 'X':		/* FALLTHRU */
+	case 's':
+	    *format++ = *s;
+	    done = TRUE;
+	    break;
+	case '.':
+	    *format++ = *s++;
+	    if (dot) {
+		err = TRUE;
+	    } else {
+		dot = TRUE;
+		prec = value;
+	    }
+	    value = 0;
+	    break;
+	case '#':
+	    *format++ = *s++;
+	    break;
+	case ' ':
+	    *format++ = *s++;
+	    break;
+	case ':':
+	    s++;
+	    allowminus = TRUE;
+	    break;
+	case '-':
+	    if (allowminus) {
+		*format++ = *s++;
+	    } else {
+		done = TRUE;
+	    }
+	    break;
+	default:
+	    if (isdigit(*s)) {
+		value = (value * 10) + (*s - '0');
+		if (value > 10000)
+		    err = TRUE;
+		*format++ = *s++;
+	    } else {
+		done = TRUE;
+	    }
+	}
+    }
+
+    /*
+     * If we found an error, ignore (and remove) the flags.
+     */
+    if (err) {
+	prec = width = value = 0;
+	format = fmt;
+	*format++ = '%';
+	*format++ = *s;
+    }
+
+    if (dot)
+	width = value;
+    else
+	prec = value;
+
+    *format = '\0';
+    /* return maximum string length in print */
+    *len = (prec > width) ? prec : width;
+    return s;
+}
+
+#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
+
+static inline char *
+tparam_internal(const char *string, int *dataptr)
+{
+#define NUM_VARS 26
+    char *p_is_s[9];
+    int param[9];
+    int lastpop;
+    int popcount;
+    int number;
+    int len;
+    int level;
+    int x, y;
+    int i;
+    int len2;
+    register const char *cp;
+    static int len_fmt = MAX_FORMAT_LEN;
+    static char dummy[] = "";
+    static char format[MAX_FORMAT_LEN];
+    static int dynamic_var[NUM_VARS];
+    static int static_vars[NUM_VARS];
+
+    out_used = 0;
+    if (string == NULL)
+	return NULL;
+
+    if ((len2 = grub_strlen(string)) > len_fmt) {
+	return NULL;
+    }
+
+    /*
+     * Find the highest parameter-number referred to in the format string.
+     * Use this value to limit the number of arguments copied from the
+     * variable-length argument list.
+     */
+
+    number = 0;
+    lastpop = -1;
+    popcount = 0;
+    grub_memset(p_is_s, 0, sizeof(p_is_s));
+
+    /*
+     * Analyze the string to see how many parameters we need from the varargs
+     * list, and what their types are.  We will only accept string parameters
+     * if they appear as a %l or %s format following an explicit parameter
+     * reference (e.g., %p2%s).  All other parameters are numbers.
+     *
+     * 'number' counts coarsely the number of pop's we see in the string, and
+     * 'popcount' shows the highest parameter number in the string.  We would
+     * like to simply use the latter count, but if we are reading termcap
+     * strings, there may be cases that we cannot see the explicit parameter
+     * numbers.
+     */
+    for (cp = string; (cp - string) < (int) len2;) {
+	if (*cp == '%') {
+	    cp++;
+	    cp = parse_format(cp, format, &len);
+	    switch (*cp) {
+	    default:
+		break;
+
+	    case 'd':		/* FALLTHRU */
+	    case 'o':		/* FALLTHRU */
+	    case 'x':		/* FALLTHRU */
+	    case 'X':		/* FALLTHRU */
+	    case 'c':		/* FALLTHRU */
+		number++;
+		lastpop = -1;
+		break;
+
+	    case 'l':
+	    case 's':
+		if (lastpop > 0)
+		    p_is_s[lastpop - 1] = dummy;
+		++number;
+		break;
+
+	    case 'p':
+		cp++;
+		i = (*cp - '0');
+		if (i >= 0 && i <= 9) {
+		    lastpop = i;
+		    if (lastpop > popcount)
+			popcount = lastpop;
+		}
+		break;
+
+	    case 'P':
+	    case 'g':
+		cp++;
+		break;
+
+	    case '\'':
+		cp += 2;
+		lastpop = -1;
+		break;
+
+	    case '{':
+		cp++;
+		while (*cp >= '0' && *cp <= '9') {
+		    cp++;
+		}
+		break;
+
+	    case '+':
+	    case '-':
+	    case '*':
+	    case '/':
+	    case 'm':
+	    case 'A':
+	    case 'O':
+	    case '&':
+	    case '|':
+	    case '^':
+	    case '=':
+	    case '<':
+	    case '>':
+	    case '!':
+	    case '~':
+		lastpop = -1;
+		number += 2;
+		break;
+
+	    case 'i':
+		lastpop = -1;
+		if (popcount < 2)
+		    popcount = 2;
+		break;
+	    }
+	}
+	if (*cp != '\0')
+	    cp++;
+    }
+
+    if (number > 9)
+	number = 9;
+    for (i = 0; i < max(popcount, number); i++) {
+	/*
+	 * A few caps (such as plab_norm) have string-valued parms.
+	 * We'll have to assume that the caller knows the difference, since
+	 * a char* and an int may not be the same size on the stack.
+	 */
+	if (p_is_s[i] != 0) {
+	  p_is_s[i] = (char *)(*(dataptr++));
+	} else {
+	  param[i] = (int)(*(dataptr++));
+	}
+    }
+
+    /*
+     * This is a termcap compatibility hack.  If there are no explicit pop
+     * operations in the string, load the stack in such a way that
+     * successive pops will grab successive parameters.  That will make
+     * the expansion of (for example) \E[%d;%dH work correctly in termcap
+     * style, which means tparam() will expand termcap strings OK.
+     */
+    stack_ptr = 0;
+    if (popcount == 0) {
+	popcount = number;
+	for (i = number - 1; i >= 0; i--)
+	    npush(param[i]);
+    }
+
+    while (*string) {
+        /* skip delay timings */
+	if (*string == '$' && *(string + 1) == '<') {
+	    while( *string && *string != '>') 
+	        string++;
+	    if ( *string == '>' ) string++;
+	} else if ( *string == '%') {
+	    string++;
+	    string = parse_format(string, format, &len);
+	    switch (*string) {
+	    default:
+		break;
+	    case '%':
+		save_char('%');
+		break;
+
+	    case 'd':		/* FALLTHRU */
+	    case 'o':		/* FALLTHRU */
+	    case 'x':		/* FALLTHRU */
+	    case 'X':		/* FALLTHRU */
+	    case 'c':		/* FALLTHRU */
+		save_number(format, npop(), len);
+		break;
+
+	    case 'l':
+		save_number("%d", strlen(spop()), 0);
+		break;
+
+	    case 's':
+		save_text(format, spop(), len);
+		break;
+
+	    case 'p':
+		string++;
+		i = (*string - '1');
+		if (i >= 0 && i < 9) {
+		    if (p_is_s[i])
+			spush(p_is_s[i]);
+		    else
+			npush(param[i]);
+		}
+		break;
+
+	    case 'P':
+		string++;
+		if (isUPPER(*string)) {
+		    i = (*string - 'A');
+		    static_vars[i] = npop();
+		} else if (isLOWER(*string)) {
+		    i = (*string - 'a');
+		    dynamic_var[i] = npop();
+		}
+		break;
+
+	    case 'g':
+		string++;
+		if (isUPPER(*string)) {
+		    i = (*string - 'A');
+		    npush(static_vars[i]);
+		} else if (isLOWER(*string)) {
+		    i = (*string - 'a');
+		    npush(dynamic_var[i]);
+		}
+		break;
+
+	    case '\'':
+		string++;
+		npush(*string);
+		string++;
+		break;
+
+	    case '{':
+		number = 0;
+		string++;
+		while (*string >= '0' && *string <= '9') {
+		    number = number * 10 + *string - '0';
+		    string++;
+		}
+		npush(number);
+		break;
+
+	    case '+':
+		npush(npop() + npop());
+		break;
+
+	    case '-':
+		y = npop();
+		x = npop();
+		npush(x - y);
+		break;
+
+	    case '*':
+		npush(npop() * npop());
+		break;
+
+	    case '/':
+		y = npop();
+		x = npop();
+		npush(y ? (x / y) : 0);
+		break;
+
+	    case 'm':
+		y = npop();
+		x = npop();
+		npush(y ? (x % y) : 0);
+		break;
+
+	    case 'A':
+		npush(npop() && npop());
+		break;
+
+	    case 'O':
+		npush(npop() || npop());
+		break;
+
+	    case '&':
+		npush(npop() & npop());
+		break;
+
+	    case '|':
+		npush(npop() | npop());
+		break;
+
+	    case '^':
+		npush(npop() ^ npop());
+		break;
+
+	    case '=':
+		y = npop();
+		x = npop();
+		npush(x == y);
+		break;
+
+	    case '<':
+		y = npop();
+		x = npop();
+		npush(x < y);
+		break;
+
+	    case '>':
+		y = npop();
+		x = npop();
+		npush(x > y);
+		break;
+
+	    case '!':
+		npush(!npop());
+		break;
+
+	    case '~':
+		npush(~npop());
+		break;
+
+	    case 'i':
+		if (p_is_s[0] == 0)
+		    param[0]++;
+		if (p_is_s[1] == 0)
+		    param[1]++;
+		break;
+
+	    case '?':
+		break;
+
+	    case 't':
+		x = npop();
+		if (!x) {
+		    /* scan forward for %e or %; at level zero */
+		    string++;
+		    level = 0;
+		    while (*string) {
+			if (*string == '%') {
+			    string++;
+			    if (*string == '?')
+				level++;
+			    else if (*string == ';') {
+				if (level > 0)
+				    level--;
+				else
+				    break;
+			    } else if (*string == 'e' && level == 0)
+				break;
+			}
+
+			if (*string)
+			    string++;
+		    }
+		}
+		break;
+
+	    case 'e':
+		/* scan forward for a %; at level zero */
+		string++;
+		level = 0;
+		while (*string) {
+		    if (*string == '%') {
+			string++;
+			if (*string == '?')
+			    level++;
+			else if (*string == ';') {
+			    if (level > 0)
+				level--;
+			    else
+				break;
+			}
+		    }
+
+		    if (*string)
+			string++;
+		}
+		break;
+
+	    case ';':
+		break;
+
+	    }			/* endswitch (*string) */
+	} else {             	/* endelse (*string == '%') */
+	    save_char(*string);
+	}
+
+	if (*string == '\0')
+	    break;
+
+	string++;
+    }				/* endwhile (*string) */
+
+    get_space(1);
+    out_buff[out_used] = '\0';
+
+    return (out_buff);
+}
+
+char *
+grub_tparm(const char *string,...)
+{
+    char *result;
+    int *dataptr = (int *) &string;
+
+    dataptr++;
+
+    result = tparam_internal(string, dataptr);
+
+    return result;
+}

Added: trunk/filo/main/grub.c
===================================================================
--- trunk/filo/main/grub.c	                        (rev 0)
+++ trunk/filo/main/grub.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,119 @@
+/*
+ * 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 <lib.h>
+#include <fs.h>
+#include <arch/timer.h>
+
+extern char config_file[];
+// #include <grub/shared.h>
+
+#define ENTER '\r'
+#define ESCAPE '\x1b'
+
+#ifndef CONFIG_MENULST_TIMEOUT
+#define CONFIG_MENULST_TIMEOUT 0
+#endif
+#if !CONFIG_MENULST_TIMEOUT
+#define menulst_delay() 0 /* success */
+#endif
+
+#ifdef CONFIG_USE_GRUB
+#if CONFIG_MENULST_TIMEOUT
+static inline int menulst_delay(void)
+{
+    unsigned int timeout;
+    int sec, tmp;
+    char key;
+    
+    key = 0;
+
+#ifdef CONFIG_MENULST_FILE
+    printf("Press <Enter> for default menu.lst (%s), or <Esc> for prompt... ",
+		    CONFIG_MENULST_FILE);
+#else
+    printf("Press <Enter> for the FILO shell or <ESC> to enter a menu.lst path...");
+#endif    
+    for (sec = CONFIG_MENULST_TIMEOUT; 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_MENULST_TIMEOUT */
+
+void grub_menulst(void)
+{
+    char line[256];
+
+    /* If Escape key is pressed already, skip autoboot */
+    if (havechar() && getchar()==ESCAPE)
+	return;
+
+    if (menulst_delay()==0) {
+#ifdef CONFIG_MENULST_FILE
+	printf("menu: %s\n", CONFIG_MENULST_FILE);
+	strcpy(config_file, CONFIG_MENULST_FILE);
+#endif
+    } else {
+	    /* The above didn't work, ask user */
+        while (havechar())
+   	    getchar();
+
+#ifdef CONFIG_MENULST_FILE
+        strncpy(line, CONFIG_MENULST_FILE, sizeof(line)-1);
+        line[sizeof(line)-1] = '\0';
+#else
+        line[0] = '\0';
+#endif
+        for (;;) {
+	    printf("menu: ");
+	    getline(line, sizeof line);
+
+	    if (strcmp(line,"quit")==0) break;
+
+	    if (line[0]) {
+	        strcpy(config_file, line);
+		break;
+	    }
+        }
+    }
+
+    
+}
+#endif /* CONFIG_USE_GRUB */
+

Added: trunk/filo/main/ipchecksum.c
===================================================================
--- trunk/filo/main/ipchecksum.c	                        (rev 0)
+++ trunk/filo/main/ipchecksum.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,73 @@
+/*
+ * 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
+ */
+
+
+/* Taken from Etherboot */
+
+#include <ipchecksum.h>
+
+unsigned short ipchksum(const void *data, unsigned long length)
+{
+	unsigned long sum;
+	unsigned long i;
+	const unsigned char *ptr;
+	union {
+	    unsigned char byte[2];
+	    unsigned short word;
+	} u;
+
+	/* In the most straight forward way possible,
+	 * compute an ip style checksum.
+	 */
+	sum = 0;
+	ptr = data;
+	for(i = 0; i < length; i++) {
+		unsigned long value;
+		value = ptr[i];
+		if (i & 1) {
+			value <<= 8;
+		}
+		/* Add the new value */
+		sum += value;
+		/* Wrap around the carry */
+		if (sum > 0xFFFF) {
+			sum = (sum + (sum >> 16)) & 0xFFFF;
+		}
+	}
+	u.byte[0] = (unsigned char) sum;
+	u.byte[1] = (unsigned char) (sum >> 8);
+	return (unsigned short) ~u.word;
+}
+
+unsigned short add_ipchksums(unsigned long offset, unsigned short sum, unsigned short new)
+{
+	unsigned long checksum;
+	sum = ~sum & 0xFFFF;
+	new = ~new & 0xFFFF;
+	if (offset & 1) {
+		/* byte swap the sum if it came from an odd offset 
+		 * since the computation is endian independant this
+		 * works.
+		 */
+		new = (new << 8) | (new >> 8);
+	}
+	checksum = sum + new;
+	if (checksum > 0xFFFF) {
+		checksum -= 0xFFFF;
+	}
+	return (~checksum) & 0xFFFF;
+}

Added: trunk/filo/main/sound.c
===================================================================
--- trunk/filo/main/sound.c	                        (rev 0)
+++ trunk/filo/main/sound.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,71 @@
+/*
+ * 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 <sound.h>
+#include <pci.h>
+
+static struct sound_ops *ops;
+
+int sound_init(void)
+{
+    struct sound_driver *drv;
+    pcidev_t dev = 0;
+
+    for (drv = sound_drivers_start; drv < sound_drivers_end; drv++) {
+	if (pci_find_device(drv->vendor, drv->device, &dev)) {
+	    if (drv->ops->init(dev) == 0) {
+		ops = drv->ops;
+		return 0;
+	    }
+	}
+    }
+    printf("No sound device found\n");
+    return -1;
+}
+
+void sound_set_rate(int rate)
+{
+    if (ops && ops->set_rate)
+	ops->set_rate(rate);
+}
+
+void sound_set_volume(int volume)
+{
+    if (ops && ops->set_volume)
+	ops->set_volume(volume);
+}
+
+int sound_write(const void *buf, int size)
+{
+    if (ops && ops->write)
+	return ops->write(buf, size);
+    return -1;
+}
+
+int sound_is_active(void)
+{
+    if (ops && ops->is_active)
+	return ops->is_active();
+    return 0;
+}
+
+void sound_stop(void)
+{
+    if (ops && ops->stop)
+	ops->stop();
+}

Added: trunk/filo/main/strtox.c
===================================================================
--- trunk/filo/main/strtox.c	                        (rev 0)
+++ trunk/filo/main/strtox.c	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
+ */
+
+
+/*  Adapted from LinuxBIOS */
+
+/*
+ *
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ */
+
+#include <libpayload.h>
+
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((*cp == 'x') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	}
+	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+	    ? toupper(*cp) : *cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+unsigned long long strtoull_with_suffix(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long long result;
+
+	if (!endp) {
+	    printf("%s must be called with endp\n", __FUNCTION__);
+	    return 0;
+	}
+	result = simple_strtoull(cp, endp, base);
+	switch (toupper(**endp)) {
+	case 'K':
+		result <<= 10;
+		++*endp;
+		break;
+	case 'M':
+		result <<= 20;
+		++*endp;
+		break;
+	case 'G':
+		result <<= 30;
+		++*endp;
+		break;
+	}
+	return result;
+}
+

Added: trunk/filo/payload.sh
===================================================================
--- trunk/filo/payload.sh	                        (rev 0)
+++ trunk/filo/payload.sh	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# This is a trivial payload finder script for abuild
+#
+echo "`dirname $0`/build/filo.elf"


Property changes on: trunk/filo/payload.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/filo/util/Makefile.inc
===================================================================
--- trunk/filo/util/Makefile.inc	                        (rev 0)
+++ trunk/filo/util/Makefile.inc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+EBCHECKSUM = ebchecksum.o ipchecksum.o checksum_elf32le.o checksum_elf32be.o checksum_elf64le.o checksum_elf64be.o
+EBCHECKSUM_OBJS     := $(patsubst %,$(obj)/util/%,$(EBCHECKSUM))
+
+$(obj)/util/ebchecksum: $(EBCHECKSUM_OBJS)
+	@echo "  HOSTCC  $@"
+	@$(HOSTCC) $(HOSTCFLAGS) $(EBCHECKSUM_OBJS) -o $@
+
+$(obj)/util/%.o: $(src)/util/%.c
+	@echo "  HOSTCC  $<"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -c $< -o $@
+
+$(obj)/util/ipchecksum.o: $(src)/main/ipchecksum.c
+	@echo "  HOSTCC  $<"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -c $< -o $@
+
+$(obj)/util/checksum_elf32le.o: util/checksum_elf.c
+	@echo "  HOSTCC  $< -> `basename $@`"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -DTARGET_CLASS=ELFCLASS32 -DTARGET_DATA=ELFDATA2LSB -c $< -o $@
+$(obj)/util/checksum_elf32be.o: util/checksum_elf.c
+	@echo "  HOSTCC  $< -> `basename $@`"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -DTARGET_CLASS=ELFCLASS32 -DTARGET_DATA=ELFDATA2MSB -c $< -o $@
+$(obj)/util/checksum_elf64le.o: util/checksum_elf.c
+	@echo "  HOSTCC  $< -> `basename $@`"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -DTARGET_CLASS=ELFCLASS64 -DTARGET_DATA=ELFDATA2LSB -c $< -o $@
+$(obj)/util/checksum_elf64be.o: util/checksum_elf.c
+	@echo "  HOSTCC  $< -> `basename $@`"
+	@$(HOSTCC) $(HOSTCFLAGS) -Iinclude -DTARGET_CLASS=ELFCLASS64 -DTARGET_DATA=ELFDATA2MSB -c $< -o $@
+
+$(obj)/util/vmser: vmser.o
+	@echo "  HOSTCC  $<"
+	@$(HOSTCC) $(HOSTCFLAGS) vmser.o -lcurses -o $@
+

Added: trunk/filo/util/byteorder.h
===================================================================
--- trunk/filo/util/byteorder.h	                        (rev 0)
+++ trunk/filo/util/byteorder.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,39 @@
+/*
+ * 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 _BYTESWAP_H
+#define _BYTESWAP_H
+#include <stdint.h>
+/* These are unportable GNU functions */
+
+static inline uint16_t bswap_16(uint16_t x)
+{
+	return (x>>8) | (x<<8);
+}
+
+static inline uint32_t bswap_32(uint32_t x)
+{
+	return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16));
+}
+
+static inline uint64_t bswap_64(uint64_t x)
+{
+	return (((uint64_t)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32));
+}
+
+#endif

Added: trunk/filo/util/checksum_elf.c
===================================================================
--- trunk/filo/util/checksum_elf.c	                        (rev 0)
+++ trunk/filo/util/checksum_elf.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,327 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(__GLIBC__)
+#define USE_BSD
+#include <endian.h>
+#include <byteswap.h>
+#else
+#include "byteorder.h"
+#endif
+#define STDINT_H
+#include "elf.h"
+#include "elf_boot.h"
+#include "ipchecksum.h"
+#include "ebchecksum.h"
+
+#if TARGET_DATA != ELFDATA2LSB && TARGET_DATA != ELFDATA2MSB
+#error Invalid TARGET_DATA 
+#endif
+
+#if TARGET_CLASS == ELFCLASS32
+# define Elf_Ehdr Elf32_Ehdr
+# define Elf_Phdr Elf32_Phdr
+# if TARGET_DATA == ELFDATA2LSB
+#  define checksum_elf checksum_elf32le
+# else
+#  define checksum_elf checksum_elf32be
+# endif
+#elif TARGET_CLASS == ELFCLASS64
+# define Elf_Ehdr Elf64_Ehdr
+# define Elf_Phdr Elf64_Phdr
+# if TARGET_DATA == ELFDATA2LSB
+#  define checksum_elf checksum_elf64le
+# else
+#  define checksum_elf checksum_elf64be
+# endif
+#else
+# error Invalid TARGET_CLASS 
+#endif
+
+#define HOST_DATA (BYTE_ORDER==BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB)
+#if HOST_DATA != TARGET_DATA
+# define BSWAP(x) \
+    sizeof(x)==1 ? (x) \
+    : sizeof(x)==2 ? bswap_16(x) \
+    : sizeof(x)==4 ? bswap_32(x) \
+    : sizeof(x)==8 ? bswap_64(x) \
+    : *(int*)0 /* Error, do a segfault to catch */
+#else
+# define BSWAP(x) (x) /* nop */
+#endif
+
+static int process_note_segment(FILE *fp, const char *filename,
+	off_t note_off, unsigned long note_size, 
+	unsigned short *image_sum_ptr, off_t *sum_offset_ptr)
+{
+    int retval = -1;
+    void *notes = NULL;
+    unsigned long note_addr, note_end;
+    Elf_Nhdr *nhdr;
+    unsigned int namesz, descsz, type;
+    char *name;
+    void *desc;
+
+    notes = malloc(note_size);
+    if (!notes) {
+	perror("Can't allocate memory for notes");
+	goto out;
+    }
+    if (fseek(fp, note_off, SEEK_SET) != 0) {
+	perror("Can't seek to notes");
+	goto out;
+    }
+    if (fread(notes, note_size, 1, fp) != 1) {
+	perror("Can't read notes");
+	goto out;
+    }
+
+    /* Find note for ELFBoot checksum */
+    retval = 0;
+    note_addr = (unsigned long) notes;
+    note_end = note_addr + note_size;
+    while (note_addr < note_end) {
+	nhdr = (Elf_Nhdr *) note_addr;
+	namesz = BSWAP(nhdr->n_namesz);
+	descsz = BSWAP(nhdr->n_descsz);
+	type = BSWAP(nhdr->n_type);
+	note_addr += sizeof(Elf_Nhdr);
+	name = (char *) note_addr;
+	note_addr += (namesz + 3) & ~3;
+	desc = (void *) note_addr;
+	note_addr += (descsz + 3) & ~3;
+
+	if (namesz != sizeof(ELF_NOTE_BOOT)
+		|| memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) != 0)
+	    continue;
+
+	if (verbose >= 2) {
+	    if (type == EIN_PROGRAM_NAME)
+		printf("Program name: %.*s\n", (int) descsz, (char *) desc);
+	    else if (type == EIN_PROGRAM_VERSION)
+		printf("Program version: %.*s\n", (int) descsz, (char *) desc);
+	}
+	if (type == EIN_PROGRAM_CHECKSUM) {
+	    retval = 1;
+	    *image_sum_ptr = BSWAP(*(unsigned short *) desc);
+	    if (verbose >= 2)
+		printf("Image checksum: %#04x\n", *image_sum_ptr);
+	    /* Where in the file */
+	    *sum_offset_ptr = note_off
+		+ (unsigned long) desc - (unsigned long) notes;
+	}
+    }
+out:
+    if (notes)
+	free(notes);
+    return retval;
+}
+
+static int do_checksum(FILE *fp, const char *filename, Elf_Ehdr *ehdr, Elf_Phdr *phdr)
+{
+    char buf[8192];
+    unsigned short sum, part_sum;
+    off_t offset;
+    unsigned long phsize;
+    unsigned long seg_size, to_read, size_read;
+    int i;
+
+    sum = ipchksum(ehdr, sizeof *ehdr);
+    offset = sizeof ehdr;
+
+    phsize = BSWAP(ehdr->e_phnum) * sizeof(*phdr);
+    part_sum = ipchksum(phdr, phsize);
+    sum = add_ipchksums(offset, sum, part_sum);
+    offset += phsize;
+    for (i = 0; i < (BSWAP(ehdr->e_phnum)); i++) {
+	if (BSWAP(phdr[i].p_type) != PT_LOAD)
+	    continue;
+
+	if (fseek(fp, BSWAP(phdr[i].p_offset), SEEK_SET) != 0) {
+	    perror("Can't seek to program segment");
+	    return -1;
+	}
+	seg_size = BSWAP(phdr[i].p_filesz);
+	while (seg_size > 0) {
+	    to_read = seg_size;
+	    if (to_read > sizeof buf)
+		to_read = sizeof buf;
+	    size_read = fread(buf, 1, to_read, fp);
+	    if (size_read <= 0) {
+		perror("Can't read program segment");
+		return -1;
+	    }
+	    part_sum = ipchksum(buf, size_read);
+	    sum = add_ipchksums(offset, sum, part_sum);
+	    offset += size_read;
+	    seg_size -= size_read;
+	}
+	/* Simulate cleared memory */
+	memset(buf, 0, sizeof buf);
+	seg_size = BSWAP(phdr[i].p_memsz) - BSWAP(phdr[i].p_filesz);
+	while (seg_size > 0) {
+	    size_read = seg_size;
+	    if (size_read > sizeof buf)
+		size_read = sizeof buf;
+	    part_sum = ipchksum(buf, size_read);
+	    sum = add_ipchksums(offset, sum, part_sum);
+	    offset += size_read;
+	    seg_size -= size_read;
+	}
+    }
+    if (verbose >= 2)
+	printf("Computed checksum: %#04x\n", sum);
+
+    return sum;
+}
+
+int checksum_elf(FILE *fp, const char *filename, int write_sum)
+{
+    int retval = 2;
+    Elf_Ehdr ehdr;
+    Elf_Phdr *phdr = NULL;
+    off_t phoff;
+    int phnum, phentsize;
+    int i;
+    int image_has_sum;
+    unsigned short image_sum=0;
+    int computed_sum;
+    off_t sum_offset=0;
+
+    if (fseek(fp, 0, SEEK_SET) != 0) {
+	perror(filename);
+	goto out;
+    }
+    if (fread(&ehdr, sizeof ehdr, 1, fp) != 1) {
+	perror("Can't read ELF header");
+	goto out;
+    }
+    if (BSWAP(ehdr.e_type) != ET_EXEC) {
+	fprintf(stderr, "%s: Not executable\n", filename);
+	goto out;
+    }
+    if (BSWAP(ehdr.e_version) != EV_CURRENT) {
+	fprintf(stderr, "%s: Unsupported ELF version\n", filename);
+	goto out;
+    }
+
+    phoff = BSWAP(ehdr.e_phoff);
+    phnum = BSWAP(ehdr.e_phnum);
+    if (phoff==0 || phnum==0) {
+	fprintf(stderr, "%s: Program header not found\n", filename);
+	goto out;
+    }
+
+    phentsize = BSWAP(ehdr.e_phentsize);
+    if (phentsize != sizeof(*phdr)) {
+	fprintf(stderr, "%s: Unsupported program header entry size\n",
+		filename);
+	goto out;
+    }
+
+    phdr = malloc(phnum * phentsize);
+    if (!phdr) {
+	perror("Can't allocate memory for program header");
+	goto out;
+    }
+    if (fseek(fp, phoff, SEEK_SET) != 0) {
+	perror("Can't seek to program header");
+	goto out;
+    }
+    if (fread(phdr, phentsize, phnum, fp) != phnum) {
+	perror("Can't read program header");
+	goto out;
+    }
+
+    /* find checksum in the image */
+    image_has_sum = 0;
+    for (i = 0; i < phnum; i++) {
+	if (BSWAP(phdr[i].p_type) == PT_NOTE) {
+	    image_has_sum = process_note_segment(fp, filename,
+		    BSWAP(phdr[i].p_offset),
+		    BSWAP(phdr[i].p_filesz),
+		    &image_sum, &sum_offset);
+	    if (image_has_sum < 0) /* error */
+		goto out;
+	    if (image_has_sum)
+		break;
+	}
+    }
+    if (!image_has_sum) {
+	fprintf(stderr, "%s: Image doesn't have ELF Boot checksum\n", filename);
+	goto out;
+    }
+
+    /* See if checksum itself is summed */
+    for (i = 0; i < phnum; i++) {
+	if (BSWAP(phdr[i].p_type) == PT_LOAD) {
+	    off_t start, end;
+	    start = BSWAP(phdr[i].p_offset);
+	    end = start + BSWAP(phdr[i].p_filesz);
+	    if (sum_offset >= start && sum_offset < end) {
+		/* It is. Computed checksum should be zero. */
+		if (verbose >= 2)
+		    printf("Checksum is in PT_LOAD segment, "
+			    "computation result should be 0\n");
+		image_sum = 0;
+		break;
+	    }
+	}
+    }
+
+    /* OK, compute the sum */
+    computed_sum = do_checksum(fp, filename, &ehdr, phdr);
+    if (computed_sum < 0) /* error */
+	goto out;
+    
+    if (write_sum && image_sum != computed_sum) {
+	unsigned short target_sum;
+	if (fseek(fp, sum_offset, SEEK_SET) != 0) {
+	    perror("Can't seek to checksum offset");
+	    goto out;
+	}
+	target_sum = BSWAP(computed_sum);
+	if (fwrite(&target_sum, 2, 1, fp) != 1) {
+	    perror("Can't write checksum");
+	    goto out;
+	}
+	if (verbose >= 2)
+	    printf("Checksum %#04x written\n", computed_sum);
+	retval = 0;
+    } else {
+	if (image_sum == computed_sum) {
+	    if (verbose)
+		printf("Verified\n");
+	    retval = 0;
+	} else {
+	    if (verbose)
+		printf("Verify FAILED\n");
+	    retval = 1;
+	}
+    }
+
+out:
+    if (phdr)
+	free(phdr);
+    return retval;
+}

Added: trunk/filo/util/ebchecksum.c
===================================================================
--- trunk/filo/util/ebchecksum.c	                        (rev 0)
+++ trunk/filo/util/ebchecksum.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,138 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#define STDINT_H
+#include "elf.h"
+#include "ebchecksum.h"
+
+int verbose = 1;
+typedef int (*checksum_func_t)();
+
+checksum_func_t identify_elf(FILE *fp, const char *filename)
+{
+    unsigned char ident[EI_NIDENT];
+    int class, data;
+
+    rewind(fp);
+    if (fread(&ident, sizeof ident, 1, fp) != 1) {
+	perror("Can't read ELF identify");
+	return NULL;
+    }
+
+    if (ident[EI_MAG0] != ELFMAG0
+     || ident[EI_MAG1] != ELFMAG1
+     || ident[EI_MAG2] != ELFMAG2
+     || ident[EI_MAG3] != ELFMAG3
+     || ident[EI_VERSION] != EV_CURRENT) {
+	fprintf(stderr, "%s: Not an ELF file\n", filename);
+	return NULL;
+    }
+
+    class = ident[EI_CLASS];
+    if (class != ELFCLASS32 && class != ELFCLASS64) {
+	fprintf(stderr, "%s: Unsupported ELF class: %d\n", filename, class);
+	return NULL;
+    }
+
+    data = ident[EI_DATA];
+    if (data != ELFDATA2LSB && data != ELFDATA2MSB) {
+	fprintf(stderr, "%s: Unsupported ELF data type: %d\n", filename, data);
+	return NULL;
+    }
+
+    if (class==ELFCLASS32) {
+	if (data==ELFDATA2LSB)
+	    return checksum_elf32le;
+	else
+	    return checksum_elf32be;
+    } else {
+	if (data==ELFDATA2LSB)
+	    return checksum_elf64le;
+	else
+	    return checksum_elf64be;
+    }
+}
+
+void usage(const char *progname)
+{
+    printf("Usage: %s [-w] IMAGE\n"
+	    "\n"
+	    "IMAGE:\tBootable ELF image file\n"
+	    "-w:\tWrite checksum to the ELFBoot note in the IMAGE\n"
+	    "\n"
+	    "This program computes checksum of a bootable ELF image,\n"
+	    "compares it against the value from the ELFBoot note,\n"
+	    "and optionally writes the correct value to the ELFBoot note.\n",
+	    progname);
+}
+
+int main(int argc, char *argv[])
+{
+    int write_checksum = 0;
+    int done_opt = 0;
+    const char *filename;
+    int retval = 2;
+    FILE *fp;
+    checksum_func_t checksum_func;
+
+    while (!done_opt) {
+	switch (getopt(argc, argv, "wqv")) {
+	case 'w':
+	    write_checksum = 1;
+	    break;
+	case 'q':
+	    verbose = 0;
+	    break;
+	case 'v':
+	    verbose++;
+	    break;
+	case EOF:
+	    done_opt = 1;
+	    break;
+	default:
+	    usage(argv[0]);
+	    return retval;
+	}
+    }
+
+    if (optind != argc-1) {
+	usage(argv[0]);
+	return retval;
+    }
+    filename = argv[optind];
+
+    fp = fopen(filename, write_checksum? "r+" : "r");
+    if (!fp) {
+	perror(filename);
+	goto out;
+    }
+    checksum_func = identify_elf(fp, filename);
+    if (checksum_func == NULL)
+	goto out;
+
+    retval = checksum_func(fp, filename, write_checksum);
+
+out:
+    if (fp)
+	fclose(fp);
+    return retval;
+}

Added: trunk/filo/util/ebchecksum.h
===================================================================
--- trunk/filo/util/ebchecksum.h	                        (rev 0)
+++ trunk/filo/util/ebchecksum.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,26 @@
+/*
+ * 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 EBCHECKSUM_H
+#define EBCHECKSUM_H
+extern int verbose;
+int checksum_elf32le(FILE *fp, const char *filename, int write_sum);
+int checksum_elf32be(FILE *fp, const char *filename, int write_sum);
+int checksum_elf64le(FILE *fp, const char *filename, int write_sum);
+int checksum_elf64be(FILE *fp, const char *filename, int write_sum);
+#endif

Added: trunk/filo/util/kconfig/Makefile
===================================================================
--- trunk/filo/util/kconfig/Makefile	                        (rev 0)
+++ trunk/filo/util/kconfig/Makefile	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,337 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
+
+Kconfig := Config.in
+
+xconfig: prepare $(objk)/qconf
+	$(Q)$(objk)/qconf $(Kconfig)
+
+gconfig: prepare $(objk)/gconf
+	$(Q)$(objk)/gconf $(Kconfig)
+
+menuconfig: prepare $(objk)/mconf
+	$(Q)$(objk)/mconf $(Kconfig)
+
+config: prepare $(objk)/conf
+	$(Q)$(objk)/conf $(Kconfig)
+
+oldconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -o $(Kconfig)
+
+silentoldconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -s $(Kconfig)
+
+# --- UNUSED, ignore ----------------------------------------------------------
+# Create new linux.pot file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+	$(Q)echo "  GEN config"
+	$(Q)xgettext --default-domain=linux              \
+	    --add-comments --keyword=_ --keyword=N_      \
+	    --from-code=UTF-8                            \
+	    --files-from=scripts/kconfig/POTFILES.in     \
+	    --output $(obj)/config.pot
+	$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+	$(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+	$(Q)(for i in `ls arch/`;                        \
+	    do                                           \
+		echo "  GEN $$i";                        \
+		$(obj)/kxgettext arch/$$i/Kconfig        \
+		     >> $(obj)/config.pot;               \
+	    done )
+	$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+	    --output $(obj)/linux.pot
+	$(Q)rm -f arch/um/Kconfig.arch
+	$(Q)rm -f $(obj)/config.pot
+# --- UNUSED, ignore ----------------------------------------------------------
+
+PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
+
+randconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -r $(Kconfig)
+
+allyesconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -y $(Kconfig)
+
+allnoconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -n $(Kconfig)
+
+allmodconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -m $(Kconfig)
+
+defconfig: prepare $(objk)/conf
+ifeq ($(KBUILD_DEFCONFIG),)
+	$(Q)$(objk)/conf -d $(Kconfig)
+else
+	@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
+	$(Q)$(objk)/conf -D $(KBUILD_DEFCONFIG) $(Kconfig)
+endif
+
+%_defconfig: prepare $(objk)/conf
+	$(Q)$(objk)/conf -D configs/$@ $(Kconfig)
+
+# Help text used by make help
+help:
+	@echo  '  config	  - Update current config utilising a line-oriented program'
+	@echo  '  menuconfig	  - Update current config utilising a menu based program'
+	@echo  '  xconfig	  - Update current config utilising a QT based front-end'
+	@echo  '  gconfig	  - Update current config utilising a GTK based front-end'
+	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
+	@echo  '  silentoldconfig - Same as oldconfig, but quietly'
+	@echo  '  randconfig	  - New config with random answer to all options'
+	@echo  '  defconfig	  - New config with default answer to all options'
+	@echo  '  allmodconfig	  - New config selecting modules when possible'
+	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
+	@echo  '  allnoconfig	  - New config where all options are answered with no'
+
+# lxdialog stuff
+check-lxdialog  := $(srck)/lxdialog/check-lxdialog.sh
+
+# Use recursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
+HOST_LOADLIBES   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOST_EXTRACFLAGS += -DLOCALE
+
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:	  Used for defconfig, oldconfig and related targets
+# mconf:  Used for the mconfig target.
+#         Utilizes the lxdialog package
+# qconf:  Used for the xconfig target
+#         Based on QT which needs to be installed to compile it
+# gconf:  Used for the gconfig target
+#         Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs	:= conf.o  zconf.tab.o
+mconf-objs	:= mconf.o zconf.tab.o $(lxdialog)
+kxgettext-objs	:= kxgettext.o zconf.tab.o
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+	hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+	qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+	gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs	:= qconf.o
+qconf-objs	:= kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs	:= gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
+		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files     += mconf qconf gconf
+clean-files     += config.pot coreinfo.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(objk)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(objk)/dochecklxdialog
+$(objk)/dochecklxdialog:
+	$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srck)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o	:= -I$(src)
+HOSTCFLAGS_zconf.tab.o	:= -I$(src)
+
+HOSTLOADLIBES_qconf	= $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o	= $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf	= `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
+HOSTCFLAGS_gconf.o	= `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+$(objk)/qconf.o: $(objk)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(objk)/.tmp_qtcheck: $(srck)/Makefile
+-include $(objk)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(objk)/.tmp_qtcheck: prepare
+	@set -e; dir=""; pkg=""; \
+	pkg-config --exists qt 2> /dev/null && pkg=qt; \
+	pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+	if [ -n "$$pkg" ]; then \
+	  cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+	  libs="\$$(shell pkg-config $$pkg --libs)"; \
+	  moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+	  dir="$$(pkg-config $$pkg --variable=prefix)"; \
+	else \
+	  for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+	    if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+	  done; \
+	  if [ -z "$$dir" ]; then \
+	    echo "*"; \
+	    echo "* Unable to find the QT3 installation. Please make sure that"; \
+	    echo "* the QT3 development package is correctly installed and"; \
+	    echo "* either install pkg-config or set the QTDIR environment"; \
+	    echo "* variable to the correct location."; \
+	    echo "*"; \
+	    false; \
+	  fi; \
+	  libpath=$$dir/lib; lib=qt; osdir=""; \
+	  $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+	    osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+	  test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+	  test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+	  cflags="-I$$dir/include"; \
+	  libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+	  moc="$$dir/bin/moc"; \
+	fi; \
+	if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+	  echo "*"; \
+	  echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+	  echo "*"; \
+	  moc="/usr/bin/moc"; \
+	fi; \
+	echo "KC_QT_CFLAGS=$$cflags" > $@; \
+	echo "KC_QT_LIBS=$$libs" >> $@; \
+	echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(objk)/gconf.o: $(objk)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(objk)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(objk)/.tmp_gtkcheck: prepare
+	@if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then		\
+		if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then			\
+			touch $@;								\
+		else									\
+			echo "*"; 							\
+			echo "* GTK+ is present but version >= 2.0.0 is required.";	\
+			echo "*";							\
+			false;								\
+		fi									\
+	else										\
+		echo "*"; 								\
+		echo "* Unable to find the GTK+ installation. Please make sure that"; 	\
+		echo "* the GTK+ 2.0 development package is correctly installed..."; 	\
+		echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; 		\
+		echo "*"; 								\
+		false;									\
+	fi
+endif
+
+# --- UNUSED, ignore ----------------------------------------------------------
+ifdef UNUSED
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+	$(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+	sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+	intltool-extract --type=gettext/glade $(obj)/gconf.glade
+endif
+# --- UNUSED, ignore ----------------------------------------------------------
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+# --- UNUSED, ignore ----------------------------------------------------------
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+	bison -l -b $* -p $(notdir $*) $<
+	cp $@ $@_shipped
+
+lex.%.c: %.l
+	flex -L -P$(notdir $*) -o$@ $<
+	cp $@ $@_shipped
+
+%.hash.c: %.gperf
+	gperf < $< > $@
+	cp $@ $@_shipped
+# --- UNUSED, ignore ----------------------------------------------------------
+
+endif
+
+$(objk)/qconf: $(patsubst %,$(objk)/%,$(qconf-cxxobjs)) \
+	       $(patsubst %,$(objk)/%,$(qconf-objs))
+	$(Q)$(HOSTCXX) $(HOSTCXXFLAGS) $(HOSTLOADLIBES_qconf) -o $@ $^
+$(objk)/gconf: $(patsubst %,$(objk)/%,$(gconf-objs))
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOSTLOADLIBES_gconf) -o $@ $^
+$(objk)/mconf: $(patsubst %,$(objk)/%,$(mconf-objs))
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES) -o $@ $^
+$(objk)/conf: $(patsubst %,$(objk)/%,$(conf-objs))
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -o $@ $^
+
+$(objk)/mconf.o: $(srck)/mconf.c
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
+$(objk)/conf.o: $(srck)/conf.c
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
+
+$(objk)/zconf.tab.o: $(objk)/zconf.tab.c $(objk)/lex.zconf.c \
+		     $(objk)/zconf.hash.c
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $(objk)/zconf.tab.c
+$(objk)/kconfig_load.o: $(srck)/kconfig_load.c $(objk)/lkc_defs.h
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
+$(objk)/qconf.o: $(srck)/qconf.cc $(objk)/qconf.moc $(objk)/lkc_defs.h
+	$(Q)$(HOSTCXX) $(HOSTCXXFLAGS) $(HOSTCXXFLAGS_qconf.o) -c -o $@ $<
+$(objk)/gconf.o: $(srck)/gconf.c $(objk)/lkc_defs.h
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOSTCFLAGS_gconf.o) -c -o $@ $<
+$(objk)/%.moc: $(srck)/%.h
+	$(Q)$(KC_QT_MOC) -i $< -o $@
+$(objk)/lkc_defs.h: $(srck)/lkc_proto.h
+	$(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+$(objk)/lex.zconf.c: $(srck)/lex.zconf.c_shipped
+	$(Q)cp $< $@
+$(objk)/zconf.hash.c: $(srck)/zconf.hash.c_shipped
+	$(Q)cp $< $@
+$(objk)/zconf.tab.c: $(srck)/zconf.tab.c_shipped
+	$(Q)cp $< $@
+
+$(objk)/lxdialog/lxdialog: $(objk)/dochecklxdialog \
+			   $(patsubst %,$(objk)/lxdialog/%,$(lxdialog))
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES) \
+		$(patsubst %,$(objk)/lxdialog/%,$(lxdialog)) -o $@
+$(objk)/lxdialog/%.o: $(srck)/lxdialog/%.c
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $^ -c -o $@
+

Added: trunk/filo/util/kconfig/POTFILES.in
===================================================================
--- trunk/filo/util/kconfig/POTFILES.in	                        (rev 0)
+++ trunk/filo/util/kconfig/POTFILES.in	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,12 @@
+util/kconfig/lxdialog/checklist.c
+util/kconfig/lxdialog/inputbox.c
+util/kconfig/lxdialog/menubox.c
+util/kconfig/lxdialog/textbox.c
+util/kconfig/lxdialog/util.c
+util/kconfig/lxdialog/yesno.c
+util/kconfig/mconf.c
+util/kconfig/conf.c
+util/kconfig/confdata.c
+util/kconfig/gconf.c
+util/kconfig/gconf.glade.h
+util/kconfig/qconf.cc

Added: trunk/filo/util/kconfig/check.sh
===================================================================
--- trunk/filo/util/kconfig/check.sh	                        (rev 0)
+++ trunk/filo/util/kconfig/check.sh	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+	gettext("");
+	return 0;
+}
+EOF
+if [ ! "$?" -eq "0"  ]; then
+	echo -DKBUILD_NO_NLS;
+fi
+


Property changes on: trunk/filo/util/kconfig/check.sh
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/filo/util/kconfig/conf.c
===================================================================
--- trunk/filo/util/kconfig/conf.c	                        (rev 0)
+++ trunk/filo/util/kconfig/conf.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum {
+	ask_all,
+	ask_new,
+	ask_silent,
+	set_default,
+	set_yes,
+	set_mod,
+	set_no,
+	set_random
+} input_mode = ask_all;
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
+
+static const char *get_help(struct menu *menu)
+{
+	if (menu_has_help(menu))
+		return _(menu_get_help(menu));
+	else
+		return nohelp_text;
+}
+
+static void strip(char *str)
+{
+	char *p = str;
+	int l;
+
+	while ((isspace(*p)))
+		p++;
+	l = strlen(p);
+	if (p != str)
+		memmove(str, p, l + 1);
+	if (!l)
+		return;
+	p = str + l - 1;
+	while ((isspace(*p)))
+		*p-- = 0;
+}
+
+static void check_stdin(void)
+{
+	if (!valid_stdin && input_mode == ask_silent) {
+		printf(_("aborted!\n\n"));
+		printf(_("Console input/output is redirected. "));
+		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+		exit(1);
+	}
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+	enum symbol_type type = sym_get_type(sym);
+	tristate val;
+
+	if (!sym_has_value(sym))
+		printf(_("(NEW) "));
+
+	line[0] = '\n';
+	line[1] = 0;
+
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return 0;
+	}
+
+	switch (input_mode) {
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return 0;
+		}
+		break;
+	case ask_new:
+	case ask_silent:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return 0;
+		}
+		check_stdin();
+	case ask_all:
+		fflush(stdout);
+		fgets(line, 128, stdin);
+		return 1;
+	case set_default:
+		printf("%s\n", def);
+		return 1;
+	default:
+		break;
+	}
+
+	switch (type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		printf("%s\n", def);
+		return 1;
+	default:
+		;
+	}
+	switch (input_mode) {
+	case set_yes:
+		if (sym_tristate_within_range(sym, yes)) {
+			line[0] = 'y';
+			line[1] = '\n';
+			line[2] = 0;
+			break;
+		}
+	case set_mod:
+		if (type == S_TRISTATE) {
+			if (sym_tristate_within_range(sym, mod)) {
+				line[0] = 'm';
+				line[1] = '\n';
+				line[2] = 0;
+				break;
+			}
+		} else {
+			if (sym_tristate_within_range(sym, yes)) {
+				line[0] = 'y';
+				line[1] = '\n';
+				line[2] = 0;
+				break;
+			}
+		}
+	case set_no:
+		if (sym_tristate_within_range(sym, no)) {
+			line[0] = 'n';
+			line[1] = '\n';
+			line[2] = 0;
+			break;
+		}
+	case set_random:
+		do {
+			val = (tristate)(rand() % 3);
+		} while (!sym_tristate_within_range(sym, val));
+		switch (val) {
+		case no: line[0] = 'n'; break;
+		case mod: line[0] = 'm'; break;
+		case yes: line[0] = 'y'; break;
+		}
+		line[1] = '\n';
+		line[2] = 0;
+		break;
+	default:
+		break;
+	}
+	printf("%s", line);
+	return 1;
+}
+
+int conf_string(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	const char *def;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		printf("(%s) ", sym->name);
+		def = sym_get_string_value(sym);
+		if (sym_get_string_value(sym))
+			printf("[%s] ", def);
+		if (!conf_askvalue(sym, def))
+			return 0;
+		switch (line[0]) {
+		case '\n':
+			break;
+		case '?':
+			/* print help */
+			if (line[1] == '\n') {
+				printf("\n%s\n", get_help(menu));
+				def = NULL;
+				break;
+			}
+		default:
+			line[strlen(line)-1] = 0;
+			def = line;
+		}
+		if (def && sym_set_string_value(sym, def))
+			return 0;
+	}
+}
+
+static int conf_sym(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	int type;
+	tristate oldval, newval;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		if (sym->name)
+			printf("(%s) ", sym->name);
+		type = sym_get_type(sym);
+		putchar('[');
+		oldval = sym_get_tristate_value(sym);
+		switch (oldval) {
+		case no:
+			putchar('N');
+			break;
+		case mod:
+			putchar('M');
+			break;
+		case yes:
+			putchar('Y');
+			break;
+		}
+		if (oldval != no && sym_tristate_within_range(sym, no))
+			printf("/n");
+		if (oldval != mod && sym_tristate_within_range(sym, mod))
+			printf("/m");
+		if (oldval != yes && sym_tristate_within_range(sym, yes))
+			printf("/y");
+		if (menu_has_help(menu))
+			printf("/?");
+		printf("] ");
+		if (!conf_askvalue(sym, sym_get_string_value(sym)))
+			return 0;
+		strip(line);
+
+		switch (line[0]) {
+		case 'n':
+		case 'N':
+			newval = no;
+			if (!line[1] || !strcmp(&line[1], "o"))
+				break;
+			continue;
+		case 'm':
+		case 'M':
+			newval = mod;
+			if (!line[1])
+				break;
+			continue;
+		case 'y':
+		case 'Y':
+			newval = yes;
+			if (!line[1] || !strcmp(&line[1], "es"))
+				break;
+			continue;
+		case 0:
+			newval = oldval;
+			break;
+		case '?':
+			goto help;
+		default:
+			continue;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			return 0;
+help:
+		printf("\n%s\n", get_help(menu));
+	}
+}
+
+static int conf_choice(struct menu *menu)
+{
+	struct symbol *sym, *def_sym;
+	struct menu *child;
+	int type;
+	bool is_new;
+
+	sym = menu->sym;
+	type = sym_get_type(sym);
+	is_new = !sym_has_value(sym);
+	if (sym_is_changable(sym)) {
+		conf_sym(menu);
+		sym_calc_value(sym);
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			return 0;
+		case yes:
+			break;
+		}
+	} else {
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+			return 0;
+		case yes:
+			break;
+		}
+	}
+
+	while (1) {
+		int cnt, def;
+
+		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+		def_sym = sym_get_choice_value(sym);
+		cnt = def = 0;
+		line[0] = 0;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (!child->sym) {
+				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+				continue;
+			}
+			cnt++;
+			if (child->sym == def_sym) {
+				def = cnt;
+				printf("%*c", indent, '>');
+			} else
+				printf("%*c", indent, ' ');
+			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+			if (child->sym->name)
+				printf(" (%s)", child->sym->name);
+			if (!sym_has_value(child->sym))
+				printf(_(" (NEW)"));
+			printf("\n");
+		}
+		printf(_("%*schoice"), indent - 1, "");
+		if (cnt == 1) {
+			printf("[1]: 1\n");
+			goto conf_childs;
+		}
+		printf("[1-%d", cnt);
+		if (menu_has_help(menu))
+			printf("?");
+		printf("]: ");
+		switch (input_mode) {
+		case ask_new:
+		case ask_silent:
+			if (!is_new) {
+				cnt = def;
+				printf("%d\n", cnt);
+				break;
+			}
+			check_stdin();
+		case ask_all:
+			fflush(stdout);
+			fgets(line, 128, stdin);
+			strip(line);
+			if (line[0] == '?') {
+				printf("\n%s\n", get_help(menu));
+				continue;
+			}
+			if (!line[0])
+				cnt = def;
+			else if (isdigit(line[0]))
+				cnt = atoi(line);
+			else
+				continue;
+			break;
+		case set_random:
+			if (is_new)
+				def = (rand() % cnt) + 1;
+		case set_default:
+		case set_yes:
+		case set_mod:
+		case set_no:
+			cnt = def;
+			printf("%d\n", cnt);
+			break;
+		}
+
+	conf_childs:
+		for (child = menu->list; child; child = child->next) {
+			if (!child->sym || !menu_is_visible(child))
+				continue;
+			if (!--cnt)
+				break;
+		}
+		if (!child)
+			continue;
+		if (line[strlen(line) - 1] == '?') {
+			printf("\n%s\n", get_help(child));
+			continue;
+		}
+		sym_set_choice_value(sym, child->sym);
+		for (child = child->list; child; child = child->next) {
+			indent += 2;
+			conf(child);
+			indent -= 2;
+		}
+		return 1;
+	}
+}
+
+static void conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (prop) {
+		const char *prompt;
+
+		switch (prop->type) {
+		case P_MENU:
+			if (input_mode == ask_silent && rootEntry != menu) {
+				check_conf(menu);
+				return;
+			}
+		case P_COMMENT:
+			prompt = menu_get_prompt(menu);
+			if (prompt)
+				printf("%*c\n%*c %s\n%*c\n",
+					indent, '*',
+					indent, '*', _(prompt),
+					indent, '*');
+		default:
+			;
+		}
+	}
+
+	if (!sym)
+		goto conf_childs;
+
+	if (sym_is_choice(sym)) {
+		conf_choice(menu);
+		if (sym->curr.tri != mod)
+			return;
+		goto conf_childs;
+	}
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		conf_string(menu);
+		break;
+	default:
+		conf_sym(menu);
+		break;
+	}
+
+conf_childs:
+	if (sym)
+		indent += 2;
+	for (child = menu->list; child; child = child->next)
+		conf(child);
+	if (sym)
+		indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	if (sym && !sym_has_value(sym)) {
+		if (sym_is_changable(sym) ||
+		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+			if (!conf_cnt++)
+				printf(_("*\n* Restart config...\n*\n"));
+			rootEntry = menu_get_parent_menu(menu);
+			conf(rootEntry);
+		}
+	}
+
+	for (child = menu->list; child; child = child->next)
+		check_conf(child);
+}
+
+int main(int ac, char **av)
+{
+	int opt;
+	const char *name;
+	struct stat tmpstat;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+		switch (opt) {
+		case 'o':
+			input_mode = ask_new;
+			break;
+		case 's':
+			input_mode = ask_silent;
+			valid_stdin = isatty(0) && isatty(1) && isatty(2);
+			break;
+		case 'd':
+			input_mode = set_default;
+			break;
+		case 'D':
+			input_mode = set_default;
+			defconfig_file = optarg;
+			break;
+		case 'n':
+			input_mode = set_no;
+			break;
+		case 'm':
+			input_mode = set_mod;
+			break;
+		case 'y':
+			input_mode = set_yes;
+			break;
+		case 'r':
+			input_mode = set_random;
+			srand(time(NULL));
+			break;
+		case 'h':
+			printf(_("See README for usage info\n"));
+			exit(0);
+			break;
+		default:
+			fprintf(stderr, _("See README for usage info\n"));
+			exit(1);
+		}
+	}
+	if (ac == optind) {
+		printf(_("%s: Kconfig file missing\n"), av[0]);
+		exit(1);
+	}
+	name = av[optind];
+	conf_parse(name);
+	//zconfdump(stdout);
+	switch (input_mode) {
+	case set_default:
+		if (!defconfig_file)
+			defconfig_file = conf_get_default_confname();
+		if (conf_read(defconfig_file)) {
+			printf(_("***\n"
+				"*** Can't find default configuration \"%s\"!\n"
+				"***\n"), defconfig_file);
+			exit(1);
+		}
+		break;
+	case ask_silent:
+		if (stat(".config", &tmpstat)) {
+			printf(_("***\n"
+				"*** You have not yet configured FILO!\n"
+				"*** (missing .config file)\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"));
+			exit(1);
+		}
+	case ask_all:
+	case ask_new:
+		conf_read(NULL);
+		break;
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		name = getenv("KCONFIG_ALLCONFIG");
+		if (name && !stat(name, &tmpstat)) {
+			conf_read_simple(name, S_DEF_USER);
+			break;
+		}
+		switch (input_mode) {
+		case set_no:	 name = "allno.config"; break;
+		case set_mod:	 name = "allmod.config"; break;
+		case set_yes:	 name = "allyes.config"; break;
+		case set_random: name = "allrandom.config"; break;
+		default: break;
+		}
+		if (!stat(name, &tmpstat))
+			conf_read_simple(name, S_DEF_USER);
+		else if (!stat("all.config", &tmpstat))
+			conf_read_simple("all.config", S_DEF_USER);
+		break;
+	default:
+		break;
+	}
+
+	if (input_mode != ask_silent) {
+		rootEntry = &rootmenu;
+		conf(&rootmenu);
+		if (input_mode == ask_all) {
+			input_mode = ask_silent;
+			valid_stdin = 1;
+		}
+	} else if (conf_get_changed()) {
+		name = getenv("KCONFIG_NOSILENTUPDATE");
+		if (name && *name) {
+			fprintf(stderr, _("\n*** FILO configuration requires explicit update.\n\n"));
+			return 1;
+		}
+	} else
+		goto skip_check;
+
+	do {
+		conf_cnt = 0;
+		check_conf(&rootmenu);
+	} while (conf_cnt);
+	if (conf_write(NULL)) {
+		fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+		return 1;
+	}
+	if (conf_write_autoconf()) {
+		fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+		return 1;
+	}
+skip_check:
+	if (input_mode == ask_silent && conf_write_autoconf()) {
+		fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+		return 1;
+	}
+
+	return 0;
+}

Added: trunk/filo/util/kconfig/confdata.c
===================================================================
--- trunk/filo/util/kconfig/confdata.c	                        (rev 0)
+++ trunk/filo/util/kconfig/confdata.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	conf_warnings++;
+}
+
+const char *conf_get_configname(void)
+{
+	char *name = getenv("KCONFIG_CONFIG");
+
+	return name ? name : ".config";
+}
+
+static char *conf_expand_value(const char *in)
+{
+	struct symbol *sym;
+	const char *src;
+	static char res_value[SYMBOL_MAXLENGTH];
+	char *dst, name[SYMBOL_MAXLENGTH];
+
+	res_value[0] = 0;
+	dst = name;
+	while ((src = strchr(in, '$'))) {
+		strncat(res_value, in, src - in);
+		src++;
+		dst = name;
+		while (isalnum(*src) || *src == '_')
+			*dst++ = *src++;
+		*dst = 0;
+		sym = sym_lookup(name, 0);
+		sym_calc_value(sym);
+		strcat(res_value, sym_get_string_value(sym));
+		in = src;
+	}
+	strcat(res_value, in);
+
+	return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+	struct stat buf;
+	static char fullname[PATH_MAX+1];
+	char *env, *name;
+
+	name = conf_expand_value(conf_defname);
+	env = getenv(SRCTREE);
+	if (env) {
+		sprintf(fullname, "%s/%s", env, name);
+		if (!stat(fullname, &buf))
+			return fullname;
+	}
+	return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+	char *p2;
+
+	switch (sym->type) {
+	case S_TRISTATE:
+		if (p[0] == 'm') {
+			sym->def[def].tri = mod;
+			sym->flags |= def_flags;
+			break;
+		}
+	case S_BOOLEAN:
+		if (p[0] == 'y') {
+			sym->def[def].tri = yes;
+			sym->flags |= def_flags;
+			break;
+		}
+		if (p[0] == 'n') {
+			sym->def[def].tri = no;
+			sym->flags |= def_flags;
+			break;
+		}
+		conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+		break;
+	case S_OTHER:
+		if (*p != '"') {
+			for (p2 = p; *p2 && !isspace(*p2); p2++)
+				;
+			sym->type = S_STRING;
+			goto done;
+		}
+	case S_STRING:
+		if (*p++ != '"')
+			break;
+		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+			if (*p2 == '"') {
+				*p2 = 0;
+				break;
+			}
+			memmove(p2, p2 + 1, strlen(p2));
+		}
+		if (!p2) {
+			conf_warning("invalid string found");
+			return 1;
+		}
+	case S_INT:
+	case S_HEX:
+	done:
+		if (sym_string_valid(sym, p)) {
+			sym->def[def].val = strdup(p);
+			sym->flags |= def_flags;
+		} else {
+			conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+			return 1;
+		}
+		break;
+	default:
+		;
+	}
+	return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+	FILE *in = NULL;
+	char line[1024];
+	char *p, *p2;
+	struct symbol *sym;
+	int i, def_flags;
+
+	if (name) {
+		in = zconf_fopen(name);
+	} else {
+		struct property *prop;
+
+		name = conf_get_configname();
+		in = zconf_fopen(name);
+		if (in)
+			goto load;
+		sym_add_change_count(1);
+		if (!sym_defconfig_list)
+			return 1;
+
+		for_all_defaults(sym_defconfig_list, prop) {
+			if (expr_calc_value(prop->visible.expr) == no ||
+			    prop->expr->type != E_SYMBOL)
+				continue;
+			name = conf_expand_value(prop->expr->left.sym->name);
+			in = zconf_fopen(name);
+			if (in) {
+				printf(_("#\n"
+					 "# using defaults found in %s\n"
+					 "#\n"), name);
+				goto load;
+			}
+		}
+	}
+	if (!in)
+		return 1;
+
+load:
+	conf_filename = name;
+	conf_lineno = 0;
+	conf_warnings = 0;
+	conf_unsaved = 0;
+
+	def_flags = SYMBOL_DEF << def;
+	for_all_symbols(i, sym) {
+		sym->flags |= SYMBOL_CHANGED;
+		sym->flags &= ~(def_flags|SYMBOL_VALID);
+		if (sym_is_choice(sym))
+			sym->flags |= def_flags;
+		switch (sym->type) {
+		case S_INT:
+		case S_HEX:
+		case S_STRING:
+			if (sym->def[def].val)
+				free(sym->def[def].val);
+		default:
+			sym->def[def].val = NULL;
+			sym->def[def].tri = no;
+		}
+	}
+
+	while (fgets(line, sizeof(line), in)) {
+		conf_lineno++;
+		sym = NULL;
+		switch (line[0]) {
+		case '#':
+			if (memcmp(line + 2, "CONFIG_", 7))
+				continue;
+			p = strchr(line + 9, ' ');
+			if (!p)
+				continue;
+			*p++ = 0;
+			if (strncmp(p, "is not set", 10))
+				continue;
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 9);
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 9);
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + 9, 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_BOOLEAN;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("override: reassigning to symbol %s", sym->name);
+			}
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				sym->def[def].tri = no;
+				sym->flags |= def_flags;
+				break;
+			default:
+				;
+			}
+			break;
+		case 'C':
+			if (memcmp(line, "CONFIG_", 7)) {
+				conf_warning("unexpected data");
+				continue;
+			}
+			p = strchr(line + 7, '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+			p2 = strchr(p, '\n');
+			if (p2) {
+				*p2-- = 0;
+				if (*p2 == '\r')
+					*p2 = 0;
+			}
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 7);
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 7);
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + 7, 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_OTHER;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("override: reassigning to symbol %s", sym->name);
+			}
+			if (conf_set_sym_val(sym, def, def_flags, p))
+				continue;
+			break;
+		case '\r':
+		case '\n':
+			break;
+		default:
+			conf_warning("unexpected data");
+			continue;
+		}
+		if (sym && sym_is_choice_value(sym)) {
+			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+			switch (sym->def[def].tri) {
+			case no:
+				break;
+			case mod:
+				if (cs->def[def].tri == yes) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags &= ~def_flags;
+				}
+				break;
+			case yes:
+				if (cs->def[def].tri != no)
+					conf_warning("override: %s changes choice state", sym->name);
+				cs->def[def].val = sym;
+				break;
+			}
+			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+		}
+	}
+	fclose(in);
+
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+	return 0;
+}
+
+int conf_read(const char *name)
+{
+	struct symbol *sym, *choice_sym;
+	struct property *prop;
+	struct expr *e;
+	int i, flags;
+
+	sym_set_change_count(0);
+
+	if (conf_read_simple(name, S_DEF_USER))
+		return 1;
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+			goto sym_ok;
+		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+			/* check that calculated value agrees with saved value */
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+					break;
+				if (!sym_is_choice(sym))
+					goto sym_ok;
+			default:
+				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+					goto sym_ok;
+				break;
+			}
+		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+			/* no previous value and not saved */
+			goto sym_ok;
+		conf_unsaved++;
+		/* maybe print value in verbose mode... */
+	sym_ok:
+		if (!sym_is_choice(sym))
+			continue;
+		/* The choice symbol only has a set value (and thus is not new)
+		 * if all its visible childs have values.
+		 */
+		prop = sym_get_choice_prop(sym);
+		flags = sym->flags;
+		expr_list_for_each_sym(prop->expr, e, choice_sym)
+			if (choice_sym->visible != no)
+				flags &= choice_sym->flags;
+		sym->flags &= flags | ~SYMBOL_DEF_USER;
+	}
+
+	for_all_symbols(i, sym) {
+		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+			/* Reset values of generates values, so they'll appear
+			 * as new, if they should become visible, but that
+			 * doesn't quite work if the Kconfig and the saved
+			 * configuration disagree.
+			 */
+			if (sym->visible == no && !conf_unsaved)
+				sym->flags &= ~SYMBOL_DEF_USER;
+			switch (sym->type) {
+			case S_STRING:
+			case S_INT:
+			case S_HEX:
+				/* Reset a string value if it's out of range */
+				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+					break;
+				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+				conf_unsaved++;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	sym_add_change_count(conf_warnings || conf_unsaved);
+
+	return 0;
+}
+
+int conf_write(const char *name)
+{
+	FILE *out;
+	struct symbol *sym;
+	struct menu *menu;
+	const char *basename;
+	char dirname[128], tmpname[128], newname[128];
+	int type, l;
+	const char *str;
+	time_t now;
+	int use_timestamp = 1;
+	char *env;
+
+	dirname[0] = 0;
+	if (name && name[0]) {
+		struct stat st;
+		char *slash;
+
+		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+			strcpy(dirname, name);
+			strcat(dirname, "/");
+			basename = conf_get_configname();
+		} else if ((slash = strrchr(name, '/'))) {
+			int size = slash - name + 1;
+			memcpy(dirname, name, size);
+			dirname[size] = 0;
+			if (slash[1])
+				basename = slash + 1;
+			else
+				basename = conf_get_configname();
+		} else
+			basename = name;
+	} else
+		basename = conf_get_configname();
+
+	sprintf(newname, "%s%s", dirname, basename);
+	env = getenv("KCONFIG_OVERWRITECONFIG");
+	if (!env || !*env) {
+		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+		out = fopen(tmpname, "w");
+	} else {
+		*tmpname = 0;
+		out = fopen(newname, "w");
+	}
+	if (!out)
+		return 1;
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	time(&now);
+	env = getenv("KCONFIG_NOTIMESTAMP");
+	if (env && *env)
+		use_timestamp = 0;
+
+	fprintf(out, _("#\n"
+		       "# Automatically generated make config: don't edit\n"
+		       "# FILO version: %s\n"
+		       "%s%s"
+		       "#\n"),
+		     getenv("KERNELVERSION"),
+		     use_timestamp ? "# " : "",
+		     use_timestamp ? ctime(&now) : "");
+
+	if (!conf_get_changed())
+		sym_clear_all_valid();
+
+	menu = rootmenu.list;
+	while (menu) {
+		sym = menu->sym;
+		if (!sym) {
+			if (!menu_is_visible(menu))
+				goto next;
+			str = menu_get_prompt(menu);
+			fprintf(out, "\n"
+				     "#\n"
+				     "# %s\n"
+				     "#\n", str);
+		} else if (!(sym->flags & SYMBOL_CHOICE)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & SYMBOL_WRITE))
+				goto next;
+			sym->flags &= ~SYMBOL_WRITE;
+			type = sym->type;
+			if (type == S_TRISTATE) {
+				sym_calc_value(modules_sym);
+				if (modules_sym->curr.tri == no)
+					type = S_BOOLEAN;
+			}
+			switch (type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				switch (sym_get_tristate_value(sym)) {
+				case no:
+					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
+					break;
+				case mod:
+					fprintf(out, "CONFIG_%s=m\n", sym->name);
+					break;
+				case yes:
+					fprintf(out, "CONFIG_%s=y\n", sym->name);
+					break;
+				}
+				break;
+			case S_STRING:
+				str = sym_get_string_value(sym);
+				fprintf(out, "CONFIG_%s=\"", sym->name);
+				while (1) {
+					l = strcspn(str, "\"\\");
+					if (l) {
+						fwrite(str, l, 1, out);
+						str += l;
+					}
+					if (!*str)
+						break;
+					fprintf(out, "\\%c", *str++);
+				}
+				fputs("\"\n", out);
+				break;
+			case S_HEX:
+				str = sym_get_string_value(sym);
+				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+					break;
+				}
+			case S_INT:
+				str = sym_get_string_value(sym);
+				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+				break;
+			}
+		}
+
+	next:
+		if (menu->list) {
+			menu = menu->list;
+			continue;
+		}
+		if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+	fclose(out);
+
+	if (*tmpname) {
+		strcat(dirname, basename);
+		strcat(dirname, ".old");
+		rename(newname, dirname);
+		if (rename(tmpname, newname))
+			return 1;
+	}
+
+	printf(_("#\n"
+		 "# configuration written to %s\n"
+		 "#\n"), newname);
+
+	sym_set_change_count(0);
+
+	return 0;
+}
+
+int conf_split_config(void)
+{
+	char *name, path[128];
+	char *s, *d, c;
+	struct symbol *sym;
+	struct stat sb;
+	int res, i, fd;
+
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	conf_read_simple(name, S_DEF_AUTO);
+
+	if (chdir("build"))
+		return 1;
+
+	res = 0;
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+			continue;
+		if (sym->flags & SYMBOL_WRITE) {
+			if (sym->flags & SYMBOL_DEF_AUTO) {
+				/*
+				 * symbol has old and new value,
+				 * so compare them...
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) ==
+					    sym->def[S_DEF_AUTO].tri)
+						continue;
+					break;
+				case S_STRING:
+				case S_HEX:
+				case S_INT:
+					if (!strcmp(sym_get_string_value(sym),
+						    sym->def[S_DEF_AUTO].val))
+						continue;
+					break;
+				default:
+					break;
+				}
+			} else {
+				/*
+				 * If there is no old value, only 'no' (unset)
+				 * is allowed as new value.
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) == no)
+						continue;
+					break;
+				default:
+					break;
+				}
+			}
+		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
+			/* There is neither an old nor a new value. */
+			continue;
+		/* else
+		 *	There is an old value, but no new value ('no' (unset)
+		 *	isn't saved in auto.conf, so the old value is always
+		 *	different from 'no').
+		 */
+
+		/* Replace all '_' and append ".h" */
+		s = sym->name;
+		d = path;
+		while ((c = *s++)) {
+			c = tolower(c);
+			*d++ = (c == '_') ? '/' : c;
+		}
+		strcpy(d, ".h");
+
+		/* Assume directory path already exists. */
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+		if (fd == -1) {
+			if (errno != ENOENT) {
+				res = 1;
+				break;
+			}
+			/*
+			 * Create directory components,
+			 * unless they exist already.
+			 */
+			d = path;
+			while ((d = strchr(d, '/'))) {
+				*d = 0;
+				if (stat(path, &sb) && mkdir(path, 0755)) {
+					res = 1;
+					goto out;
+				}
+				*d++ = '/';
+			}
+			/* Try it again. */
+			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+			if (fd == -1) {
+				res = 1;
+				break;
+			}
+		}
+		close(fd);
+	}
+out:
+	if (chdir("../.."))
+		return 1;
+
+	return res;
+}
+
+int conf_write_autoconf(void)
+{
+	struct symbol *sym;
+	const char *str;
+	char *name;
+	FILE *out, *out_h;
+	time_t now;
+	int i, l;
+
+	sym_clear_all_valid();
+
+	file_write_dep("build/auto.conf.cmd");
+
+#if 0
+	if (conf_split_config())
+		return 1;
+#endif
+
+	out = fopen(".tmpconfig", "w");
+	if (!out)
+		return 1;
+
+	out_h = fopen(".tmpconfig.h", "w");
+	if (!out_h) {
+		fclose(out);
+		return 1;
+	}
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	time(&now);
+	fprintf(out, "#\n"
+		     "# Automatically generated make config: don't edit\n"
+		     "# FILO version: %s\n"
+		     "# %s"
+		     "#\n",
+		     getenv("KERNELVERSION"), ctime(&now));
+	fprintf(out_h, "/*\n"
+		       " * Automatically generated C config: don't edit\n"
+		       " * FILO version: %s\n"
+		       " * %s"
+		       " */\n"
+		       "#define AUTOCONF_INCLUDED\n",
+		       getenv("KERNELVERSION"), ctime(&now));
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+			continue;
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			switch (sym_get_tristate_value(sym)) {
+			case no:
+				break;
+			case mod:
+				fprintf(out, "CONFIG_%s=m\n", sym->name);
+				fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
+				break;
+			case yes:
+				fprintf(out, "CONFIG_%s=y\n", sym->name);
+				fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
+				break;
+			}
+			break;
+		case S_STRING:
+			str = sym_get_string_value(sym);
+			fprintf(out, "CONFIG_%s=\"", sym->name);
+			fprintf(out_h, "#define CONFIG_%s \"", sym->name);
+			while (1) {
+				l = strcspn(str, "\"\\");
+				if (l) {
+					fwrite(str, l, 1, out);
+					fwrite(str, l, 1, out_h);
+					str += l;
+				}
+				if (!*str)
+					break;
+				fprintf(out, "\\%c", *str);
+				fprintf(out_h, "\\%c", *str);
+				str++;
+			}
+			fputs("\"\n", out);
+			fputs("\"\n", out_h);
+			break;
+		case S_HEX:
+			str = sym_get_string_value(sym);
+			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+				fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
+				break;
+			}
+		case S_INT:
+			str = sym_get_string_value(sym);
+			fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+			fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
+			break;
+		default:
+			break;
+		}
+	}
+	fclose(out);
+	fclose(out_h);
+
+	name = getenv("KCONFIG_AUTOHEADER");
+	if (!name)
+		name = "include/linux/autoconf.h";
+	if (rename(".tmpconfig.h", name))
+		return 1;
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	/*
+	 * This must be the last step, kbuild has a dependency on auto.conf
+	 * and this marks the successful completion of the previous steps.
+	 */
+	if (rename(".tmpconfig", name))
+		return 1;
+
+	return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+	int _sym_change_count = sym_change_count;
+	sym_change_count = count;
+	if (conf_changed_callback &&
+	    (bool)_sym_change_count != (bool)count)
+		conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+	sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+	return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+	conf_changed_callback = fn;
+}

Added: trunk/filo/util/kconfig/expr.c
===================================================================
--- trunk/filo/util/kconfig/expr.c	                        (rev 0)
+++ trunk/filo/util/kconfig/expr.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1106 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR	0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = E_SYMBOL;
+	e->left.sym = sym;
+	return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = ce;
+	return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = e1;
+	e->right.expr = e2;
+	return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.sym = s1;
+	e->right.sym = s2;
+	return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(struct expr *org)
+{
+	struct expr *e;
+
+	if (!org)
+		return NULL;
+
+	e = malloc(sizeof(*org));
+	memcpy(e, org, sizeof(*org));
+	switch (org->type) {
+	case E_SYMBOL:
+		e->left = org->left;
+		break;
+	case E_NOT:
+		e->left.expr = expr_copy(org->left.expr);
+		break;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		e->left.sym = org->left.sym;
+		e->right.sym = org->right.sym;
+		break;
+	case E_AND:
+	case E_OR:
+	case E_LIST:
+		e->left.expr = expr_copy(org->left.expr);
+		e->right.expr = expr_copy(org->right.expr);
+		break;
+	default:
+		printf("can't copy type %d\n", e->type);
+		free(e);
+		e = NULL;
+		break;
+	}
+
+	return e;
+}
+
+void expr_free(struct expr *e)
+{
+	if (!e)
+		return;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		break;
+	case E_NOT:
+		expr_free(e->left.expr);
+		return;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		break;
+	case E_OR:
+	case E_AND:
+		expr_free(e->left.expr);
+		expr_free(e->right.expr);
+		break;
+	default:
+		printf("how to free type %d?\n", e->type);
+		break;
+	}
+	free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+	if (e1->type == type) {
+		__expr_eliminate_eq(type, &e1->left.expr, &e2);
+		__expr_eliminate_eq(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		__expr_eliminate_eq(type, &e1, &e2->left.expr);
+		__expr_eliminate_eq(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+	    e1->left.sym == e2->left.sym &&
+	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+		return;
+	if (!expr_eq(e1, e2))
+		return;
+	trans_count++;
+	expr_free(e1); expr_free(e2);
+	switch (type) {
+	case E_OR:
+		e1 = expr_alloc_symbol(&symbol_no);
+		e2 = expr_alloc_symbol(&symbol_no);
+		break;
+	case E_AND:
+		e1 = expr_alloc_symbol(&symbol_yes);
+		e2 = expr_alloc_symbol(&symbol_yes);
+		break;
+	default:
+		;
+	}
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+	if (!e1 || !e2)
+		return;
+	switch (e1->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e1->type, ep1, ep2);
+	default:
+		;
+	}
+	if (e1->type != e2->type) switch (e2->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e2->type, ep1, ep2);
+	default:
+		;
+	}
+	e1 = expr_eliminate_yn(e1);
+	e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+	int res, old_count;
+
+	if (e1->type != e2->type)
+		return 0;
+	switch (e1->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+	case E_SYMBOL:
+		return e1->left.sym == e2->left.sym;
+	case E_NOT:
+		return expr_eq(e1->left.expr, e2->left.expr);
+	case E_AND:
+	case E_OR:
+		e1 = expr_copy(e1);
+		e2 = expr_copy(e2);
+		old_count = trans_count;
+		expr_eliminate_eq(&e1, &e2);
+		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+		       e1->left.sym == e2->left.sym);
+		expr_free(e1);
+		expr_free(e2);
+		trans_count = old_count;
+		return res;
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+
+	if (DEBUG_EXPR) {
+		expr_fprint(e1, stdout);
+		printf(" = ");
+		expr_fprint(e2, stdout);
+		printf(" ?\n");
+	}
+
+	return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (e) switch (e->type) {
+	case E_AND:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		break;
+	case E_OR:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_AND:
+	case E_OR:
+	case E_NOT:
+		e->left.expr = expr_trans_bool(e->left.expr);
+		e->right.expr = expr_trans_bool(e->right.expr);
+		break;
+	case E_UNEQUAL:
+		// FOO!=n -> FOO
+		if (e->left.sym->type == S_TRISTATE) {
+			if (e->right.sym == &symbol_no) {
+				e->type = E_SYMBOL;
+				e->right.sym = NULL;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='m') -> (a!='n')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='n') -> (a!='m')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+			// (a='m') || (a='n') -> (a!='y')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+		}
+	}
+	if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+			return expr_alloc_symbol(&symbol_yes);
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") || (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+
+	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+		// (a) && (a='y') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+		// (a) && (a!='n') -> (a)
+		return expr_alloc_symbol(sym1);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+		// (a) && (a!='m') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e1->right.sym;
+			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e2->right.sym;
+			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='m') -> (a='n')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+			// (a!='m') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+			return NULL;
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") && (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp;
+
+	if (e1->type == type) {
+		expr_eliminate_dups1(type, &e1->left.expr, &e2);
+		expr_eliminate_dups1(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups1(type, &e1, &e2->left.expr);
+		expr_eliminate_dups1(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR: case E_AND:
+		expr_eliminate_dups1(e1->type, &e1, &e1);
+	default:
+		;
+	}
+
+	switch (type) {
+	case E_OR:
+		tmp = expr_join_or(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	case E_AND:
+		tmp = expr_join_and(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp, *tmp1, *tmp2;
+
+	if (e1->type == type) {
+		expr_eliminate_dups2(type, &e1->left.expr, &e2);
+		expr_eliminate_dups2(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups2(type, &e1, &e2->left.expr);
+		expr_eliminate_dups2(type, &e1, &e2->right.expr);
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO || BAR) && (!FOO && !BAR) -> n
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_and(&tmp1, &tmp2);
+		if (expr_is_yes(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_no);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	case E_AND:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO && BAR) || (!FOO || !BAR) -> y
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_or(&tmp1, &tmp2);
+		if (expr_is_no(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+	int oldcount;
+	if (!e)
+		return e;
+
+	oldcount = trans_count;
+	while (1) {
+		trans_count = 0;
+		switch (e->type) {
+		case E_OR: case E_AND:
+			expr_eliminate_dups1(e->type, &e, &e);
+			expr_eliminate_dups2(e->type, &e, &e);
+		default:
+			;
+		}
+		if (!trans_count)
+			break;
+		e = expr_eliminate_yn(e);
+	}
+	trans_count = oldcount;
+	return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+	case E_SYMBOL:
+	case E_LIST:
+		break;
+	default:
+		e->left.expr = expr_transform(e->left.expr);
+		e->right.expr = expr_transform(e->right.expr);
+	}
+
+	switch (e->type) {
+	case E_EQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_no;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_yes;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_NOT:
+		switch (e->left.expr->type) {
+		case E_NOT:
+			// !!a -> a
+			tmp = e->left.expr->left.expr;
+			free(e->left.expr);
+			free(e);
+			e = tmp;
+			e = expr_transform(e);
+			break;
+		case E_EQUAL:
+		case E_UNEQUAL:
+			// !a='x' -> a!='x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+			break;
+		case E_OR:
+			// !(a || b) -> !a && !b
+			tmp = e->left.expr;
+			e->type = E_AND;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_AND:
+			// !(a && b) -> !a || !b
+			tmp = e->left.expr;
+			e->type = E_OR;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_SYMBOL:
+			if (e->left.expr->left.sym == &symbol_yes) {
+				// !'y' -> 'n'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_mod) {
+				// !'m' -> 'm'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_mod;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_no) {
+				// !'n' -> 'y'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				break;
+			}
+			break;
+		default:
+			;
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return 0;
+
+	switch (dep->type) {
+	case E_AND:
+	case E_OR:
+		return expr_contains_symbol(dep->left.expr, sym) ||
+		       expr_contains_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return dep->left.sym == sym ||
+		       dep->right.sym == sym;
+	case E_NOT:
+		return expr_contains_symbol(dep->left.expr, sym);
+	default:
+		;
+	}
+	return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return false;
+
+	switch (dep->type) {
+	case E_AND:
+		return expr_depends_symbol(dep->left.expr, sym) ||
+		       expr_depends_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+				return true;
+		}
+		break;
+	case E_UNEQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_no)
+				return true;
+		}
+		break;
+	default:
+		;
+	}
+ 	return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_AND, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_OR, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	if (e1->type == type) {
+		expr_extract_eq(type, ep, &e1->left.expr, &e2);
+		expr_extract_eq(type, ep, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_extract_eq(type, ep, ep1, &e2->left.expr);
+		expr_extract_eq(type, ep, ep1, &e2->right.expr);
+		return;
+	}
+	if (expr_eq(e1, e2)) {
+		*ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+		expr_free(e2);
+		if (type == E_AND) {
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = expr_alloc_symbol(&symbol_yes);
+		} else if (type == E_OR) {
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = expr_alloc_symbol(&symbol_no);
+		}
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+	struct expr *e1, *e2;
+
+	if (!e) {
+		e = expr_alloc_symbol(sym);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	}
+	switch (e->type) {
+	case E_AND:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_OR:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_NOT:
+		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+	case E_UNEQUAL:
+	case E_EQUAL:
+		if (type == E_EQUAL) {
+			if (sym == &symbol_yes)
+				return expr_copy(e);
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_no);
+			if (sym == &symbol_no)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+		} else {
+			if (sym == &symbol_yes)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_yes);
+			if (sym == &symbol_no)
+				return expr_copy(e);
+		}
+		break;
+	case E_SYMBOL:
+		return expr_alloc_comp(type, e->left.sym, sym);
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+	return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+	tristate val1, val2;
+	const char *str1, *str2;
+
+	if (!e)
+		return yes;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		sym_calc_value(e->left.sym);
+		return e->left.sym->curr.tri;
+	case E_AND:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_AND(val1, val2);
+	case E_OR:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_OR(val1, val2);
+	case E_NOT:
+		val1 = expr_calc_value(e->left.expr);
+		return EXPR_NOT(val1);
+	case E_EQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? yes : no;
+	case E_UNEQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? no : yes;
+	default:
+		printf("expr_calc_value: %d?\n", e->type);
+		return no;
+	}
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+	return 1;
+#else
+	if (t1 == t2)
+		return 0;
+	switch (t1) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		if (t2 == E_NOT)
+			return 1;
+	case E_NOT:
+		if (t2 == E_AND)
+			return 1;
+	case E_AND:
+		if (t2 == E_OR)
+			return 1;
+	case E_OR:
+		if (t2 == E_LIST)
+			return 1;
+	case E_LIST:
+		if (t2 == 0)
+			return 1;
+	default:
+		return -1;
+	}
+	printf("[%dgt%d?]", t1, t2);
+	return 0;
+#endif
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+	if (!e) {
+		fn(data, NULL, "y");
+		return;
+	}
+
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, "(");
+	switch (e->type) {
+	case E_SYMBOL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		break;
+	case E_NOT:
+		fn(data, NULL, "!");
+		expr_print(e->left.expr, fn, data, E_NOT);
+		break;
+	case E_EQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "!=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_OR:
+		expr_print(e->left.expr, fn, data, E_OR);
+		fn(data, NULL, " || ");
+		expr_print(e->right.expr, fn, data, E_OR);
+		break;
+	case E_AND:
+		expr_print(e->left.expr, fn, data, E_AND);
+		fn(data, NULL, " && ");
+		expr_print(e->right.expr, fn, data, E_AND);
+		break;
+	case E_LIST:
+		fn(data, e->right.sym, e->right.sym->name);
+		if (e->left.expr) {
+			fn(data, NULL, " ^ ");
+			expr_print(e->left.expr, fn, data, E_LIST);
+		}
+		break;
+	case E_RANGE:
+		fn(data, NULL, "[");
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, " ");
+		fn(data, e->right.sym, e->right.sym->name);
+		fn(data, NULL, "]");
+		break;
+	default:
+	  {
+		char buf[32];
+		sprintf(buf, "<unknown type %d>", e->type);
+		fn(data, NULL, buf);
+		break;
+	  }
+	}
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+	fwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+	expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+	str_append((struct gstr*)data, str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+	expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}

Added: trunk/filo/util/kconfig/expr.h
===================================================================
--- trunk/filo/util/kconfig/expr.h	                        (rev 0)
+++ trunk/filo/util/kconfig/expr.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+	struct file *next;
+	struct file *parent;
+	char *name;
+	int lineno;
+	int flags;
+};
+
+#define FILE_BUSY		0x0001
+#define FILE_SCANNED		0x0002
+
+typedef enum tristate {
+	no, mod, yes
+} tristate;
+
+enum expr_type {
+	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+	struct expr *expr;
+	struct symbol *sym;
+};
+
+struct expr {
+	enum expr_type type;
+	union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)		(2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+	for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+	struct expr *expr;
+	tristate tri;
+};
+
+struct symbol_value {
+	void *val;
+	tristate tri;
+};
+
+enum symbol_type {
+	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,
+};
+
+struct symbol {
+	struct symbol *next;
+	char *name;
+	enum symbol_type type;
+	struct symbol_value curr;
+	struct symbol_value def[4];
+	tristate visible;
+	int flags;
+	struct property *prop;
+	struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST		0x0001
+#define SYMBOL_CHECK		0x0008
+#define SYMBOL_CHOICE		0x0010
+#define SYMBOL_CHOICEVAL	0x0020
+#define SYMBOL_VALID		0x0080
+#define SYMBOL_OPTIONAL		0x0100
+#define SYMBOL_WRITE		0x0200
+#define SYMBOL_CHANGED		0x0400
+#define SYMBOL_AUTO		0x1000
+#define SYMBOL_CHECKED		0x2000
+#define SYMBOL_WARNED		0x8000
+#define SYMBOL_DEF		0x10000
+#define SYMBOL_DEF_USER		0x10000
+#define SYMBOL_DEF_AUTO		0x20000
+#define SYMBOL_DEF3		0x40000
+#define SYMBOL_DEF4		0x80000
+
+#define SYMBOL_MAXLENGTH	256
+#define SYMBOL_HASHSIZE		257
+#define SYMBOL_HASHMASK		0xff
+
+enum prop_type {
+	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE,
+	P_SELECT, P_RANGE, P_ENV
+};
+
+struct property {
+	struct property *next;
+	struct symbol *sym;
+	enum prop_type type;
+	const char *text;
+	struct expr_value visible;
+	struct expr *expr;
+	struct menu *menu;
+	struct file *file;
+	int lineno;
+};
+
+#define for_all_properties(sym, st, tok) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->text)
+
+struct menu {
+	struct menu *next;
+	struct menu *parent;
+	struct menu *list;
+	struct symbol *sym;
+	struct property *prompt;
+	struct expr *dep;
+	unsigned int flags;
+	char *help;
+	struct file *file;
+	int lineno;
+	void *data;
+};
+
+#define MENU_CHANGED		0x0001
+#define MENU_ROOT		0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */

Added: trunk/filo/util/kconfig/gconf.c
===================================================================
--- trunk/filo/util/kconfig/gconf.c	                        (rev 0)
+++ trunk/filo/util/kconfig/gconf.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1636 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms at tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean show_all = FALSE;
+static gboolean show_debug = FALSE;
+static gboolean resizeable = FALSE;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL;	// left  frame
+GtkWidget *tree2_w = NULL;	// right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+	COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+	COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+	COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+
+const char *dbg_print_stype(int val)
+{
+	static char buf[256];
+
+	bzero(buf, 256);
+
+	if (val == S_UNKNOWN)
+		strcpy(buf, "unknown");
+	if (val == S_BOOLEAN)
+		strcpy(buf, "boolean");
+	if (val == S_TRISTATE)
+		strcpy(buf, "tristate");
+	if (val == S_INT)
+		strcpy(buf, "int");
+	if (val == S_HEX)
+		strcpy(buf, "hex");
+	if (val == S_STRING)
+		strcpy(buf, "string");
+	if (val == S_OTHER)
+		strcpy(buf, "other");
+
+#ifdef DEBUG
+	printf("%s", buf);
+#endif
+
+	return buf;
+}
+
+const char *dbg_print_flags(int val)
+{
+	static char buf[256];
+
+	bzero(buf, 256);
+
+	if (val & SYMBOL_CONST)
+		strcat(buf, "const/");
+	if (val & SYMBOL_CHECK)
+		strcat(buf, "check/");
+	if (val & SYMBOL_CHOICE)
+		strcat(buf, "choice/");
+	if (val & SYMBOL_CHOICEVAL)
+		strcat(buf, "choiceval/");
+	if (val & SYMBOL_VALID)
+		strcat(buf, "valid/");
+	if (val & SYMBOL_OPTIONAL)
+		strcat(buf, "optional/");
+	if (val & SYMBOL_WRITE)
+		strcat(buf, "write/");
+	if (val & SYMBOL_CHANGED)
+		strcat(buf, "changed/");
+	if (val & SYMBOL_AUTO)
+		strcat(buf, "auto/");
+
+	buf[strlen(buf) - 1] = '\0';
+#ifdef DEBUG
+	printf("%s", buf);
+#endif
+
+	return buf;
+}
+
+const char *dbg_print_ptype(int val)
+{
+	static char buf[256];
+
+	bzero(buf, 256);
+
+	if (val == P_UNKNOWN)
+		strcpy(buf, "unknown");
+	if (val == P_PROMPT)
+		strcpy(buf, "prompt");
+	if (val == P_COMMENT)
+		strcpy(buf, "comment");
+	if (val == P_MENU)
+		strcpy(buf, "menu");
+	if (val == P_DEFAULT)
+		strcpy(buf, "default");
+	if (val == P_CHOICE)
+		strcpy(buf, "choice");
+
+#ifdef DEBUG
+	printf("%s", buf);
+#endif
+
+	return buf;
+}
+
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+	GdkPixmap *pixmap;
+	GdkBitmap *mask;
+	GtkToolButton *button;
+	GtkWidget *image;
+
+	pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+					      &style->bg[GTK_STATE_NORMAL],
+					      xpm);
+
+	button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+	image = gtk_image_new_from_pixmap(pixmap, mask);
+	gtk_widget_show(image);
+	gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+	GladeXML *xml;
+	GtkWidget *widget;
+	GtkTextBuffer *txtbuf;
+	char title[256];
+	GtkStyle *style;
+
+	xml = glade_xml_new(glade_file, "window1", NULL);
+	if (!xml)
+		g_error(_("GUI loading failed !\n"));
+	glade_xml_signal_autoconnect(xml);
+
+	main_wnd = glade_xml_get_widget(xml, "window1");
+	hpaned = glade_xml_get_widget(xml, "hpaned1");
+	vpaned = glade_xml_get_widget(xml, "vpaned1");
+	tree1_w = glade_xml_get_widget(xml, "treeview1");
+	tree2_w = glade_xml_get_widget(xml, "treeview2");
+	text_w = glade_xml_get_widget(xml, "textview3");
+
+	back_btn = glade_xml_get_widget(xml, "button1");
+	gtk_widget_set_sensitive(back_btn, FALSE);
+
+	widget = glade_xml_get_widget(xml, "show_name1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_name);
+
+	widget = glade_xml_get_widget(xml, "show_range1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_range);
+
+	widget = glade_xml_get_widget(xml, "show_data1");
+	gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+				       show_value);
+
+	save_btn = glade_xml_get_widget(xml, "button3");
+	save_menu_item = glade_xml_get_widget(xml, "save1");
+	conf_set_changed_callback(conf_changed);
+
+	style = gtk_widget_get_style(main_wnd);
+	widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0	/* Use stock Gtk icons instead */
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button1", (gchar **) xpm_back);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button2", (gchar **) xpm_load);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button3", (gchar **) xpm_save);
+#endif
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button4", (gchar **) xpm_single_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button5", (gchar **) xpm_split_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button6", (gchar **) xpm_tree_view);
+
+#if 0
+	switch (view_mode) {
+	case SINGLE_VIEW:
+		widget = glade_xml_get_widget(xml, "button4");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	case SPLIT_VIEW:
+		widget = glade_xml_get_widget(xml, "button5");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	case FULL_VIEW:
+		widget = glade_xml_get_widget(xml, "button6");
+		g_signal_emit_by_name(widget, "clicked");
+		break;
+	}
+#endif
+	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+					  "foreground", "red",
+					  "weight", PANGO_WEIGHT_BOLD,
+					  NULL);
+	tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+					  /*"style", PANGO_STYLE_OBLIQUE, */
+					  NULL);
+
+	sprintf(title, _("FILO v%s Configuration"),
+		getenv("KERNELVERSION"));
+	gtk_window_set_title(GTK_WINDOW(main_wnd), title);
+
+	gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+	gint i;
+
+	tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_STRING, G_TYPE_STRING,
+					  G_TYPE_POINTER, GDK_TYPE_COLOR,
+					  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+					  G_TYPE_BOOLEAN);
+	model2 = GTK_TREE_MODEL(tree2);
+
+	for (parents[0] = NULL, i = 1; i < 256; i++)
+		parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+	tree1 = gtk_tree_store_new(COL_NUMBER,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_STRING, G_TYPE_STRING,
+				   G_TYPE_POINTER, GDK_TYPE_COLOR,
+				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+				   G_TYPE_BOOLEAN);
+	model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+	GtkCellRenderer *renderer;
+	GtkTreeSelection *sel;
+	GtkTreeViewColumn *column;
+
+	gtk_tree_view_set_model(view, model1);
+	gtk_tree_view_set_headers_visible(view, TRUE);
+	gtk_tree_view_set_rules_hint(view, FALSE);
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_append_column(view, column);
+	gtk_tree_view_column_set_title(column, _("Options"));
+
+	renderer = gtk_cell_renderer_toggle_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "active", COL_BTNACT,
+					    "inconsistent", COL_BTNINC,
+					    "visible", COL_BTNVIS,
+					    "radio", COL_BTNRAD, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "text", COL_OPTION,
+					    "foreground-gdk",
+					    COL_COLOR, NULL);
+
+	sel = gtk_tree_view_get_selection(view);
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+	gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+			    const gchar * path_string,
+			    const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+			     gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+	GtkCellRenderer *renderer;
+	GtkTreeSelection *sel;
+	GtkTreeViewColumn *column;
+	gint i;
+
+	gtk_tree_view_set_model(view, model2);
+	gtk_tree_view_set_headers_visible(view, TRUE);
+	gtk_tree_view_set_rules_hint(view, FALSE);
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_append_column(view, column);
+	gtk_tree_view_column_set_title(column, _("Options"));
+
+	renderer = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "pixbuf", COL_PIXBUF,
+					    "visible", COL_PIXVIS, NULL);
+	renderer = gtk_cell_renderer_toggle_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "active", COL_BTNACT,
+					    "inconsistent", COL_BTNINC,
+					    "visible", COL_BTNVIS,
+					    "radio", COL_BTNRAD, NULL);
+	/*g_signal_connect(G_OBJECT(renderer), "toggled",
+	   G_CALLBACK(renderer_toggled), NULL); */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+					renderer, FALSE);
+	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+					    renderer,
+					    "text", COL_OPTION,
+					    "foreground-gdk",
+					    COL_COLOR, NULL);
+
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    _("Name"), renderer,
+						    "text", COL_NAME,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "N", renderer,
+						    "text", COL_NO,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "M", renderer,
+						    "text", COL_MOD,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    "Y", renderer,
+						    "text", COL_YES,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(view, -1,
+						    _("Value"), renderer,
+						    "text", COL_VALUE,
+						    "editable",
+						    COL_EDIT,
+						    "foreground-gdk",
+						    COL_COLOR, NULL);
+	g_signal_connect(G_OBJECT(renderer), "edited",
+			 G_CALLBACK(renderer_edited), NULL);
+
+	column = gtk_tree_view_get_column(view, COL_NAME);
+	gtk_tree_view_column_set_visible(column, show_name);
+	column = gtk_tree_view_get_column(view, COL_NO);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_MOD);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_YES);
+	gtk_tree_view_column_set_visible(column, show_range);
+	column = gtk_tree_view_get_column(view, COL_VALUE);
+	gtk_tree_view_column_set_visible(column, show_value);
+
+	if (resizeable) {
+		for (i = 0; i < COL_VALUE; i++) {
+			column = gtk_tree_view_get_column(view, i);
+			gtk_tree_view_column_set_resizable(column, TRUE);
+		}
+	}
+
+	sel = gtk_tree_view_get_selection(view);
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	const char *prompt = _(menu_get_prompt(menu));
+	gchar *name;
+	const char *help;
+
+	help = menu_get_help(menu);
+
+	/* Gettextize if the help text not empty */
+	if ((help != 0) && (help[0] != 0))
+		help = _(help);
+
+	if (menu->sym && menu->sym->name)
+		name = g_strdup_printf(menu->sym->name);
+	else
+		name = g_strdup("");
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	gtk_text_buffer_get_bounds(buffer, &start, &end);
+	gtk_text_buffer_delete(buffer, &start, &end);
+	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+					 NULL);
+	gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
+					 NULL);
+	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
+					 NULL);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	const char *msg = message;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+	gtk_text_buffer_get_bounds(buffer, &start, &end);
+	gtk_text_buffer_delete(buffer, &start, &end);
+	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+					 NULL);
+	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+	gtk_text_buffer_get_end_iter(buffer, &end);
+	gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+					 NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+				 gpointer user_data)
+{
+	GtkWidget *dialog, *label;
+	gint result;
+
+	if (!conf_get_changed())
+		return FALSE;
+
+	dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+					     GTK_WINDOW(main_wnd),
+					     (GtkDialogFlags)
+					     (GTK_DIALOG_MODAL |
+					      GTK_DIALOG_DESTROY_WITH_PARENT),
+					     GTK_STOCK_OK,
+					     GTK_RESPONSE_YES,
+					     GTK_STOCK_NO,
+					     GTK_RESPONSE_NO,
+					     GTK_STOCK_CANCEL,
+					     GTK_RESPONSE_CANCEL, NULL);
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+					GTK_RESPONSE_CANCEL);
+
+	label = gtk_label_new(_("\nSave configuration ?\n"));
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+	gtk_widget_show(label);
+
+	result = gtk_dialog_run(GTK_DIALOG(dialog));
+	switch (result) {
+	case GTK_RESPONSE_YES:
+		on_save_activate(NULL, NULL);
+		return FALSE;
+	case GTK_RESPONSE_NO:
+		return FALSE;
+	case GTK_RESPONSE_CANCEL:
+	case GTK_RESPONSE_DELETE_EVENT:
+	default:
+		gtk_widget_destroy(dialog);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+	gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+			GtkRequisition * requisition, gpointer user_data)
+{
+	static gint old_h;
+	gint w, h;
+
+	if (widget->window == NULL)
+		gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+	else
+		gdk_window_get_size(widget->window, &w, &h);
+
+	if (h == old_h)
+		return;
+	old_h = h;
+
+	gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+	const gchar *fn;
+
+	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+					     (user_data));
+
+	if (conf_read(fn))
+		text_insert_msg(_("Error"), _("Unable to load configuration !"));
+	else
+		display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *fs;
+
+	fs = gtk_file_selection_new(_("Load file..."));
+	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+			 "clicked",
+			 G_CALLBACK(load_filename), (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->ok_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->cancel_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	if (conf_write(NULL))
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+	if (conf_write_autoconf())
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+	const gchar *fn;
+
+	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+					     (user_data));
+
+	if (conf_write(fn))
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+	if (conf_write_autoconf())
+		text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+	gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *fs;
+
+	fs = gtk_file_selection_new(_("Save file as..."));
+	g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+			 "clicked",
+			 G_CALLBACK(store_filename), (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->ok_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	g_signal_connect_swapped(GTK_OBJECT
+				 (GTK_FILE_SELECTION(fs)->cancel_button),
+				 "clicked", G_CALLBACK(gtk_widget_destroy),
+				 (gpointer) fs);
+	gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	if (!on_window1_delete_event(NULL, NULL, NULL))
+		gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkTreeViewColumn *col;
+
+	show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+	if (col)
+		gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
+
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	// instead of update_tree to speed-up
+}
+
+
+void
+on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	update_tree(&rootmenu, NULL);
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *intro_text = _(
+	    "Welcome to gkc, the GTK+ graphical configuration tool\n"
+	    "for FILO.\n"
+	    "For each option, a blank box indicates the feature is disabled, a\n"
+	    "check indicates it is enabled, and a dot indicates that it is to\n"
+	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
+	    "\n"
+	    "If you do not see an option (e.g., a device driver) that you\n"
+	    "believe should be present, try turning on Show All Options\n"
+	    "under the Options menu.\n"
+	    "Although there is no cross reference yet to help you figure out\n"
+	    "what other options must be enabled to support the option you\n"
+	    "are interested in, you can still view the help of a grayed-out\n"
+	    "option.\n"
+	    "\n"
+	    "Toggling Show Debug Info under the Options menu will show \n"
+	    "the dependencies, which you can then match by examining other options.");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, intro_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *about_text =
+	    _("gkc is copyright (c) 2002 Romain Lievin <roms at lpg.ticalc.org>.\n"
+	      "Based on the source code from Roman Zippel.\n");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, about_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+	GtkWidget *dialog;
+	const gchar *license_text =
+	    _("gkc is released under the terms of the GNU GPL v2.\n"
+	      "For more information, please see the source code or\n"
+	      "visit http://www.fsf.org/licenses/licenses.html\n");
+
+	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_CLOSE, license_text);
+	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+				 G_CALLBACK(gtk_widget_destroy),
+				 GTK_OBJECT(dialog));
+	gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+	enum prop_type ptype;
+
+	current = current->parent;
+	ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+	if (ptype != P_MENU)
+		current = current->parent;
+	display_tree_part();
+
+	if (current == &rootmenu)
+		gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+	on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+	view_mode = SINGLE_VIEW;
+	gtk_paned_set_position(GTK_PANED(hpaned), 0);
+	gtk_widget_hide(tree1_w);
+	current = &rootmenu;
+	display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+	gint w, h;
+	view_mode = SPLIT_VIEW;
+	gtk_widget_show(tree1_w);
+	gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+	gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	display_list();
+
+	/* Disable back btn, like in full mode. */
+	gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+	view_mode = FULL_VIEW;
+	gtk_paned_set_position(GTK_PANED(hpaned), 0);
+	gtk_widget_hide(tree1_w);
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);
+	gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+			    const gchar * path_string,
+			    const gchar * new_text, gpointer user_data)
+{
+	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+	GtkTreeIter iter;
+	const char *old_def, *new_def;
+	struct menu *menu;
+	struct symbol *sym;
+
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return;
+
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+	sym = menu->sym;
+
+	gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+	new_def = new_text;
+
+	sym_set_string_value(sym, new_def);
+
+	update_tree(&rootmenu, NULL);
+
+	gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+	struct symbol *sym = menu->sym;
+	tristate oldval, newval;
+
+	if (!sym)
+		return;
+
+	if (col == COL_NO)
+		newval = no;
+	else if (col == COL_MOD)
+		newval = mod;
+	else if (col == COL_YES)
+		newval = yes;
+	else
+		return;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldval = sym_get_tristate_value(sym);
+		if (!sym_tristate_within_range(sym, newval))
+			newval = yes;
+		sym_set_tristate_value(sym, newval);
+		if (view_mode == FULL_VIEW)
+			update_tree(&rootmenu, NULL);
+		else if (view_mode == SPLIT_VIEW) {
+			update_tree(browsed, NULL);
+			display_list();
+		}
+		else if (view_mode == SINGLE_VIEW)
+			display_tree_part();	//fixme: keep exp/coll
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+	default:
+		break;
+	}
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+	if (!menu->sym)
+		return;
+
+	sym_toggle_tristate_value(menu->sym);
+	if (view_mode == FULL_VIEW)
+		update_tree(&rootmenu, NULL);
+	else if (view_mode == SPLIT_VIEW) {
+		update_tree(browsed, NULL);
+		display_list();
+	}
+	else if (view_mode == SINGLE_VIEW)
+		display_tree_part();	//fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
+			     gchar * path_string, gpointer user_data)
+{
+	GtkTreePath *path, *sel_path = NULL;
+	GtkTreeIter iter, sel_iter;
+	GtkTreeSelection *sel;
+	struct menu *menu;
+
+	path = gtk_tree_path_new_from_string(path_string);
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return;
+
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+	if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+		sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+	if (!sel_path)
+		goto out1;
+	if (gtk_tree_path_compare(path, sel_path))
+		goto out2;
+
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+	toggle_sym_value(menu);
+
+      out2:
+	gtk_tree_path_free(sel_path);
+      out1:
+	gtk_tree_path_free(path);
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+	gint i;
+
+	for (i = 0; i < COL_NUMBER; i++) {
+		GtkTreeViewColumn *col;
+
+		col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+		if (col == column)
+			return i;
+	}
+
+	return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+				GdkEventButton * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+	gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+	gint tx = (gint) event->x;
+	gint ty = (gint) event->y;
+	gint cx, cy;
+
+	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+				      &cy);
+#else
+	gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+	if (path == NULL)
+		return FALSE;
+
+	if (!gtk_tree_model_get_iter(model2, &iter, path))
+		return FALSE;
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+	col = column2index(column);
+	if (event->type == GDK_2BUTTON_PRESS) {
+		enum prop_type ptype;
+		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+		if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+			// goes down into menu
+			current = menu;
+			display_tree_part();
+			gtk_widget_set_sensitive(back_btn, TRUE);
+		} else if ((col == COL_OPTION)) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	} else {
+		if (col == COL_VALUE) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		} else if (col == COL_NO || col == COL_MOD
+			   || col == COL_YES) {
+			change_sym_value(menu, col);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	}
+
+	return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+			     GdkEventKey * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+	gint col;
+
+	gtk_tree_view_get_cursor(view, &path, &column);
+	if (path == NULL)
+		return FALSE;
+
+	if (event->keyval == GDK_space) {
+		if (gtk_tree_view_row_expanded(view, path))
+			gtk_tree_view_collapse_row(view, path);
+		else
+			gtk_tree_view_expand_row(view, path, FALSE);
+		return TRUE;
+	}
+	if (event->keyval == GDK_KP_Enter) {
+	}
+	if (widget == tree1_w)
+		return FALSE;
+
+	gtk_tree_model_get_iter(model2, &iter, path);
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+	if (!strcasecmp(event->string, "n"))
+		col = COL_NO;
+	else if (!strcasecmp(event->string, "m"))
+		col = COL_MOD;
+	else if (!strcasecmp(event->string, "y"))
+		col = COL_YES;
+	else
+		col = -1;
+	change_sym_value(menu, col);
+
+	return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+	GtkTreeSelection *selection;
+	GtkTreeIter iter;
+	struct menu *menu;
+
+	selection = gtk_tree_view_get_selection(treeview);
+	if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+		gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+		text_insert_help(menu);
+	}
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+				GdkEventButton * event, gpointer user_data)
+{
+	GtkTreeView *view = GTK_TREE_VIEW(widget);
+	GtkTreePath *path;
+	GtkTreeViewColumn *column;
+	GtkTreeIter iter;
+	struct menu *menu;
+
+	gint tx = (gint) event->x;
+	gint ty = (gint) event->y;
+	gint cx, cy;
+
+	gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+				      &cy);
+	if (path == NULL)
+		return FALSE;
+
+	gtk_tree_model_get_iter(model1, &iter, path);
+	gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+	if (event->type == GDK_2BUTTON_PRESS) {
+		toggle_sym_value(menu);
+		current = menu;
+		display_tree_part();
+	} else {
+		browsed = menu;
+		display_tree_part();
+	}
+
+	gtk_widget_realize(tree2_w);
+	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+	gtk_widget_grab_focus(tree2_w);
+
+	return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+	static gchar *row[COL_NUMBER];
+	struct symbol *sym = menu->sym;
+	const char *def;
+	int stype;
+	tristate val;
+	enum prop_type ptype;
+	int i;
+
+	for (i = COL_OPTION; i <= COL_COLOR; i++)
+		g_free(row[i]);
+	bzero(row, sizeof(row));
+
+	row[COL_OPTION] =
+	    g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+			    sym && sym_has_value(sym) ? "(NEW)" : "");
+
+	if (show_all && !menu_is_visible(menu))
+		row[COL_COLOR] = g_strdup("DarkGray");
+	else
+		row[COL_COLOR] = g_strdup("Black");
+
+	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	switch (ptype) {
+	case P_MENU:
+		row[COL_PIXBUF] = (gchar *) xpm_menu;
+		if (view_mode == SINGLE_VIEW)
+			row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	case P_COMMENT:
+		row[COL_PIXBUF] = (gchar *) xpm_void;
+		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	default:
+		row[COL_PIXBUF] = (gchar *) xpm_void;
+		row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+		break;
+	}
+
+	if (!sym)
+		return row;
+	row[COL_NAME] = g_strdup(sym->name);
+
+	sym_calc_value(sym);
+	sym->flags &= ~SYMBOL_CHANGED;
+
+	if (sym_is_choice(sym)) {	// parse childs for getting final value
+		struct menu *child;
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child)
+			    && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		if (def_menu)
+			row[COL_VALUE] =
+			    g_strdup(_(menu_get_prompt(def_menu)));
+	}
+	if (sym->flags & SYMBOL_CHOICEVAL)
+		row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+	stype = sym_get_type(sym);
+	switch (stype) {
+	case S_BOOLEAN:
+		if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+		if (sym_is_choice(sym))
+			break;
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			row[COL_NO] = g_strdup("N");
+			row[COL_VALUE] = g_strdup("N");
+			row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+			break;
+		case mod:
+			row[COL_MOD] = g_strdup("M");
+			row[COL_VALUE] = g_strdup("M");
+			row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+			break;
+		case yes:
+			row[COL_YES] = g_strdup("Y");
+			row[COL_VALUE] = g_strdup("Y");
+			row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+			row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+			break;
+		}
+
+		if (val != no && sym_tristate_within_range(sym, no))
+			row[COL_NO] = g_strdup("_");
+		if (val != mod && sym_tristate_within_range(sym, mod))
+			row[COL_MOD] = g_strdup("_");
+		if (val != yes && sym_tristate_within_range(sym, yes))
+			row[COL_YES] = g_strdup("_");
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		def = sym_get_string_value(sym);
+		row[COL_VALUE] = g_strdup(def);
+		row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+		break;
+	}
+
+	return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+	GdkColor color;
+	gboolean success;
+	GdkPixbuf *pix;
+
+	pix = gdk_pixbuf_new_from_xpm_data((const char **)
+					   row[COL_PIXBUF]);
+
+	gdk_color_parse(row[COL_COLOR], &color);
+	gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+				  FALSE, FALSE, &success);
+
+	gtk_tree_store_set(tree, node,
+			   COL_OPTION, row[COL_OPTION],
+			   COL_NAME, row[COL_NAME],
+			   COL_NO, row[COL_NO],
+			   COL_MOD, row[COL_MOD],
+			   COL_YES, row[COL_YES],
+			   COL_VALUE, row[COL_VALUE],
+			   COL_MENU, (gpointer) menu,
+			   COL_COLOR, &color,
+			   COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+			   COL_PIXBUF, pix,
+			   COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+			   COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+			   COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+			   COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+			   COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+			   -1);
+
+	g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+	GtkTreeIter *parent = parents[indent - 1];
+	GtkTreeIter *node = parents[indent];
+
+	gtk_tree_store_append(tree, node, parent);
+	set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+				    struct menu *tofind)
+{
+	GtkTreeIter iter;
+	GtkTreeIter *child = &iter;
+	gboolean valid;
+	GtkTreeIter *ret;
+
+	valid = gtk_tree_model_iter_children(model2, child, parent);
+	while (valid) {
+		struct menu *menu;
+
+		gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+		if (menu == tofind) {
+			memcpy(&found, child, sizeof(GtkTreeIter));
+			return &found;
+		}
+
+		ret = gtktree_iter_find_node(child, tofind);
+		if (ret)
+			return ret;
+
+		valid = gtk_tree_model_iter_next(model2, child);
+	}
+
+	return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+	struct menu *child1;
+	GtkTreeIter iter, tmp;
+	GtkTreeIter *child2 = &iter;
+	gboolean valid;
+	GtkTreeIter *sibling;
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *menu1, *menu2;
+
+	if (src == &rootmenu)
+		indent = 1;
+
+	valid = gtk_tree_model_iter_children(model2, child2, dst);
+	for (child1 = src->list; child1; child1 = child1->next) {
+
+		prop = child1->prompt;
+		sym = child1->sym;
+
+	      reparse:
+		menu1 = child1;
+		if (valid)
+			gtk_tree_model_get(model2, child2, COL_MENU,
+					   &menu2, -1);
+		else
+			menu2 = NULL;	// force adding of a first child
+
+#ifdef DEBUG
+		printf("%*c%s | %s\n", indent, ' ',
+		       menu1 ? menu_get_prompt(menu1) : "nil",
+		       menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+		if (!menu_is_visible(child1) && !show_all) {	// remove node
+			if (gtktree_iter_find_node(dst, menu1) != NULL) {
+				memcpy(&tmp, child2, sizeof(GtkTreeIter));
+				valid = gtk_tree_model_iter_next(model2,
+								 child2);
+				gtk_tree_store_remove(tree2, &tmp);
+				if (!valid)
+					return;	// next parent
+				else
+					goto reparse;	// next child
+			} else
+				continue;
+		}
+
+		if (menu1 != menu2) {
+			if (gtktree_iter_find_node(dst, menu1) == NULL) {	// add node
+				if (!valid && !menu2)
+					sibling = NULL;
+				else
+					sibling = child2;
+				gtk_tree_store_insert_before(tree2,
+							     child2,
+							     dst, sibling);
+				set_node(child2, menu1, fill_row(menu1));
+				if (menu2 == NULL)
+					valid = TRUE;
+			} else {	// remove node
+				memcpy(&tmp, child2, sizeof(GtkTreeIter));
+				valid = gtk_tree_model_iter_next(model2,
+								 child2);
+				gtk_tree_store_remove(tree2, &tmp);
+				if (!valid)
+					return;	// next parent
+				else
+					goto reparse;	// next child
+			}
+		} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+			set_node(child2, menu1, fill_row(menu1));
+		}
+
+		indent++;
+		update_tree(child1, child2);
+		indent--;
+
+		valid = gtk_tree_model_iter_next(model2, child2);
+	}
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	enum prop_type ptype;
+
+	if (menu == &rootmenu) {
+		indent = 1;
+		current = &rootmenu;
+	}
+
+	for (child = menu->list; child; child = child->next) {
+		prop = child->prompt;
+		sym = child->sym;
+		ptype = prop ? prop->type : P_UNKNOWN;
+
+		if (sym)
+			sym->flags &= ~SYMBOL_CHANGED;
+
+		if ((view_mode == SPLIT_VIEW)
+		    && !(child->flags & MENU_ROOT) && (tree == tree1))
+			continue;
+
+		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+		    && (tree == tree2))
+			continue;
+
+		if (menu_is_visible(child) || show_all)
+			place_node(child, fill_row(child));
+#ifdef DEBUG
+		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+		printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+		dbg_print_ptype(ptype);
+		printf(" | ");
+		if (sym) {
+			dbg_print_stype(sym->type);
+			printf(" | ");
+			dbg_print_flags(sym->flags);
+			printf("\n");
+		} else
+			printf("\n");
+#endif
+		if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+		    && (tree == tree2))
+			continue;
+/*
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+		    || (view_mode == FULL_VIEW)
+		    || (view_mode == SPLIT_VIEW))*/
+		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+		    || (view_mode == FULL_VIEW)
+		    || (view_mode == SPLIT_VIEW)) {
+			indent++;
+			display_tree(child);
+			indent--;
+		}
+	}
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	if (view_mode == SINGLE_VIEW)
+		display_tree(current);
+	else if (view_mode == SPLIT_VIEW)
+		display_tree(browsed);
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+	if (tree1)
+		gtk_tree_store_clear(tree1);
+
+	tree = tree1;
+	display_tree(&rootmenu);
+	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+	tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+	struct menu *child;
+	static int menu_cnt = 0;
+
+	menu->flags |= MENU_ROOT;
+	for (child = menu->list; child; child = child->next) {
+		if (child->prompt && child->prompt->type == P_MENU) {
+			menu_cnt++;
+			fixup_rootmenu(child);
+			menu_cnt--;
+		} else if (!menu_cnt)
+			fixup_rootmenu(child);
+	}
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+	const char *name;
+	char *env;
+	gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+	kconfig_load();
+#endif
+
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset(PACKAGE, "UTF-8");
+	textdomain(PACKAGE);
+
+	/* GTK stuffs */
+	gtk_set_locale();
+	gtk_init(&ac, &av);
+	glade_init();
+
+	//add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+	//add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+	/* Determine GUI path */
+	env = getenv(SRCTREE);
+	if (env)
+		glade_file = g_strconcat(env, "/util/kconfig/gconf.glade", NULL);
+	else if (av[0][0] == '/')
+		glade_file = g_strconcat(av[0], ".glade", NULL);
+	else
+		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+	/* Load the interface and connect signals */
+	init_main_window(glade_file);
+	init_tree_model();
+	init_left_tree();
+	init_right_tree();
+
+	/* Conf stuffs */
+	if (ac > 1 && av[1][0] == '-') {
+		switch (av[1][1]) {
+		case 'a':
+			//showAll = 1;
+			break;
+		case 'h':
+		case '?':
+			printf("%s <config>\n", av[0]);
+			exit(0);
+		}
+		name = av[2];
+	} else
+		name = av[1];
+
+	conf_parse(name);
+	fixup_rootmenu(&rootmenu);
+	conf_read(NULL);
+
+	switch (view_mode) {
+	case SINGLE_VIEW:
+		display_tree_part();
+		break;
+	case SPLIT_VIEW:
+		display_list();
+		break;
+	case FULL_VIEW:
+		display_tree(&rootmenu);
+		break;
+	}
+
+	gtk_main();
+
+	return 0;
+}
+
+static void conf_changed(void)
+{
+	bool changed = conf_get_changed();
+	gtk_widget_set_sensitive(save_btn, changed);
+	gtk_widget_set_sensitive(save_menu_item, changed);
+}

Added: trunk/filo/util/kconfig/gconf.glade
===================================================================
--- trunk/filo/util/kconfig/gconf.glade	                        (rev 0)
+++ trunk/filo/util/kconfig/gconf.glade	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,648 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Gtk FILO Configurator</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+  <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+  <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+	<widget class="GtkMenuBar" id="menubar1">
+	  <property name="visible">True</property>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="file1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_File</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="file1_menu">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="load1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Load a config file</property>
+		      <property name="label" translatable="yes">_Load</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_load1_activate"/>
+		      <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image39">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-open</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Save the config in .config</property>
+		      <property name="label" translatable="yes">_Save</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_save_activate"/>
+		      <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image40">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-save</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save_as1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Save the config in a file</property>
+		      <property name="label" translatable="yes">Save _as</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_save_as1_activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image41">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-save-as</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separator1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="quit1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Quit</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_quit1_activate"/>
+		      <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image42">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-quit</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="options1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Options</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="options1_menu">
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_name1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show name</property>
+		      <property name="label" translatable="yes">Show _name</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_name1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_range1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+		      <property name="label" translatable="yes">Show _range</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_range1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_data1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show value of the option</property>
+		      <property name="label" translatable="yes">Show _data</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_data1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separator2">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_all_options1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show all options</property>
+		      <property name="label" translatable="yes">Show all _options</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_all_options1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkCheckMenuItem" id="show_debug_info1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show masked options</property>
+		      <property name="label" translatable="yes">Show _debug info</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">False</property>
+		      <signal name="activate" handler="on_show_debug_info1_activate"/>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="help1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Help</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="help1_menu">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="introduction1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Introduction</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+		      <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image43">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-dialog-question</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="about1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_About</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+		      <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image44">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-properties</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="license1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_License</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image45">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-justify-fill</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHandleBox" id="handlebox1">
+	  <property name="visible">True</property>
+	  <property name="shadow_type">GTK_SHADOW_OUT</property>
+	  <property name="handle_position">GTK_POS_LEFT</property>
+	  <property name="snap_edge">GTK_POS_TOP</property>
+
+	  <child>
+	    <widget class="GtkToolbar" id="toolbar1">
+	      <property name="visible">True</property>
+	      <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+	      <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+	      <property name="tooltips">True</property>
+	      <property name="show_arrow">True</property>
+
+	      <child>
+		<widget class="GtkToolButton" id="button1">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+		  <property name="label" translatable="yes">Back</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-undo</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_back_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem1">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button2">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Load a config file</property>
+		  <property name="label" translatable="yes">Load</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-open</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_load_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button3">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Save a config file</property>
+		  <property name="label" translatable="yes">Save</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-save</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_save_activate"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem2">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator2">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button4">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Single view</property>
+		  <property name="label" translatable="yes">Single</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button5">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Split view</property>
+		  <property name="label" translatable="yes">Split</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button6">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Full view</property>
+		  <property name="label" translatable="yes">Full</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolItem" id="toolitem3">
+		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator3">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button7">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+		  <property name="label" translatable="yes">Collapse</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-remove</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_collapse_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkToolButton" id="button8">
+		  <property name="visible">True</property>
+		  <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+		  <property name="label" translatable="yes">Expand</property>
+		  <property name="use_underline">True</property>
+		  <property name="stock_id">gtk-add</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_expand_clicked"/>
+		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHPaned" id="hpaned1">
+	  <property name="width_request">1</property>
+	  <property name="visible">True</property>
+	  <property name="can_focus">True</property>
+	  <property name="position">0</property>
+
+	  <child>
+	    <widget class="GtkScrolledWindow" id="scrolledwindow1">
+	      <property name="visible">True</property>
+	      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+	      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+	      <property name="shadow_type">GTK_SHADOW_IN</property>
+	      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+	      <child>
+		<widget class="GtkTreeView" id="treeview1">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="headers_visible">True</property>
+		  <property name="rules_hint">False</property>
+		  <property name="reorderable">False</property>
+		  <property name="enable_search">True</property>
+		  <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+		  <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+		  <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="shrink">True</property>
+	      <property name="resize">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkVPaned" id="vpaned1">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="position">0</property>
+
+	      <child>
+		<widget class="GtkScrolledWindow" id="scrolledwindow2">
+		  <property name="visible">True</property>
+		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="shadow_type">GTK_SHADOW_IN</property>
+		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		  <child>
+		    <widget class="GtkTreeView" id="treeview2">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="has_focus">True</property>
+		      <property name="headers_visible">True</property>
+		      <property name="rules_hint">False</property>
+		      <property name="reorderable">False</property>
+		      <property name="enable_search">True</property>
+		      <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+		      <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+		      <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="shrink">True</property>
+		  <property name="resize">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkScrolledWindow" id="scrolledwindow3">
+		  <property name="visible">True</property>
+		  <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="shadow_type">GTK_SHADOW_IN</property>
+		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		  <child>
+		    <widget class="GtkTextView" id="textview3">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">False</property>
+		      <property name="overwrite">False</property>
+		      <property name="accepts_tab">True</property>
+		      <property name="justification">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap_mode">GTK_WRAP_WORD</property>
+		      <property name="cursor_visible">True</property>
+		      <property name="pixels_above_lines">0</property>
+		      <property name="pixels_below_lines">0</property>
+		      <property name="pixels_inside_wrap">0</property>
+		      <property name="left_margin">0</property>
+		      <property name="right_margin">0</property>
+		      <property name="indent">0</property>
+		      <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="shrink">True</property>
+		  <property name="resize">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="shrink">True</property>
+	      <property name="resize">True</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>

Added: trunk/filo/util/kconfig/images.c
===================================================================
--- trunk/filo/util/kconfig/images.c	                        (rev 0)
+++ trunk/filo/util/kconfig/images.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .      . . ",
+" .     .. . ",
+" . .  ..  . ",
+" . ....   . ",
+" .  ..    . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" . ..     . ",
+" . ....   . ",
+" . ...... . ",
+" . ...... . ",
+" . ....   . ",
+" . ..     . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .......... ",
+" ..  ...... ",
+" ..    .... ",
+" ..      .. ",
+" ..      .. ",
+" ..    .... ",
+" ..  ...... ",
+" .......... ",
+" .......... ",
+"            "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .     .. . ",
+" .   .... . ",
+" . ...... . ",
+" . ...... . ",
+" .   .... . ",
+" .     .. . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            "};

Added: trunk/filo/util/kconfig/kconfig_load.c
===================================================================
--- trunk/filo/util/kconfig/kconfig_load.c	                        (rev 0)
+++ trunk/filo/util/kconfig/kconfig_load.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg)	type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+	void *handle;
+	char *error;
+
+	handle = dlopen("./libkconfig.so", RTLD_LAZY);
+	if (!handle) {
+		handle = dlopen("./util/kconfig/libkconfig.so", RTLD_LAZY);
+		if (!handle) {
+			fprintf(stderr, "%s\n", dlerror());
+			exit(1);
+		}
+	}
+
+#define P(name,type,arg)			\
+{						\
+	name ## _p = dlsym(handle, #name);	\
+        if ((error = dlerror()))  {		\
+                fprintf(stderr, "%s\n", error);	\
+		exit(1);			\
+	}					\
+}
+#include "lkc_proto.h"
+#undef P
+}

Added: trunk/filo/util/kconfig/kxgettext.c
===================================================================
--- trunk/filo/util/kconfig/kxgettext.c	                        (rev 0)
+++ trunk/filo/util/kconfig/kxgettext.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,229 @@
+/*
+ * Arnaldo Carvalho de Melo <acme at conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+	char *bfp = bf;
+	int multiline = strchr(text, '\n') != NULL;
+	int eol = 0;
+	int textlen = strlen(text);
+
+	if ((textlen > 0) && (text[textlen-1] == '\n'))
+		eol = 1;
+
+	*bfp++ = '"';
+	--len;
+
+	if (multiline) {
+		*bfp++ = '"';
+		*bfp++ = '\n';
+		*bfp++ = '"';
+		len -= 3;
+	}
+
+	while (*text != '\0' && len > 1) {
+		if (*text == '"')
+			*bfp++ = '\\';
+		else if (*text == '\n') {
+			*bfp++ = '\\';
+			*bfp++ = 'n';
+			*bfp++ = '"';
+			*bfp++ = '\n';
+			*bfp++ = '"';
+			len -= 5;
+			++text;
+			goto next;
+		}
+		*bfp++ = *text++;
+next:
+		--len;
+	}
+
+	if (multiline && eol)
+		bfp -= 3;
+
+	*bfp++ = '"';
+	*bfp = '\0';
+
+	return bf;
+}
+
+struct file_line {
+	struct file_line *next;
+	char*		 file;
+	int		 lineno;
+};
+
+static struct file_line *file_line__new(char *file, int lineno)
+{
+	struct file_line *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->file   = file;
+	self->lineno = lineno;
+	self->next   = NULL;
+out:
+	return self;
+}
+
+struct message {
+	const char	 *msg;
+	const char	 *option;
+	struct message	 *next;
+	struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+{
+	struct message *self = malloc(sizeof(*self));
+
+	if (self == NULL)
+		goto out;
+
+	self->files = file_line__new(file, lineno);
+	if (self->files == NULL)
+		goto out_fail;
+
+	self->msg = strdup(msg);
+	if (self->msg == NULL)
+		goto out_fail_msg;
+
+	self->option = option;
+	self->next = NULL;
+out:
+	return self;
+out_fail_msg:
+	free(self->files);
+out_fail:
+	free(self);
+	self = NULL;
+	goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		if (strcmp(m->msg, msg) == 0)
+			break;
+		m = m->next;
+	}
+
+	return m;
+}
+
+static int message__add_file_line(struct message *self, char *file, int lineno)
+{
+	int rc = -1;
+	struct file_line *fl = file_line__new(file, lineno);
+
+	if (fl == NULL)
+		goto out;
+
+	fl->next    = self->files;
+	self->files = fl;
+	rc = 0;
+out:
+	return rc;
+}
+
+static int message__add(const char *msg, char *option, char *file, int lineno)
+{
+	int rc = 0;
+	char bf[16384];
+	char *escaped = escape(msg, bf, sizeof(bf));
+	struct message *m = mesage__find(escaped);
+
+	if (m != NULL)
+		rc = message__add_file_line(m, file, lineno);
+	else {
+		m = message__new(escaped, option, file, lineno);
+
+		if (m != NULL) {
+			m->next	      = message__list;
+			message__list = m;
+		} else
+			rc = -1;
+	}
+	return rc;
+}
+
+void menu_build_message_list(struct menu *menu)
+{
+	struct menu *child;
+
+	message__add(menu_get_prompt(menu), NULL,
+		     menu->file == NULL ? "Root Menu" : menu->file->name,
+		     menu->lineno);
+
+	if (menu->sym != NULL && menu_has_help(menu))
+		message__add(menu_get_help(menu), menu->sym->name,
+			     menu->file == NULL ? "Root Menu" : menu->file->name,
+			     menu->lineno);
+
+	for (child = menu->list; child != NULL; child = child->next)
+		if (child->prompt != NULL)
+			menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+	struct file_line *fl = self->files;
+
+	putchar('\n');
+	if (self->option != NULL)
+		printf("# %s:00000\n", self->option);
+
+	printf("#: %s:%d", fl->file, fl->lineno);
+	fl = fl->next;
+
+	while (fl != NULL) {
+		printf(", %s:%d", fl->file, fl->lineno);
+		fl = fl->next;
+	}
+
+	putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+	message__print_file_lineno(self);
+
+	printf("msgid %s\n"
+	       "msgstr \"\"\n", self->msg);
+}
+
+void menu__xgettext(void)
+{
+	struct message *m = message__list;
+
+	while (m != NULL) {
+		/* skip empty lines ("") */
+		if (strlen(m->msg) > sizeof("\"\""))
+			message__print_gettext_msgid_msgstr(m);
+		m = m->next;
+	}
+}
+
+int main(int ac, char **av)
+{
+	conf_parse(av[1]);
+
+	menu_build_message_list(menu_get_root_menu(NULL));
+	menu__xgettext();
+	return 0;
+}

Added: trunk/filo/util/kconfig/lex.zconf.c_shipped
===================================================================
--- trunk/filo/util/kconfig/lex.zconf.c_shipped	                        (rev 0)
+++ trunk/filo/util/kconfig/lex.zconf.c_shipped	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,2374 @@
+
+#line 3 "util/kconfig/lex.zconf.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via zconfrestart()), so that the user can continue scanning by
+	 * just pointing zconfin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	zconfleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+	text = malloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+	text = malloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	errno=0; \
+	while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+	{ \
+		if( errno != EINTR) \
+		{ \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+			break; \
+		} \
+		errno=0; \
+		clearerr(zconfin); \
+	}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+	int str = 0;
+	int ts, i;
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! zconfin )
+			zconfin = stdin;
+
+		if ( ! zconfout )
+			zconfout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			zconfensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				zconf_create_buffer(zconfin,YY_BUF_SIZE );
+		}
+
+		zconf_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of zconftext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+			++yy_cp;
+
+		yy_current_state = -yy_current_state;
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+	current_file->lineno++;
+	return T_EOL;
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+	unput(zconftext[0]);
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+	YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+		str = zconftext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+	YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+	YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+	}
+	YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+	}
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+		if (str == zconftext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(zconftext, 1);
+	}
+	YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+		ts = 0;
+		for (i = 0; i < zconfleng; i++) {
+			if (zconftext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+		while (zconfleng) {
+			if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+				break;
+			zconfleng--;
+		}
+		append_string(zconftext, zconfleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(zconfin);
+	yyterminate();
+}
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+	YY_BREAK
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed zconfin at a new source and called
+			 * zconflex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( zconfwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * zconftext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			zconfrestart(zconfin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	yy_current_state = yy_nxt[yy_current_state][1];
+	yy_is_jam = (yy_current_state <= 0);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up zconftext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					zconfrestart(zconfin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( zconfwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve zconftext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+	}
+
+	zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+	zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		zconfpop_buffer_state();
+	 *		zconfpush_buffer_state(new_buffer);
+     */
+	zconfensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	zconf_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (zconfwrap()) processing, but the only time this flag
+	 * is looked at is after zconfwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	zconf_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		zconffree((void *) b->yy_ch_buf  );
+
+	zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	zconf_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	zconfensure_buffer_stack();
+
+	/* This block is copied from zconf_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from zconf_switch_to_buffer. */
+	zconf_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	zconf_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		zconf_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	zconf_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+    
+	return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) zconfalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = zconf_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		zconftext[zconfleng] = (yy_hold_char); \
+		(yy_c_buf_p) = zconftext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		zconfleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		zconf_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		zconfpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	zconffree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+	free( (char *) ptr );	/* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = malloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+	current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+	struct file *file = file_lookup(name);
+	struct buffer *buf = malloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+		exit(1);
+	}
+	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	if (file->flags & FILE_BUSY) {
+		printf("recursive scan (%s)?\n", name);
+		exit(1);
+	}
+	if (file->flags & FILE_SCANNED) {
+		printf("file %s already scanned?\n", name);
+		exit(1);
+	}
+	file->flags |= FILE_BUSY;
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file->flags |= FILE_SCANNED;
+	current_file->flags &= ~FILE_BUSY;
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(zconfin);
+		zconf_delete_buffer(YY_CURRENT_BUFFER);
+		zconf_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
+

Added: trunk/filo/util/kconfig/lkc.h
===================================================================
--- trunk/filo/util/kconfig/lkc.h	                        (rev 0)
+++ trunk/filo/util/kconfig/lkc.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)	extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)	extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#define PACKAGE "FILO"
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+
+#define TF_COMMAND	0x0001
+#define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
+#define T_OPT_ENV		3
+
+struct kconf_id {
+	int name;
+	int token;
+	unsigned int flags;
+	enum symbol_type stype;
+};
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+
+extern int zconfdebug;
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+char *zconf_curname(void);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+	size_t len;
+	char  *s;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+	return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+	return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+	return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */

Added: trunk/filo/util/kconfig/lkc_proto.h
===================================================================
--- trunk/filo/util/kconfig/lkc_proto.h	                        (rev 0)
+++ trunk/filo/util/kconfig/lkc_proto.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,45 @@
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible,bool,(struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));

Added: trunk/filo/util/kconfig/lxdialog/BIG.FAT.WARNING
===================================================================
--- trunk/filo/util/kconfig/lxdialog/BIG.FAT.WARNING	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/BIG.FAT.WARNING	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog.  This version has been
+significantly modified from the original.  It is for use by the Linux
+kernel configuration script.  Please do not bother Savio Lam with 
+questions about this program.

Added: trunk/filo/util/kconfig/lxdialog/check-lxdialog.sh
===================================================================
--- trunk/filo/util/kconfig/lxdialog/check-lxdialog.sh	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/check-lxdialog.sh	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+	for ext in so a dylib ; do
+		for lib in ncursesw ncurses curses ; do
+			$cc -print-file-name=lib${lib}.${ext} | grep -q /
+			if [ $? -eq 0 ]; then
+				echo "-l${lib}"
+				exit
+			fi
+		done
+	done
+	exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+	if [ -f /usr/include/ncurses/ncurses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+	elif [ -f /usr/include/ncurses/curses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+	elif [ -f /usr/include/ncurses.h ]; then
+		echo '-DCURSES_LOC="<ncurses.h>"'
+	else
+		echo '-DCURSES_LOC="<curses.h>"'
+	fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+	echo -e " #include CURSES_LOC \n main() {}" |
+	    $cc -xc - -o $tmp 2> /dev/null
+	if [ $? != 0 ]; then
+	    echo " *** Unable to find the ncurses libraries or the"       1>&2
+	    echo " *** required header files."                            1>&2
+	    echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+	    echo " *** "                                                  1>&2
+	    echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+	    echo " *** "                                                  1>&2
+	    exit 1
+	fi
+}
+
+usage() {
+	printf "Usage: $0 [-check compiler options|-header|-library]\n"
+}
+
+if [ $# -eq 0 ]; then
+	usage
+	exit 1
+fi
+
+cc=""
+case "$1" in
+	"-check")
+		shift
+		cc="$@"
+		check
+		;;
+	"-ccflags")
+		ccflags
+		;;
+	"-ldflags")
+		shift
+		cc="$@"
+		ldflags
+		;;
+	"*")
+		usage
+		exit 1
+		;;
+esac

Added: trunk/filo/util/kconfig/lxdialog/checklist.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/checklist.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/checklist.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,325 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert at sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini at ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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 "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, item_str()[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, (char *)item_str() + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("Select"), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
+	}
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 6))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 6))
+		return -ERRDISPLAYTOOSMALL;
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+	              x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+	         dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+
+	check_x = (list_width - check_x) / 2;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+		case '?':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

Added: trunk/filo/util/kconfig/lxdialog/dialog.h
===================================================================
--- trunk/filo/util/kconfig/lxdialog/dialog.h	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/dialog.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,230 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *
+ *  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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)		/*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* promtp displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+	      chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+		  int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+		    int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)

Added: trunk/filo/util/kconfig/lxdialog/inputbox.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/inputbox.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/inputbox.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,238 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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 "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+                    const char *init)
+{
+	int i, x, y, box_y, box_x, box_width;
+	int input_x = 0, scroll = 0, key = 0, button = -1;
+	char *instr = dialog_input_result;
+	WINDOW *dialog;
+
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - 2))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - 2))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	/* Draw the input field box */
+	box_width = width - 6;
+	getyx(dialog, y, x);
+	box_y = y + 2;
+	box_x = (width - box_width) / 2;
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.border.atr, dlg.dialog.atr);
+
+	print_buttons(dialog, height, width, 0);
+
+	/* Set up the initial value */
+	wmove(dialog, box_y, box_x);
+	wattrset(dialog, dlg.inputbox.atr);
+
+	input_x = strlen(instr);
+
+	if (input_x >= box_width) {
+		scroll = input_x - box_width + 1;
+		input_x = box_width - 1;
+		for (i = 0; i < box_width - 1; i++)
+			waddch(dialog, instr[scroll + i]);
+	} else {
+		waddstr(dialog, instr);
+	}
+
+	wmove(dialog, box_y, box_x + input_x);
+
+	wrefresh(dialog);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		if (button == -1) {	/* Input box selected */
+			switch (key) {
+			case TAB:
+			case KEY_UP:
+			case KEY_DOWN:
+				break;
+			case KEY_LEFT:
+				continue;
+			case KEY_RIGHT:
+				continue;
+			case KEY_BACKSPACE:
+			case 127:
+				if (input_x || scroll) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (!input_x) {
+						scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++)
+							waddch(dialog,
+							       instr[scroll + input_x + i] ?
+							       instr[scroll + input_x + i] : ' ');
+						input_x = strlen(instr) - scroll;
+					} else
+						input_x--;
+					instr[scroll + input_x] = '\0';
+					mvwaddch(dialog, box_y, input_x + box_x, ' ');
+					wmove(dialog, box_y, input_x + box_x);
+					wrefresh(dialog);
+				}
+				continue;
+			default:
+				if (key < 0x100 && isprint(key)) {
+					if (scroll + input_x < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						instr[scroll + input_x] = key;
+						instr[scroll + input_x + 1] = '\0';
+						if (input_x == box_width - 1) {
+							scroll++;
+							wmove(dialog, box_y, box_x);
+							for (i = 0; i < box_width - 1; i++)
+								waddch(dialog, instr [scroll + i]);
+						} else {
+							wmove(dialog, box_y, input_x++ + box_x);
+							waddch(dialog, key);
+						}
+						wrefresh(dialog);
+					} else
+						flash();	/* Alarm user about overflow */
+					continue;
+				}
+			}
+		}
+		switch (key) {
+		case 'O':
+		case 'o':
+			delwin(dialog);
+			return 0;
+		case 'H':
+		case 'h':
+			delwin(dialog);
+			return 1;
+		case KEY_UP:
+		case KEY_LEFT:
+			switch (button) {
+			case -1:
+				button = 1;	/* Indicates "Cancel" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 0:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			case 1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			}
+			break;
+		case TAB:
+		case KEY_DOWN:
+		case KEY_RIGHT:
+			switch (button) {
+			case -1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			case 0:
+				button = 1;	/* Indicates "Cancel" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 1:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			}
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return (button == -1 ? 0 : button);
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return KEY_ESC;		/* ESC pressed */
+}

Added: trunk/filo/util/kconfig/lxdialog/menubox.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/menubox.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/menubox.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,434 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw at cfw.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.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god at clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec at shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+                          int selected, int hotkey)
+{
+	int j;
+	char *menu_item = malloc(menu_width + 1);
+
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
+	j = first_alpha(menu_item, "YyNnMmHh");
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < menu_width; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
+	if (hotkey) {
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
+	}
+	if (selected) {
+		wmove(win, line_y, item_x + 1);
+	}
+	free(menu_item);
+	wrefresh(win);
+}
+
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+			 int height)
+{
+	int cur_y, cur_x;
+
+	getyx(win, cur_y, cur_x);
+
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+	wrefresh(win);
+
+	if ((height < item_no) && (scroll + height < item_no)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	wmove(win, cur_y, cur_x);
+	wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+	int x = width / 2 - 16;
+	int y = height - 2;
+
+	print_button(win, gettext("Select"), y, x, selected == 0);
+	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+
+	wmove(win, y, x + 1 + 12 * selected);
+	wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+	/* Scroll menu up */
+	scrollok(win, TRUE);
+	wscrl(win, n);
+	scrollok(win, FALSE);
+	*scroll = *scroll + n;
+	wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
+{
+	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
+	int key = 0, button = 0, scroll = 0, choice = 0;
+	int first_item =  0, max_choice;
+	WINDOW *dialog, *menu;
+
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < 15 || width < 65)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
+	max_choice = MIN(menu_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	menu_width = width - 6;
+	box_y = height - menu_height - 5;
+	box_x = (width - menu_width) / 2 - 1;
+
+	/* create new window for the menu */
+	menu = subwin(dialog, menu_height, menu_width,
+		      y + box_y + 1, x + box_x + 1);
+	keypad(menu, TRUE);
+
+	/* draw a box around the menu items */
+	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
+
+	/* Set choice to default item */
+	item_foreach()
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
+	}
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
+		else
+			scroll = first_item = choice - max_choice / 2;
+		choice = choice - scroll;
+	}
+
+	/* Print the menu */
+	for (i = 0; i < max_choice; i++) {
+		print_item(first_item + i, i, i == choice);
+	}
+
+	wnoutrefresh(menu);
+
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
+
+	print_buttons(dialog, height, width, 0);
+	wmove(menu, choice, item_x + 1);
+	wrefresh(menu);
+
+	while (key != KEY_ESC) {
+		key = wgetch(menu);
+
+		if (key < 256 && isalpha(key))
+			key = tolower(key);
+
+		if (strchr("ynmh", key))
+			i = max_choice;
+		else {
+			for (i = choice + 1; i < max_choice; i++) {
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
+					break;
+			}
+			if (i == max_choice)
+				for (i = 0; i < max_choice; i++) {
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
+						break;
+				}
+		}
+
+		if (i < max_choice ||
+		    key == KEY_UP || key == KEY_DOWN ||
+		    key == '-' || key == '+' ||
+		    key == KEY_PPAGE || key == KEY_NPAGE) {
+			/* Remove highligt of current item */
+			print_item(scroll + choice, choice, FALSE);
+
+			if (key == KEY_UP || key == '-') {
+				if (choice < 2 && scroll) {
+					/* Scroll menu down */
+					do_scroll(menu, &scroll, -1);
+
+					print_item(scroll, 0, FALSE);
+				} else
+					choice = MAX(choice - 1, 0);
+
+			} else if (key == KEY_DOWN || key == '+') {
+				print_item(scroll+choice, choice, FALSE);
+
+				if ((choice > max_choice - 3) &&
+				    (scroll + max_choice < item_count())) {
+					/* Scroll menu up */
+					do_scroll(menu, &scroll, 1);
+
+					print_item(scroll+max_choice - 1,
+						   max_choice - 1, FALSE);
+				} else
+					choice = MIN(choice + 1, max_choice - 1);
+
+			} else if (key == KEY_PPAGE) {
+				scrollok(menu, TRUE);
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll > 0) {
+						do_scroll(menu, &scroll, -1);
+						print_item(scroll, 0, FALSE);
+					} else {
+						if (choice > 0)
+							choice--;
+					}
+				}
+
+			} else if (key == KEY_NPAGE) {
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll + max_choice < item_count()) {
+						do_scroll(menu, &scroll, 1);
+						print_item(scroll+max_choice-1,
+							   max_choice - 1, FALSE);
+					} else {
+						if (choice + 1 < max_choice)
+							choice++;
+					}
+				}
+			} else
+				choice = i;
+
+			print_item(scroll + choice, choice, TRUE);
+
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
+
+			wnoutrefresh(dialog);
+			wrefresh(menu);
+
+			continue;	/* wait for another key press */
+		}
+
+		switch (key) {
+		case KEY_LEFT:
+		case TAB:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 2 : (button > 2 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(menu);
+			break;
+		case ' ':
+		case 's':
+		case 'y':
+		case 'n':
+		case 'm':
+		case '/':
+			/* save scroll info */
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			switch (key) {
+			case 's':
+				return 3;
+			case 'y':
+				return 3;
+			case 'n':
+				return 4;
+			case 'm':
+				return 5;
+			case ' ':
+				return 6;
+			case '/':
+				return 7;
+			}
+			return 0;
+		case 'h':
+		case '?':
+			button = 2;
+		case '\n':
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			return button;
+		case 'e':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
+			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
+		}
+	}
+	delwin(menu);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

Added: trunk/filo/util/kconfig/lxdialog/textbox.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/textbox.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/textbox.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,391 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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 "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+							  int cur_y, int cur_x)
+{
+	print_page(box, boxh, boxw);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+		   int initial_height, int initial_width)
+{
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	int passed_end;
+	WINDOW *dialog, *box;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < 8 || width < 8)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+	keypad(box, TRUE);
+
+	/* register the new window, along with its borders */
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+	wnoutrefresh(dialog);
+	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
+
+	/* Print first page of text */
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+	while ((key != KEY_ESC) && (key != '\n')) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'E':	/* Exit */
+		case 'e':
+		case 'X':
+		case 'x':
+			delwin(box);
+			delwin(dialog);
+			return 0;
+		case 'g':	/* First page */
+		case KEY_HOME:
+			if (!begin_reached) {
+				begin_reached = 1;
+				page = buf;
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x);
+			}
+			break;
+		case 'G':	/* Last page */
+		case KEY_END:
+
+			end_reached = 1;
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'K':	/* Previous line */
+		case 'k':
+		case KEY_UP:
+			if (!begin_reached) {
+				back_lines(page_length + 1);
+
+				/* We don't call print_page() here but use
+				 * scrolling to ensure faster screen update.
+				 * However, 'end_reached' and 'page_length'
+				 * should still be updated, and 'page' should
+				 * point to start of next page. This is done
+				 * by calling get_line() in the following
+				 * 'for' loop. */
+				scrollok(box, TRUE);
+				wscrl(box, -1);	/* Scroll box region down one line */
+				scrollok(box, FALSE);
+				page_length = 0;
+				passed_end = 0;
+				for (i = 0; i < boxh; i++) {
+					if (!i) {
+						/* print first line of page */
+						print_line(box, 0, boxw);
+						wnoutrefresh(box);
+					} else
+						/* Called to update 'end_reached' and 'page' */
+						get_line();
+					if (!passed_end)
+						page_length++;
+					if (end_reached && !passed_end)
+						passed_end = 1;
+				}
+
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case 'B':	/* Previous page */
+		case 'b':
+		case KEY_PPAGE:
+			if (begin_reached)
+				break;
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'J':	/* Next line */
+		case 'j':
+		case KEY_DOWN:
+			if (!end_reached) {
+				begin_reached = 0;
+				scrollok(box, TRUE);
+				scroll(box);	/* Scroll box region up one line */
+				scrollok(box, FALSE);
+				print_line(box, boxh - 1, boxw);
+				wnoutrefresh(box);
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case KEY_NPAGE:	/* Next page */
+		case ' ':
+			if (end_reached)
+				break;
+
+			begin_reached = 0;
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case '0':	/* Beginning of line */
+		case 'H':	/* Scroll left */
+		case 'h':
+		case KEY_LEFT:
+			if (hscroll <= 0)
+				break;
+
+			if (key == '0')
+				hscroll = 0;
+			else
+				hscroll--;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'L':	/* Scroll right */
+		case 'l':
+		case KEY_RIGHT:
+			if (hscroll >= MAX_LEN)
+				break;
+			hscroll++;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+	delwin(box);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+	int i;
+
+	begin_reached = 0;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
+			}
+		}
+		if (page == buf) {
+			begin_reached = 1;
+			return;
+		}
+		page--;
+		do {
+			if (page == buf) {
+				begin_reached = 1;
+				return;
+			}
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+	int i, passed_end = 0;
+
+	page_length = 0;
+	for (i = 0; i < height; i++) {
+		print_line(win, i, width);
+		if (!passed_end)
+			page_length++;
+		if (end_reached && !passed_end)
+			passed_end = 1;
+	}
+	wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+	int y, x;
+	char *line;
+
+	line = get_line();
+	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
+	wmove(win, row, 0);	/* move cursor to correct line */
+	waddch(win, ' ');
+	waddnstr(win, line, MIN(strlen(line), width - 2));
+
+	getyx(win, y, x);
+	/* Clear 'residue' of previous line */
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < width - x; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+	int i = 0;
+	static char line[MAX_LEN + 1];
+
+	end_reached = 0;
+	while (*page != '\n') {
+		if (*page == '\0') {
+			if (!end_reached) {
+				end_reached = 1;
+				break;
+			}
+		} else if (i < MAX_LEN)
+			line[i++] = *(page++);
+		else {
+			/* Truncate lines longer than MAX_LEN characters */
+			if (i == MAX_LEN)
+				line[i++] = '\0';
+			page++;
+		}
+	}
+	if (i <= MAX_LEN)
+		line[i] = '\0';
+	if (!end_reached)
+		page++;		/* move pass '\n' */
+
+	return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+	int percent;
+
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+	wprintw(win, "(%3d%%)", percent);
+}

Added: trunk/filo/util/kconfig/lxdialog/util.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/util.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/util.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,655 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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 "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 0;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+	int use_color;
+
+	use_color = set_theme(theme);
+	if (use_color && has_colors()) {
+		start_color();
+		init_dialog_colors();
+	} else
+		set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+	int i, j;
+
+	wattrset(win, attr);
+	for (i = 0; i < height; i++) {
+		wmove(win, i, 0);
+		for (j = 0; j < width; j++)
+			waddch(win, ' ');
+	}
+	touchwin(win);
+}
+
+void dialog_clear(void)
+{
+	attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+	/* Display background title if it exists ... - SLH */
+	if (dlg.backtitle != NULL) {
+		int i;
+
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+		wmove(stdscr, 1, 1);
+		for (i = 1; i < COLS - 1; i++)
+			waddch(stdscr, ACS_HLINE);
+	}
+	wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+	int height, width;
+
+	initscr();		/* Init curses */
+	getmaxyx(stdscr, height, width);
+	if (height < 19 || width < 80) {
+		endwin();
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	dlg.backtitle = backtitle;
+	color_setup(getenv("MENUCONFIG_COLOR"));
+
+	keypad(stdscr, TRUE);
+	cbreak();
+	noecho();
+	dialog_clear();
+
+	return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+	/* move cursor back to original position */
+	move(y, x);
+	refresh();
+	endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+	if (title) {
+		int tlen = MIN(width - 2, strlen(title));
+		wattrset(dialog, dlg.title.atr);
+		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+		waddch(dialog, ' ');
+	}
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+	int newl, cur_x, cur_y;
+	int i, prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+	strcpy(tempstr, prompt);
+
+	prompt_len = strlen(tempstr);
+
+	/*
+	 * Remove newlines
+	 */
+	for (i = 0; i < prompt_len; i++) {
+		if (tempstr[i] == '\n')
+			tempstr[i] = ' ';
+	}
+
+	if (prompt_len <= width - x * 2) {	/* If prompt is short */
+		wmove(win, y, (width - prompt_len) / 2);
+		waddstr(win, tempstr);
+	} else {
+		cur_x = x;
+		cur_y = y;
+		newl = 1;
+		word = tempstr;
+		while (word && *word) {
+			sp = strchr(word, ' ');
+			if (sp)
+				*sp++ = 0;
+
+			/* Wrap to next line if either the word does not fit,
+			   or it is the first word of a new sentence, and it is
+			   short, and the next word does not fit. */
+			room = width - cur_x;
+			wlen = strlen(word);
+			if (wlen > room ||
+			    (newl && wlen < 4 && sp
+			     && wlen + 1 + strlen(sp) > room
+			     && (!(sp2 = strchr(sp, ' '))
+				 || wlen + 1 + (sp2 - sp) > room))) {
+				cur_y++;
+				cur_x = x;
+			}
+			wmove(win, cur_y, cur_x);
+			waddstr(win, word);
+			getyx(win, cur_y, cur_x);
+			cur_x++;
+			if (sp && *sp == ' ') {
+				cur_x++;	/* double space */
+				while (*++sp == ' ') ;
+				newl = 1;
+			} else
+				newl = 0;
+			word = sp;
+		}
+	}
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+	int i, temp;
+
+	wmove(win, y, x);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, "<");
+	temp = strspn(label, " ");
+	label += temp;
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	for (i = 0; i < temp; i++)
+		waddch(win, ' ');
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
+	waddch(win, label[0]);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	waddstr(win, (char *)label + 1);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, ">");
+	wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+	 chtype box, chtype border)
+{
+	int i, j;
+
+	wattrset(win, 0);
+	for (i = 0; i < height; i++) {
+		wmove(win, y + i, x);
+		for (j = 0; j < width; j++)
+			if (!i && !j)
+				waddch(win, border | ACS_ULCORNER);
+			else if (i == height - 1 && !j)
+				waddch(win, border | ACS_LLCORNER);
+			else if (!i && j == width - 1)
+				waddch(win, box | ACS_URCORNER);
+			else if (i == height - 1 && j == width - 1)
+				waddch(win, box | ACS_LRCORNER);
+			else if (!i)
+				waddch(win, border | ACS_HLINE);
+			else if (i == height - 1)
+				waddch(win, box | ACS_HLINE);
+			else if (!j)
+				waddch(win, border | ACS_VLINE);
+			else if (j == width - 1)
+				waddch(win, box | ACS_VLINE);
+			else
+				waddch(win, box | ' ');
+	}
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+	int i;
+
+	if (has_colors()) {	/* Whether terminal supports color? */
+		wattrset(win, dlg.shadow.atr);
+		wmove(win, y + height, x + 2);
+		for (i = 0; i < width; i++)
+			waddch(win, winch(win) & A_CHARTEXT);
+		for (i = y + 1; i < y + height + 1; i++) {
+			wmove(win, i, x + width);
+			waddch(win, winch(win) & A_CHARTEXT);
+			waddch(win, winch(win) & A_CHARTEXT);
+		}
+		wnoutrefresh(win);
+	}
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+	int i, in_paren = 0, c;
+
+	for (i = 0; i < strlen(string); i++) {
+		c = tolower(string[i]);
+
+		if (strchr("<[(", c))
+			++in_paren;
+		if (strchr(">])", c) && in_paren > 0)
+			--in_paren;
+
+		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+        size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}

Added: trunk/filo/util/kconfig/lxdialog/yesno.c
===================================================================
--- trunk/filo/util/kconfig/lxdialog/yesno.c	                        (rev 0)
+++ trunk/filo/util/kconfig/lxdialog/yesno.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,114 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836 at cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap at cfw.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 "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 10;
+	int y = height - 2;
+
+	print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+	print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
+
+	wmove(dialog, y, x + 1 + 13 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+	int i, x, y, key = 0, button = 0;
+	WINDOW *dialog;
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 4))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 4))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	print_buttons(dialog, height, width, 0);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'Y':
+		case 'y':
+			delwin(dialog);
+			return 0;
+		case 'N':
+		case 'n':
+			delwin(dialog);
+			return 1;
+
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return button;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

Added: trunk/filo/util/kconfig/mconf.c
===================================================================
--- trunk/filo/util/kconfig/mconf.c	                        (rev 0)
+++ trunk/filo/util/kconfig/mconf.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky at ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme at conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some features may be built directly into FILO.\n"
+"Some may be made into loadable runtime modules.  Some features\n"
+"may be completely removed altogether.  There are also certain\n"
+"parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+"  [ ] can be built in or removed\n"
+"  < > can be built in, modularized or removed\n"
+"  { } can be built in or modularized (selected by other feature)\n"
+"  - - are selected by other feature,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit> and <Help>\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
+"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono       => selects colors suitable for monochrome displays\n"
+" blackbg    => selects a color scheme with black background\n"
+" classic    => theme with blue background. The classic look\n"
+" bluetitle  => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+	"Arrow keys navigate the menu.  "
+	"<Enter> selects submenus --->.  "
+	"Highlighted letters are hotkeys.  "
+	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+	"Use the arrow keys to navigate this window or "
+	"press the hotkey of the item you wish to select "
+	"followed by the <SPACE BAR>. "
+	"Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+	"Please enter a decimal value. "
+	"Fractions will not be accepted.  "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+	"Please enter a hexadecimal value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+	"Please enter a string value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+	"This feature depends on another which has been configured as a module.\n"
+	"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+	"There is no help available for this option.\n"),
+load_config_text[] = N_(
+	"Enter the name of the configuration file you wish to load.  "
+	"Accept the name shown to restore the configuration you "
+	"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep several different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"If you have saved a previous configuration in a file other than the\n"
+	"default, entering the name of the file here will allow you\n"
+	"to modify that configuration.\n"
+	"\n"
+	"If you are uncertain, then you have probably never used alternate\n"
+	"configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+	"Enter a filename to which this configuration should be saved "
+	"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"Entering a file name here will allow you to later retrieve, modify\n"
+	"and use the current configuration as an alternate to whatever\n"
+	"configuration options you have selected at that time.\n"
+	"\n"
+	"If you are uncertain what all this means then you should probably\n"
+	"leave this blank.\n"),
+search_help[] = N_(
+	"\n"
+	"Search for CONFIG_ symbols and display their relations.\n"
+	"Regular expressions are allowed.\n"
+	"Example: search for \"^FOO\"\n"
+	"Result:\n"
+	"-----------------------------------------------------------------\n"
+	"Symbol: FOO [=m]\n"
+	"Prompt: Foo bus is used to drive the bar HW\n"
+	"Defined at drivers/pci/Kconfig:47\n"
+	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+	"Location:\n"
+	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+	"    -> PCI support (PCI [=y])\n"
+	"      -> PCI access mode (<choice> [=y])\n"
+	"Selects: LIBCRC32\n"
+	"Selected by: BAR\n"
+	"-----------------------------------------------------------------\n"
+	"o The line 'Prompt:' shows the text used in the menu structure for\n"
+	"  this CONFIG_ symbol\n"
+	"o The 'Defined at' line tell at what file / line number the symbol\n"
+	"  is defined\n"
+	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+	"  this symbol to be visible in the menu (selectable)\n"
+	"o The 'Location:' lines tell where in the menu structure this symbol\n"
+	"  is located\n"
+	"    A location followed by a [=y] indicate that this is a selectable\n"
+	"    menu item - and current value is displayed inside brackets.\n"
+	"o The 'Selects:' line tell what symbol will be automatically\n"
+	"  selected if this symbol is selected (y or m)\n"
+	"o The 'Selected by' line tell what symbol has selected this symbol\n"
+	"\n"
+	"Only relevant lines are shown.\n"
+	"\n\n"
+	"Search examples:\n"
+	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
+	"          ^USB => find all CONFIG_ symbols starting with USB\n"
+	"          USB$ => find all CONFIG_ symbols ending with USB\n"
+	"\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+	int i, j;
+	struct menu *submenu[8], *menu;
+
+	str_printf(r, _("Prompt: %s\n"), _(prop->text));
+	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+		prop->menu->lineno);
+	if (!expr_is_yes(prop->visible.expr)) {
+		str_append(r, _("  Depends on: "));
+		expr_gstr_print(prop->visible.expr, r);
+		str_append(r, "\n");
+	}
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+		submenu[i++] = menu;
+	if (i > 0) {
+		str_printf(r, _("  Location:\n"));
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : _("<choice>"),
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+static void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+	bool hit;
+	struct property *prop;
+
+	if (sym && sym->name)
+		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+		                                    sym_get_string_value(sym));
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop);
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, _("  Selected by: "));
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+static struct gstr get_relations_str(struct symbol **sym_arr)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym);
+	if (!i)
+		str_append(&res, _("No matches found.\n"));
+	return res;
+}
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+	static char menu_backtitle[PATH_MAX+128];
+	int size;
+	struct symbol *sym;
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+	                _("%s - FILO v%s Configuration"),
+		        config_filename, getenv("KERNELVERSION"));
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+	set_dialog_backtitle(menu_backtitle);
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+}
+
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	char *dialog_input;
+	int dres;
+again:
+	dialog_clear();
+	dres = dialog_inputbox(_("Search Configuration Parameter"),
+			      _("Enter CONFIG_ (sub)string to search for "
+				"(with or without \"CONFIG\")"),
+			      10, 75, "");
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_helptext(_("Search Configuration"), search_help);
+		goto again;
+	default:
+		return;
+	}
+
+	/* strip CONFIG_ if necessary */
+	dialog_input = dialog_input_result;
+	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
+		dialog_input += 7;
+
+	sym_arr = sym_re_search(dialog_input);
+	res = get_relations_str(sym_arr);
+	free(sym_arr);
+	show_textbox(_("Search Results"), str_get(&res), 0, 0);
+	str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	int type, tmp, doint = 2;
+	tristate val;
+	char ch;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (!sym) {
+		if (prop && menu != current_menu) {
+			const char *prompt = menu_get_prompt(menu);
+			switch (prop->type) {
+			case P_MENU:
+				child_count++;
+				prompt = _(prompt);
+				if (single_menu_mode) {
+					item_make("%s%*c%s",
+						  menu->data ? "-->" : "++>",
+						  indent + 1, ' ', prompt);
+				} else
+					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
+
+				item_set_tag('m');
+				item_set_data(menu);
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			case P_COMMENT:
+				if (prompt) {
+					child_count++;
+					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+				break;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make("---%*c%s", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+			}
+		} else
+			doint = 0;
+		goto conf_childs;
+	}
+
+	type = sym_get_type(sym);
+	if (sym_is_choice(sym)) {
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		child_count++;
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child) && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		val = sym_get_tristate_value(sym);
+		if (sym_is_changable(sym)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make("[%c]", val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				item_make("<%c>", ch);
+				break;
+			}
+			item_set_tag('t');
+			item_set_data(menu);
+		} else {
+			item_make("   ");
+			item_set_tag(def_menu ? 't' : ':');
+			item_set_data(menu);
+		}
+
+		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+			item_set_tag(':');
+			item_set_data(menu);
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make("   ");
+			item_set_tag(':');
+			item_set_data(menu);
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make("[%c]", val == no ? ' ' : '*');
+				else
+					item_make("-%c-", val == no ? ' ' : '*');
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				if (sym_is_changable(sym)) {
+					if (sym->rev_dep.tri == mod)
+						item_make("{%c}", ch);
+					else
+						item_make("<%c>", ch);
+				} else
+					item_make("-%c-", ch);
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+				item_make("(%s)", sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
+					     "" : _(" (NEW)"));
+				item_set_tag('s');
+				item_set_data(menu);
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
+			  "" : _(" (NEW)"));
+		if (menu->prompt->type == P_MENU) {
+			item_add_str("  --->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+	struct menu *submenu;
+	const char *prompt = menu_get_prompt(menu);
+	struct symbol *sym;
+	struct menu *active_menu = NULL;
+	int res;
+	int s_scroll = 0;
+
+	while (1) {
+		item_reset();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+		if (menu == &rootmenu) {
+			item_make("--- ");
+			item_set_tag(':');
+			item_make(_("    Load an Alternate Configuration File"));
+			item_set_tag('L');
+			item_make(_("    Save an Alternate Configuration File"));
+			item_set_tag('S');
+		}
+		dialog_clear();
+		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+				  _(menu_instructions),
+				  active_menu, &s_scroll);
+		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+			break;
+		if (!item_activate_selected())
+			continue;
+		if (!item_tag())
+			continue;
+
+		submenu = item_data();
+		active_menu = item_data();
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
+
+		switch (res) {
+		case 0:
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data = (void *) (long) !submenu->data;
+				else
+					conf(submenu);
+				break;
+			case 't':
+				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt->type == P_MENU)
+					conf(submenu);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			case 'L':
+				conf_load();
+				break;
+			case 'S':
+				conf_save();
+				break;
+			}
+			break;
+		case 2:
+			if (sym)
+				show_help(submenu);
+			else
+				show_helptext(_("README"), _(mconf_readme));
+			break;
+		case 3:
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					show_textbox(NULL, setmod_text, 6, 74);
+			}
+			break;
+		case 4:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 5:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		case 6:
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu);
+			break;
+		case 7:
+			search_conf();
+			break;
+		}
+	}
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+	dialog_clear();
+	dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+	show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+	struct symbol *sym = menu->sym;
+
+	if (menu_has_help(menu))
+	{
+		if (sym->name) {
+			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
+			str_append(&help, _(menu_get_help(menu)));
+			str_append(&help, "\n");
+		}
+	} else {
+		str_append(&help, nohelp_text);
+	}
+	get_symbol_str(&help, sym);
+	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = _(menu_get_prompt(menu));
+	struct menu *child;
+	struct symbol *active;
+
+	active = sym_get_choice_value(menu->sym);
+	while (1) {
+		int res;
+		int selected;
+		item_reset();
+
+		current_menu = menu;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			item_make("%s", _(menu_get_prompt(child)));
+			item_set_data(child);
+			if (child->sym == active)
+				item_set_selected(1);
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_set_tag('X');
+		}
+		dialog_clear();
+		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+					_(radiolist_instructions),
+					 15, 70, 6);
+		selected = item_activate_selected();
+		switch (res) {
+		case 0:
+			if (selected) {
+				child = item_data();
+				sym_set_tristate_value(child->sym, yes);
+			}
+			return;
+		case 1:
+			if (selected) {
+				child = item_data();
+				show_help(child);
+				active = child->sym;
+			} else
+				show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		case -ERRDISPLAYTOOSMALL:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+
+	while (1) {
+		int res;
+		const char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = _(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = _(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = _(inputbox_instructions_string);
+			break;
+		default:
+			heading = _("Internal mconf error!");
+		}
+		dialog_clear();
+		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+				      heading, 10, 75,
+				      sym_get_string_value(menu->sym));
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym, dialog_input_result))
+				return;
+			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, load_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				sym_set_change_count(1);
+				return;
+			}
+			show_textbox(NULL, _("File does not exist!"), 5, 38);
+			break;
+		case 1:
+			show_helptext(_("Load Alternate Configuration"), load_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, save_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_write(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				return;
+			}
+			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+			break;
+		case 1:
+			show_helptext(_("Save Alternate Configuration"), save_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+int main(int ac, char **av)
+{
+	int saved_x, saved_y;
+	char *mode;
+	int res;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("MENUCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	getyx(stdscr, saved_y, saved_x);
+	if (init_dialog(NULL)) {
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+		return 1;
+	}
+
+	set_config_filename(conf_get_configname());
+	do {
+		conf(&rootmenu);
+		dialog_clear();
+		if (conf_get_changed())
+			res = dialog_yesno(NULL,
+					   _("Do you wish to save your "
+					     "new configuration?\n"
+					     "<ESC><ESC> to continue."),
+					   6, 60);
+		else
+			res = -1;
+	} while (res == KEY_ESC);
+	end_dialog(saved_x, saved_y);
+
+	switch (res) {
+	case 0:
+		if (conf_write(filename)) {
+			fprintf(stderr, _("\n\n"
+				"Error during writing of the configuration.\n"
+				"Your configuration changes were NOT saved."
+				"\n\n"));
+			return 1;
+		}
+		if (conf_write_autoconf()) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			return 1;
+		}
+	case -1:
+		printf(_("\n\n"
+			"*** End of FILO configuration.\n"
+			"*** Execute 'make' to build or try 'make help'."
+			"\n\n"));
+		break;
+	default:
+		fprintf(stderr, _("\n\n"
+			"Your configuration changes were NOT saved."
+			"\n\n"));
+	}
+
+	return 0;
+}

Added: trunk/filo/util/kconfig/menu.c
===================================================================
--- trunk/filo/util/kconfig/menu.c	                        (rev 0)
+++ trunk/filo/util/kconfig/menu.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+void menu_init(void)
+{
+	current_entry = current_menu = &rootmenu;
+	last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+	struct menu *menu;
+
+	menu = malloc(sizeof(*menu));
+	memset(menu, 0, sizeof(*menu));
+	menu->sym = sym;
+	menu->parent = current_menu;
+	menu->file = current_file;
+	menu->lineno = zconf_lineno();
+
+	*last_entry_ptr = menu;
+	last_entry_ptr = &menu->next;
+	current_entry = menu;
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+	menu_end_entry();
+	last_entry_ptr = &current_entry->list;
+	return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+	last_entry_ptr = &current_menu->next;
+	current_menu = current_menu->parent;
+}
+
+struct expr *menu_check_dep(struct expr *e)
+{
+	if (!e)
+		return e;
+
+	switch (e->type) {
+	case E_NOT:
+		e->left.expr = menu_check_dep(e->left.expr);
+		break;
+	case E_OR:
+	case E_AND:
+		e->left.expr = menu_check_dep(e->left.expr);
+		e->right.expr = menu_check_dep(e->right.expr);
+		break;
+	case E_SYMBOL:
+		/* change 'm' into 'm' && MODULES */
+		if (e->left.sym == &symbol_mod)
+			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+		break;
+	default:
+		break;
+	}
+	return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+	struct symbol *sym = current_entry->sym;
+
+	if (sym->type == type)
+		return;
+	if (sym->type == S_UNKNOWN) {
+		sym->type = type;
+		return;
+	}
+	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
+	    sym->name ? sym->name : "<choice>",
+	    sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+	struct property *prop = prop_alloc(type, current_entry->sym);
+
+	prop->menu = current_entry;
+	prop->expr = expr;
+	prop->visible.expr = menu_check_dep(dep);
+
+	if (prompt) {
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
+		if (current_entry->prompt)
+			prop_warn(prop, "prompt redefined");
+		current_entry->prompt = prop;
+	}
+	prop->text = prompt;
+
+	return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+	return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+	struct property *prop;
+
+	switch (token) {
+	case T_OPT_MODULES:
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(current_entry->sym);
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	case T_OPT_ENV:
+		prop_add_env(arg);
+		break;
+	}
+}
+
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+	return sym2->type == S_INT || sym2->type == S_HEX ||
+	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+void sym_check_prop(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *sym2;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_DEFAULT:
+			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+			    prop->expr->type != E_SYMBOL)
+				prop_warn(prop,
+				    "default for config symbol '%'"
+				    " must be a single symbol", sym->name);
+			break;
+		case P_SELECT:
+			sym2 = prop_get_symbol(prop);
+			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+				prop_warn(prop,
+				    "config symbol '%s' uses select, but is "
+				    "not boolean or tristate", sym->name);
+			else if (sym2->type != S_UNKNOWN &&
+			         sym2->type != S_BOOLEAN &&
+			         sym2->type != S_TRISTATE)
+				prop_warn(prop,
+				    "'%s' has wrong type. 'select' only "
+				    "accept arguments of boolean and "
+				    "tristate type", sym2->name);
+			break;
+		case P_RANGE:
+			if (sym->type != S_INT && sym->type != S_HEX)
+				prop_warn(prop, "range is only allowed "
+				                "for int or hex symbols");
+			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+			    !menu_range_valid_sym(sym, prop->expr->right.sym))
+				prop_warn(prop, "range is invalid");
+			break;
+		default:
+			;
+		}
+	}
+}
+
+void menu_finalize(struct menu *parent)
+{
+	struct menu *menu, *last_menu;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+	sym = parent->sym;
+	if (parent->list) {
+		if (sym && sym_is_choice(sym)) {
+			/* find the first choice value and find out choice type */
+			for (menu = parent->list; menu; menu = menu->next) {
+				if (menu->sym) {
+					current_entry = parent;
+					if (sym->type == S_UNKNOWN)
+						menu_set_type(menu->sym->type);
+					current_entry = menu;
+					if (menu->sym->type == S_UNKNOWN)
+						menu_set_type(sym->type);
+					break;
+				}
+			}
+			parentdep = expr_alloc_symbol(sym);
+		} else if (parent->prompt)
+			parentdep = parent->prompt->visible.expr;
+		else
+			parentdep = parent->dep;
+
+		for (menu = parent->list; menu; menu = menu->next) {
+			basedep = expr_transform(menu->dep);
+			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+			basedep = expr_eliminate_dups(basedep);
+			menu->dep = basedep;
+			if (menu->sym)
+				prop = menu->sym->prop;
+			else
+				prop = menu->prompt;
+			for (; prop; prop = prop->next) {
+				if (prop->menu != menu)
+					continue;
+				dep = expr_transform(prop->visible.expr);
+				dep = expr_alloc_and(expr_copy(basedep), dep);
+				dep = expr_eliminate_dups(dep);
+				if (menu->sym && menu->sym->type != S_TRISTATE)
+					dep = expr_trans_bool(dep);
+				prop->visible.expr = dep;
+				if (prop->type == P_SELECT) {
+					struct symbol *es = prop_get_symbol(prop);
+					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+				}
+			}
+		}
+		for (menu = parent->list; menu; menu = menu->next)
+			menu_finalize(menu);
+	} else if (sym) {
+		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+		basedep = expr_eliminate_dups(expr_transform(basedep));
+		last_menu = NULL;
+		for (menu = parent->next; menu; menu = menu->next) {
+			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+			if (!expr_contains_symbol(dep, sym))
+				break;
+			if (expr_depends_symbol(dep, sym))
+				goto next;
+			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+			dep = expr_eliminate_dups(expr_transform(dep));
+			dep2 = expr_copy(basedep);
+			expr_eliminate_eq(&dep, &dep2);
+			expr_free(dep);
+			if (!expr_is_yes(dep2)) {
+				expr_free(dep2);
+				break;
+			}
+			expr_free(dep2);
+		next:
+			menu_finalize(menu);
+			menu->parent = parent;
+			last_menu = menu;
+		}
+		if (last_menu) {
+			parent->list = parent->next;
+			parent->next = last_menu->next;
+			last_menu->next = NULL;
+		}
+	}
+	for (menu = parent->list; menu; menu = menu->next) {
+		if (sym && sym_is_choice(sym) && menu->sym) {
+			menu->sym->flags |= SYMBOL_CHOICEVAL;
+			if (!menu->prompt)
+				menu_warn(menu, "choice value must have a prompt");
+			for (prop = menu->sym->prop; prop; prop = prop->next) {
+				if (prop->type == P_PROMPT && prop->menu != menu) {
+					prop_warn(prop, "choice values "
+					    "currently only support a "
+					    "single prompt");
+				}
+				if (prop->type == P_DEFAULT)
+					prop_warn(prop, "defaults for choice "
+					    "values not supported");
+			}
+			current_entry = menu;
+			if (menu->sym->type == S_UNKNOWN)
+				menu_set_type(sym->type);
+			/* Non-tristate choice values of tristate choices must
+			 * depend on the choice being set to Y. The choice
+			 * values' dependencies were propagated to their
+			 * properties above, so the change here must be re-
+			 * propagated. */
+			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+				basedep = expr_alloc_and(basedep, menu->dep);
+				basedep = expr_eliminate_dups(basedep);
+				menu->dep = basedep;
+				for (prop = menu->sym->prop; prop; prop = prop->next) {
+					if (prop->menu != menu)
+						continue;
+					dep = expr_alloc_and(expr_copy(basedep),
+							     prop->visible.expr);
+					dep = expr_eliminate_dups(dep);
+					dep = expr_trans_bool(dep);
+					prop->visible.expr = dep;
+					if (prop->type == P_SELECT) {
+						struct symbol *es = prop_get_symbol(prop);
+						dep2 = expr_alloc_symbol(menu->sym);
+						dep = expr_alloc_and(dep2,
+								     expr_copy(dep));
+						dep = expr_alloc_or(es->rev_dep.expr, dep);
+						dep = expr_eliminate_dups(dep);
+						es->rev_dep.expr = dep;
+					}
+				}
+			}
+			menu_add_symbol(P_CHOICE, sym, NULL);
+			prop = sym_get_choice_prop(sym);
+			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+				;
+			*ep = expr_alloc_one(E_LIST, NULL);
+			(*ep)->right.sym = menu->sym;
+		}
+		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+			for (last_menu = menu->list; ; last_menu = last_menu->next) {
+				last_menu->parent = parent;
+				if (!last_menu->next)
+					break;
+			}
+			last_menu->next = menu->next;
+			menu->next = menu->list;
+			menu->list = NULL;
+		}
+	}
+
+	if (sym && !(sym->flags & SYMBOL_WARNED)) {
+		if (sym->type == S_UNKNOWN)
+			menu_warn(parent, "config symbol defined without type");
+
+		if (sym_is_choice(sym) && !parent->prompt)
+			menu_warn(parent, "choice must have a prompt");
+
+		/* Check properties connected to this symbol */
+		sym_check_prop(sym);
+		sym->flags |= SYMBOL_WARNED;
+	}
+
+	if (sym && !sym_is_optional(sym) && parent->prompt) {
+		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+				expr_alloc_and(parent->prompt->visible.expr,
+					expr_alloc_symbol(&symbol_mod)));
+	}
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+	struct menu *child;
+	struct symbol *sym;
+	tristate visible;
+
+	if (!menu->prompt)
+		return false;
+	sym = menu->sym;
+	if (sym) {
+		sym_calc_value(sym);
+		visible = menu->prompt->visible.tri;
+	} else
+		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+	if (visible != no)
+		return true;
+	if (!sym || sym_get_tristate_value(menu->sym) == no)
+		return false;
+
+	for (child = menu->list; child; child = child->next)
+		if (menu_is_visible(child))
+			return true;
+	return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+	if (menu->prompt)
+		return menu->prompt->text;
+	else if (menu->sym)
+		return menu->sym->name;
+	return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+	return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+	enum prop_type type;
+
+	for (; menu != &rootmenu; menu = menu->parent) {
+		type = menu->prompt ? menu->prompt->type : 0;
+		if (type == P_MENU)
+			break;
+	}
+	return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+	return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+	if (menu->help)
+		return menu->help;
+	else
+		return "";
+}

Added: trunk/filo/util/kconfig/qconf.cc
===================================================================
--- trunk/filo/util/kconfig/qconf.cc	                        (rev 0)
+++ trunk/filo/util/kconfig/qconf.cc	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,1764 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qapplication.h>
+#include <qmainwindow.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qlistview.h>
+#include <qtextbrowser.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qregexp.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+static ConfigSettings *configSettings;
+
+QAction *ConfigMainWindow::saveAction;
+
+static inline QString qgettext(const char* str)
+{
+	return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+	return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+	QValueList<int> result;
+	QStringList entryList = readListEntry(key, ok);
+	if (ok) {
+		QStringList::Iterator it;
+		for (it = entryList.begin(); it != entryList.end(); ++it)
+			result.push_back((*it).toInt());
+	}
+
+	return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
+{
+	QStringList stringList;
+	QValueList<int>::ConstIterator it;
+
+	for (it = value.begin(); it != value.end(); ++it)
+		stringList.push_back(QString::number(*it));
+	return writeEntry(key, stringList);
+}
+
+
+#if QT_VERSION >= 300
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+	Parent::okRename(col);
+	sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+	listView()->updateList(this);
+}
+#endif
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+	ConfigList* list;
+	struct symbol* sym;
+	struct property *prop;
+	QString prompt;
+	int type;
+	tristate expr;
+
+	list = listView();
+	if (goParent) {
+		setPixmap(promptColIdx, list->menuBackPix);
+		prompt = "..";
+		goto set_prompt;
+	}
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	prompt = _(menu_get_prompt(menu));
+
+	if (prop) switch (prop->type) {
+	case P_MENU:
+		if (list->mode == singleMode || list->mode == symbolMode) {
+			/* a menuconfig entry is displayed differently
+			 * depending whether it's at the view root or a child.
+			 */
+			if (sym && list->rootEntry == menu)
+				break;
+			setPixmap(promptColIdx, list->menuPix);
+		} else {
+			if (sym)
+				break;
+			setPixmap(promptColIdx, 0);
+		}
+		goto set_prompt;
+	case P_COMMENT:
+		setPixmap(promptColIdx, 0);
+		goto set_prompt;
+	default:
+		;
+	}
+	if (!sym)
+		goto set_prompt;
+
+	setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		char ch;
+
+		if (!sym_is_changable(sym) && !list->showAll) {
+			setPixmap(promptColIdx, 0);
+			setText(noColIdx, QString::null);
+			setText(modColIdx, QString::null);
+			setText(yesColIdx, QString::null);
+			break;
+		}
+		expr = sym_get_tristate_value(sym);
+		switch (expr) {
+		case yes:
+			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+				setPixmap(promptColIdx, list->choiceYesPix);
+			else
+				setPixmap(promptColIdx, list->symbolYesPix);
+			setText(yesColIdx, "Y");
+			ch = 'Y';
+			break;
+		case mod:
+			setPixmap(promptColIdx, list->symbolModPix);
+			setText(modColIdx, "M");
+			ch = 'M';
+			break;
+		default:
+			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+				setPixmap(promptColIdx, list->choiceNoPix);
+			else
+				setPixmap(promptColIdx, list->symbolNoPix);
+			setText(noColIdx, "N");
+			ch = 'N';
+			break;
+		}
+		if (expr != no)
+			setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+		if (expr != mod)
+			setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+		if (expr != yes)
+			setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+		setText(dataColIdx, QChar(ch));
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		const char* data;
+
+		data = sym_get_string_value(sym);
+
+#if QT_VERSION >= 300
+		int i = list->mapIdx(dataColIdx);
+		if (i >= 0)
+			setRenameEnabled(i, TRUE);
+#endif
+		setText(dataColIdx, data);
+		if (type == S_STRING)
+			prompt = QString("%1: %2").arg(prompt).arg(data);
+		else
+			prompt = QString("(%2) %1").arg(prompt).arg(data);
+		break;
+	}
+	if (!sym_has_value(sym) && visible)
+		prompt += _(" (NEW)");
+set_prompt:
+	setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+	ConfigItem* i;
+
+	visible = v;
+	if (!menu)
+		return;
+
+	sym_calc_value(menu->sym);
+	if (menu->flags & MENU_CHANGED) {
+		/* the menu entry changed, so update all list items */
+		menu->flags &= ~MENU_CHANGED;
+		for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+			i->updateMenu();
+	} else if (listView()->updateAll)
+		updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+	ConfigList* list = listView();
+
+	if (visible) {
+		if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+			Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+		else
+			Parent::paintCell(p, cg, column, width, align);
+	} else
+		Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+	if (menu) {
+		ConfigList* list = listView();
+		nextItem = (ConfigItem*)menu->data;
+		menu->data = this;
+
+		if (list->mode != fullMode)
+			setOpen(TRUE);
+		sym_calc_value(menu->sym);
+	}
+	updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+	if (menu) {
+		ConfigItem** ip = (ConfigItem**)&menu->data;
+		for (; *ip; ip = &(*ip)->nextItem) {
+			if (*ip == this) {
+				*ip = nextItem;
+				break;
+			}
+		}
+	}
+}
+
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+	: Parent(parent)
+{
+	connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+	item = i;
+	if (sym_get_string_value(item->menu->sym))
+		setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+	else
+		setText(QString::null);
+	Parent::show();
+	setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+	switch (e->key()) {
+	case Key_Escape:
+		break;
+	case Key_Return:
+	case Key_Enter:
+		sym_set_string_value(item->menu->sym, text().latin1());
+		parent()->updateList(item);
+		break;
+	default:
+		Parent::keyPressEvent(e);
+		return;
+	}
+	e->accept();
+	parent()->list->setFocus();
+	hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, const char *name)
+	: Parent(p, name),
+	  updateAll(false),
+	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+	  showAll(false), showName(false), showRange(false), showData(false),
+	  rootEntry(0), headerPopup(0)
+{
+	int i;
+
+	setSorting(-1);
+	setRootIsDecorated(TRUE);
+	disabledColorGroup = palette().active();
+	disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+	inactivedColorGroup = palette().active();
+	inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+	connect(this, SIGNAL(selectionChanged(void)),
+		SLOT(updateSelection(void)));
+
+	if (name) {
+		configSettings->beginGroup(name);
+		showAll = configSettings->readBoolEntry("/showAll", false);
+		showName = configSettings->readBoolEntry("/showName", false);
+		showRange = configSettings->readBoolEntry("/showRange", false);
+		showData = configSettings->readBoolEntry("/showData", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+
+	for (i = 0; i < colNr; i++)
+		colMap[i] = colRevMap[i] = -1;
+	addColumn(promptColIdx, _("Option"));
+
+	reinit();
+}
+
+void ConfigList::reinit(void)
+{
+	removeColumn(dataColIdx);
+	removeColumn(yesColIdx);
+	removeColumn(modColIdx);
+	removeColumn(noColIdx);
+	removeColumn(nameColIdx);
+
+	if (showName)
+		addColumn(nameColIdx, _("Name"));
+	if (showRange) {
+		addColumn(noColIdx, "N");
+		addColumn(modColIdx, "M");
+		addColumn(yesColIdx, "Y");
+	}
+	if (showData)
+		addColumn(dataColIdx, _("Value"));
+
+	updateListAll();
+}
+
+void ConfigList::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showName", showName);
+		configSettings->writeEntry("/showRange", showRange);
+		configSettings->writeEntry("/showData", showData);
+		configSettings->writeEntry("/showAll", showAll);
+		configSettings->endGroup();
+	}
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+	ConfigItem* item = (ConfigItem*)menu->data;
+
+	for (; item; item = item->nextItem) {
+		if (this == item->listView())
+			break;
+	}
+
+	return item;
+}
+
+void ConfigList::updateSelection(void)
+{
+	struct menu *menu;
+	enum prop_type type;
+
+	ConfigItem* item = (ConfigItem*)selectedItem();
+	if (!item)
+		return;
+
+	menu = item->menu;
+	emit menuChanged(menu);
+	if (!menu)
+		return;
+	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (mode == menuMode && type == P_MENU)
+		emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+	ConfigItem* last = 0;
+
+	if (!rootEntry) {
+		if (mode != listMode)
+			goto update;
+		QListViewItemIterator it(this);
+		ConfigItem* item;
+
+		for (; it.current(); ++it) {
+			item = (ConfigItem*)it.current();
+			if (!item->menu)
+				continue;
+			item->testUpdateMenu(menu_is_visible(item->menu));
+		}
+		return;
+	}
+
+	if (rootEntry != &rootmenu && (mode == singleMode ||
+	    (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+		item = firstChild();
+		if (!item)
+			item = new ConfigItem(this, 0, true);
+		last = item;
+	}
+	if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+	    rootEntry->sym && rootEntry->prompt) {
+		item = last ? last->nextSibling() : firstChild();
+		if (!item)
+			item = new ConfigItem(this, last, rootEntry, true);
+		else
+			item->testUpdateMenu(true);
+
+		updateMenuList(item, rootEntry);
+		triggerUpdate();
+		return;
+	}
+update:
+	updateMenuList(this, rootEntry);
+	triggerUpdate();
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+	struct symbol* sym;
+	int type;
+	tristate oldval;
+
+	sym = item->menu ? item->menu->sym : 0;
+	if (!sym)
+		return;
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldval = sym_get_tristate_value(sym);
+
+		if (!sym_set_tristate_value(sym, val))
+			return;
+		if (oldval == no && item->menu->list)
+			item->setOpen(TRUE);
+		parent()->updateList(item);
+		break;
+	}
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+	struct symbol* sym;
+	struct menu* menu;
+	int type, oldexpr, newexpr;
+
+	menu = item->menu;
+	if (!menu)
+		return;
+	sym = menu->sym;
+	if (!sym) {
+		if (item->menu->list)
+			item->setOpen(!item->isOpen());
+		return;
+	}
+
+	type = sym_get_type(sym);
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		oldexpr = sym_get_tristate_value(sym);
+		newexpr = sym_toggle_tristate_value(sym);
+		if (item->menu->list) {
+			if (oldexpr == newexpr)
+				item->setOpen(!item->isOpen());
+			else if (oldexpr == no)
+				item->setOpen(TRUE);
+		}
+		if (oldexpr != newexpr)
+			parent()->updateList(item);
+		break;
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+#if QT_VERSION >= 300
+		if (colMap[dataColIdx] >= 0)
+			item->startRename(colMap[dataColIdx]);
+		else
+#endif
+			parent()->lineEdit->show(item);
+		break;
+	}
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+	enum prop_type type;
+
+	if (rootEntry == menu)
+		return;
+	type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (type != P_MENU)
+		return;
+	updateMenuList(this, 0);
+	rootEntry = menu;
+	updateListAll();
+	setSelected(currentItem(), hasFocus());
+	ensureItemVisible(currentItem());
+}
+
+void ConfigList::setParentMenu(void)
+{
+	ConfigItem* item;
+	struct menu *oldroot;
+
+	oldroot = rootEntry;
+	if (rootEntry == &rootmenu)
+		return;
+	setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+	QListViewItemIterator it(this);
+	for (; (item = (ConfigItem*)it.current()); it++) {
+		if (item->menu == oldroot) {
+			setCurrentItem(item);
+			ensureItemVisible(item);
+			break;
+		}
+	}
+}
+
+/*
+ * update all the children of a menu entry
+ *   removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+	struct menu* child;
+	ConfigItem* item;
+	ConfigItem* last;
+	bool visible;
+	enum prop_type type;
+
+	if (!menu) {
+		while ((item = parent->firstChild()))
+			delete item;
+		return;
+	}
+
+	last = parent->firstChild();
+	if (last && !last->goParent)
+		last = 0;
+	for (child = menu->list; child; child = child->next) {
+		item = last ? last->nextSibling() : parent->firstChild();
+		type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+		switch (mode) {
+		case menuMode:
+			if (!(child->flags & MENU_ROOT))
+				goto hide;
+			break;
+		case symbolMode:
+			if (child->flags & MENU_ROOT)
+				goto hide;
+			break;
+		default:
+			break;
+		}
+
+		visible = menu_is_visible(child);
+		if (showAll || visible) {
+			if (!child->sym && !child->list && !child->prompt)
+				continue;
+			if (!item || item->menu != child)
+				item = new ConfigItem(parent, last, child, visible);
+			else
+				item->testUpdateMenu(visible);
+
+			if (mode == fullMode || mode == menuMode || type != P_MENU)
+				updateMenuList(item, child);
+			else
+				updateMenuList(item, 0);
+			last = item;
+			continue;
+		}
+	hide:
+		if (item && item->menu == child) {
+			last = parent->firstChild();
+			if (last == item)
+				last = 0;
+			else while (last->nextSibling() != item)
+				last = last->nextSibling();
+			delete item;
+		}
+	}
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+	QListViewItem* i = currentItem();
+	ConfigItem* item;
+	struct menu *menu;
+	enum prop_type type;
+
+	if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
+		emit parentSelected();
+		ev->accept();
+		return;
+	}
+
+	if (!i) {
+		Parent::keyPressEvent(ev);
+		return;
+	}
+	item = (ConfigItem*)i;
+
+	switch (ev->key()) {
+	case Key_Return:
+	case Key_Enter:
+		if (item->goParent) {
+			emit parentSelected();
+			break;
+		}
+		menu = item->menu;
+		if (!menu)
+			break;
+		type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+		if (type == P_MENU && rootEntry != menu &&
+		    mode != fullMode && mode != menuMode) {
+			emit menuSelected(menu);
+			break;
+		}
+	case Key_Space:
+		changeValue(item);
+		break;
+	case Key_N:
+		setValue(item, no);
+		break;
+	case Key_M:
+		setValue(item, mod);
+		break;
+	case Key_Y:
+		setValue(item, yes);
+		break;
+	default:
+		Parent::keyPressEvent(ev);
+		return;
+	}
+	ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+	//QPoint p(contentsToViewport(e->pos()));
+	//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+	QPoint p(contentsToViewport(e->pos()));
+	ConfigItem* item = (ConfigItem*)itemAt(p);
+	struct menu *menu;
+	enum prop_type ptype;
+	const QPixmap* pm;
+	int idx, x;
+
+	if (!item)
+		goto skip;
+
+	menu = item->menu;
+	x = header()->offset() + p.x();
+	idx = colRevMap[header()->sectionAt(x)];
+	switch (idx) {
+	case promptColIdx:
+		pm = item->pixmap(promptColIdx);
+		if (pm) {
+			int off = header()->sectionPos(0) + itemMargin() +
+				treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+			if (x >= off && x < off + pm->width()) {
+				if (item->goParent) {
+					emit parentSelected();
+					break;
+				} else if (!menu)
+					break;
+				ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+				if (ptype == P_MENU && rootEntry != menu &&
+				    mode != fullMode && mode != menuMode)
+					emit menuSelected(menu);
+				else
+					changeValue(item);
+			}
+		}
+		break;
+	case noColIdx:
+		setValue(item, no);
+		break;
+	case modColIdx:
+		setValue(item, mod);
+		break;
+	case yesColIdx:
+		setValue(item, yes);
+		break;
+	case dataColIdx:
+		changeValue(item);
+		break;
+	}
+
+skip:
+	//printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+	//QPoint p(contentsToViewport(e->pos()));
+	//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+	QPoint p(contentsToViewport(e->pos()));
+	ConfigItem* item = (ConfigItem*)itemAt(p);
+	struct menu *menu;
+	enum prop_type ptype;
+
+	if (!item)
+		goto skip;
+	if (item->goParent) {
+		emit parentSelected();
+		goto skip;
+	}
+	menu = item->menu;
+	if (!menu)
+		goto skip;
+	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+		emit menuSelected(menu);
+	else if (menu->sym)
+		changeValue(item);
+
+skip:
+	//printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+	Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+	struct menu *menu = NULL;
+
+	Parent::focusInEvent(e);
+
+	ConfigItem* item = (ConfigItem *)currentItem();
+	if (item) {
+		setSelected(item, TRUE);
+		menu = item->menu;
+	}
+	emit gotFocus(menu);
+}
+
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+	if (e->y() <= header()->geometry().bottom()) {
+		if (!headerPopup) {
+			QAction *action;
+
+			headerPopup = new QPopupMenu(this);
+			action = new QAction(NULL, _("Show Name"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowName(bool)));
+			  connect(parent(), SIGNAL(showNameChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showName);
+			  action->addTo(headerPopup);
+			action = new QAction(NULL, _("Show Range"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowRange(bool)));
+			  connect(parent(), SIGNAL(showRangeChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showRange);
+			  action->addTo(headerPopup);
+			action = new QAction(NULL, _("Show Data"), 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowData(bool)));
+			  connect(parent(), SIGNAL(showDataChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showData);
+			  action->addTo(headerPopup);
+		}
+		headerPopup->exec(e->globalPos());
+		e->accept();
+	} else
+		e->ignore();
+}
+
+ConfigView* ConfigView::viewList;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+	: Parent(parent, name)
+{
+	list = new ConfigList(this, name);
+	lineEdit = new ConfigLineEdit(this);
+	lineEdit->hide();
+
+	this->nextView = viewList;
+	viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+	ConfigView** vp;
+
+	for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+		if (*vp == this) {
+			*vp = nextView;
+			break;
+		}
+	}
+}
+
+void ConfigView::setShowAll(bool b)
+{
+	if (list->showAll != b) {
+		list->showAll = b;
+		list->updateListAll();
+		emit showAllChanged(b);
+	}
+}
+
+void ConfigView::setShowName(bool b)
+{
+	if (list->showName != b) {
+		list->showName = b;
+		list->reinit();
+		emit showNameChanged(b);
+	}
+}
+
+void ConfigView::setShowRange(bool b)
+{
+	if (list->showRange != b) {
+		list->showRange = b;
+		list->reinit();
+		emit showRangeChanged(b);
+	}
+}
+
+void ConfigView::setShowData(bool b)
+{
+	if (list->showData != b) {
+		list->showData = b;
+		list->reinit();
+		emit showDataChanged(b);
+	}
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+	QListViewItemIterator it(this);
+
+	for (; it.current(); it++)
+		it.current()->setOpen(open);
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+	ConfigView* v;
+
+	for (v = viewList; v; v = v->nextView)
+		v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+	ConfigView* v;
+
+	for (v = viewList; v; v = v->nextView)
+		v->list->updateListAll();
+}
+
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+	: Parent(parent, name), menu(0), sym(0)
+{
+	if (name) {
+		configSettings->beginGroup(name);
+		_showDebug = configSettings->readBoolEntry("/showDebug", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+}
+
+void ConfigInfoView::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showDebug", showDebug());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+	if (_showDebug != b) {
+		_showDebug = b;
+		if (menu)
+			menuInfo();
+		else if (sym)
+			symbolInfo();
+		emit showDebugChanged(b);
+	}
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+	if (menu == m)
+		return;
+	menu = m;
+	sym = NULL;
+	if (!menu)
+		clear();
+	else
+		menuInfo();
+}
+
+void ConfigInfoView::setSource(const QString& name)
+{
+	const char *p = name.latin1();
+
+	menu = NULL;
+	sym = NULL;
+
+	switch (p[0]) {
+	case 'm':
+		struct menu *m;
+
+		if (sscanf(p, "m%p", &m) == 1 && menu != m) {
+			menu = m;
+			menuInfo();
+			emit menuSelected(menu);
+		}
+		break;
+	case 's':
+		struct symbol *s;
+
+		if (sscanf(p, "s%p", &s) == 1 && sym != s) {
+			sym = s;
+			symbolInfo();
+		}
+		break;
+	}
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+	QString str;
+
+	str += "<big>Symbol: <b>";
+	str += print_filter(sym->name);
+	str += "</b></big><br><br>value: ";
+	str += print_filter(sym_get_string_value(sym));
+	str += "<br>visibility: ";
+	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+	str += "<br>";
+	str += debug_info(sym);
+
+	setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+	struct symbol* sym;
+	QString head, debug, help;
+
+	sym = menu->sym;
+	if (sym) {
+		if (menu->prompt) {
+			head += "<big><b>";
+			head += print_filter(_(menu->prompt->text));
+			head += "</b></big>";
+			if (sym->name) {
+				head += " (";
+				if (showDebug())
+					head += QString().sprintf("<a href=\"s%p\">", sym);
+				head += print_filter(sym->name);
+				if (showDebug())
+					head += "</a>";
+				head += ")";
+			}
+		} else if (sym->name) {
+			head += "<big><b>";
+			if (showDebug())
+				head += QString().sprintf("<a href=\"s%p\">", sym);
+			head += print_filter(sym->name);
+			if (showDebug())
+				head += "</a>";
+			head += "</b></big>";
+		}
+		head += "<br><br>";
+
+		if (showDebug())
+			debug = debug_info(sym);
+
+		help = menu_get_help(menu);
+		/* Gettextize if the help text not empty */
+		if (help.isEmpty())
+			help = print_filter(menu_get_help(menu));
+		else
+			help = print_filter(_(menu_get_help(menu)));
+	} else if (menu->prompt) {
+		head += "<big><b>";
+		head += print_filter(_(menu->prompt->text));
+		head += "</b></big><br><br>";
+		if (showDebug()) {
+			if (menu->prompt->visible.expr) {
+				debug += "  dep: ";
+				expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+				debug += "<br><br>";
+			}
+		}
+	}
+	if (showDebug())
+		debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
+
+	setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+	QString debug;
+
+	debug += "type: ";
+	debug += print_filter(sym_type_name(sym->type));
+	if (sym_is_choice(sym))
+		debug += " (choice)";
+	debug += "<br>";
+	if (sym->rev_dep.expr) {
+		debug += "reverse dep: ";
+		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+		debug += "<br>";
+	}
+	for (struct property *prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_PROMPT:
+		case P_MENU:
+			debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+			debug += print_filter(_(prop->text));
+			debug += "</a><br>";
+			break;
+		case P_DEFAULT:
+		case P_SELECT:
+		case P_RANGE:
+		case P_ENV:
+			debug += prop_get_type_name(prop->type);
+			debug += ": ";
+			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+			break;
+		case P_CHOICE:
+			if (sym_is_choice(sym)) {
+				debug += "choice: ";
+				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+				debug += "<br>";
+			}
+			break;
+		default:
+			debug += "unknown property: ";
+			debug += prop_get_type_name(prop->type);
+			debug += "<br>";
+		}
+		if (prop->visible.expr) {
+			debug += "    dep: ";
+			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+		}
+	}
+	debug += "<br>";
+
+	return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
+{
+	QRegExp re("[<>&\"\\n]");
+	QString res = str;
+	for (int i = 0; (i = res.find(re, i)) >= 0;) {
+		switch (res[i].latin1()) {
+		case '<':
+			res.replace(i, 1, "<");
+			i += 4;
+			break;
+		case '>':
+			res.replace(i, 1, ">");
+			i += 4;
+			break;
+		case '&':
+			res.replace(i, 1, "&");
+			i += 5;
+			break;
+		case '"':
+			res.replace(i, 1, """);
+			i += 6;
+			break;
+		case '\n':
+			res.replace(i, 1, "<br>");
+			i += 4;
+			break;
+		}
+	}
+	return res;
+}
+
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
+{
+	QString* text = reinterpret_cast<QString*>(data);
+	QString str2 = print_filter(str);
+
+	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+		*text += QString().sprintf("<a href=\"s%p\">", sym);
+		*text += str2;
+		*text += "</a>";
+	} else
+		*text += str2;
+}
+
+QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+	QPopupMenu* popup = Parent::createPopupMenu(pos);
+	QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup);
+	  action->setToggleAction(TRUE);
+	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+	  action->setOn(showDebug());
+	popup->insertSeparator();
+	action->addTo(popup);
+	return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+	Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
+	: Parent(parent, name), result(NULL)
+{
+	setCaption("Search Config");
+
+	QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+	QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+	layout2->addWidget(new QLabel(_("Find:"), this));
+	editField = new QLineEdit(this);
+	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+	layout2->addWidget(editField);
+	searchButton = new QPushButton(_("Search"), this);
+	searchButton->setAutoDefault(FALSE);
+	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+	layout2->addWidget(searchButton);
+	layout1->addLayout(layout2);
+
+	split = new QSplitter(this);
+	split->setOrientation(QSplitter::Vertical);
+	list = new ConfigView(split, name);
+	list->list->mode = listMode;
+	info = new ConfigInfoView(split, name);
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		info, SLOT(setInfo(struct menu *)));
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		parent, SLOT(setMenuLink(struct menu *)));
+
+	layout1->addWidget(split);
+
+	if (name) {
+		int x, y, width, height;
+		bool ok;
+
+		configSettings->beginGroup(name);
+		width = configSettings->readNumEntry("/window width", parent->width() / 2);
+		height = configSettings->readNumEntry("/window height", parent->height() / 2);
+		resize(width, height);
+		x = configSettings->readNumEntry("/window x", 0, &ok);
+		if (ok)
+			y = configSettings->readNumEntry("/window y", 0, &ok);
+		if (ok)
+			move(x, y);
+		QValueList<int> sizes = configSettings->readSizes("/split", &ok);
+		if (ok)
+			split->setSizes(sizes);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/window x", pos().x());
+		configSettings->writeEntry("/window y", pos().y());
+		configSettings->writeEntry("/window width", size().width());
+		configSettings->writeEntry("/window height", size().height());
+		configSettings->writeSizes("/split", split->sizes());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigSearchWindow::search(void)
+{
+	struct symbol **p;
+	struct property *prop;
+	ConfigItem *lastItem = NULL;
+
+	free(result);
+	list->list->clear();
+	info->clear();
+
+	result = sym_re_search(editField->text().latin1());
+	if (!result)
+		return;
+	for (p = result; *p; p++) {
+		for_all_prompts((*p), prop)
+			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+						  menu_is_visible(prop->menu));
+	}
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+	: searchWindow(0)
+{
+	QMenuBar* menu;
+	bool ok;
+	int x, y, width, height;
+	char title[256];
+
+	QWidget *d = configApp->desktop();
+	snprintf(title, sizeof(title), _("FILO v%s Configuration"),
+		getenv("KERNELVERSION"));
+	setCaption(title);
+
+	width = configSettings->readNumEntry("/window width", d->width() - 64);
+	height = configSettings->readNumEntry("/window height", d->height() - 64);
+	resize(width, height);
+	x = configSettings->readNumEntry("/window x", 0, &ok);
+	if (ok)
+		y = configSettings->readNumEntry("/window y", 0, &ok);
+	if (ok)
+		move(x, y);
+
+	split1 = new QSplitter(this);
+	split1->setOrientation(QSplitter::Horizontal);
+	setCentralWidget(split1);
+
+	menuView = new ConfigView(split1, "menu");
+	menuList = menuView->list;
+
+	split2 = new QSplitter(split1);
+	split2->setOrientation(QSplitter::Vertical);
+
+	// create config tree
+	configView = new ConfigView(split2, "config");
+	configList = configView->list;
+
+	helpText = new ConfigInfoView(split2, "help");
+	helpText->setTextFormat(Qt::RichText);
+
+	setTabOrder(configList, helpText);
+	configList->setFocus();
+
+	menu = menuBar();
+	toolBar = new QToolBar("Tools", this);
+
+	backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
+	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+	  backAction->setEnabled(FALSE);
+	QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this);
+	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
+	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this);
+	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+	saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this);
+	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+	conf_set_changed_callback(conf_changed);
+	// Set saveAction's initial state
+	conf_changed();
+	QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
+	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+	QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this);
+	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+	QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this);
+	  showNameAction->setToggleAction(TRUE);
+	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+	  showNameAction->setOn(configView->showName());
+	QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this);
+	  showRangeAction->setToggleAction(TRUE);
+	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+	  showRangeAction->setOn(configList->showRange);
+	QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this);
+	  showDataAction->setToggleAction(TRUE);
+	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+	  showDataAction->setOn(configList->showData);
+	QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
+	  showAllAction->setToggleAction(TRUE);
+	  connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
+	  connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
+	  showAllAction->setOn(configList->showAll);
+	QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
+	  showDebugAction->setToggleAction(TRUE);
+	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+	  showDebugAction->setOn(helpText->showDebug());
+
+	QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this);
+	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+	QAction *showAboutAction = new QAction(NULL, _("About"), 0, this);
+	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+	// init tool bar
+	backAction->addTo(toolBar);
+	toolBar->addSeparator();
+	loadAction->addTo(toolBar);
+	saveAction->addTo(toolBar);
+	toolBar->addSeparator();
+	singleViewAction->addTo(toolBar);
+	splitViewAction->addTo(toolBar);
+	fullViewAction->addTo(toolBar);
+
+	// create config menu
+	QPopupMenu* config = new QPopupMenu(this);
+	menu->insertItem(_("&File"), config);
+	loadAction->addTo(config);
+	saveAction->addTo(config);
+	saveAsAction->addTo(config);
+	config->insertSeparator();
+	quitAction->addTo(config);
+
+	// create edit menu
+	QPopupMenu* editMenu = new QPopupMenu(this);
+	menu->insertItem(_("&Edit"), editMenu);
+	searchAction->addTo(editMenu);
+
+	// create options menu
+	QPopupMenu* optionMenu = new QPopupMenu(this);
+	menu->insertItem(_("&Option"), optionMenu);
+	showNameAction->addTo(optionMenu);
+	showRangeAction->addTo(optionMenu);
+	showDataAction->addTo(optionMenu);
+	optionMenu->insertSeparator();
+	showAllAction->addTo(optionMenu);
+	showDebugAction->addTo(optionMenu);
+
+	// create help menu
+	QPopupMenu* helpMenu = new QPopupMenu(this);
+	menu->insertSeparator();
+	menu->insertItem(_("&Help"), helpMenu);
+	showIntroAction->addTo(helpMenu);
+	showAboutAction->addTo(helpMenu);
+
+	connect(configList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(configList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+	connect(configList, SIGNAL(parentSelected()),
+		SLOT(goBack()));
+	connect(menuList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+
+	connect(configList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		SLOT(listFocusChanged(void)));
+	connect(helpText, SIGNAL(menuSelected(struct menu *)),
+		SLOT(setMenuLink(struct menu *)));
+
+	QString listMode = configSettings->readEntry("/listMode", "symbol");
+	if (listMode == "single")
+		showSingleView();
+	else if (listMode == "full")
+		showFullView();
+	else /*if (listMode == "split")*/
+		showSplitView();
+
+	// UI setup done, restore splitter positions
+	QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+	if (ok)
+		split1->setSizes(sizes);
+
+	sizes = configSettings->readSizes("/split2", &ok);
+	if (ok)
+		split2->setSizes(sizes);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+	QString s = QFileDialog::getOpenFileName(".config", NULL, this);
+	if (s.isNull())
+		return;
+	if (conf_read(QFile::encodeName(s)))
+		QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
+	ConfigView::updateListAll();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+	if (conf_write(NULL))
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+	if (conf_write_autoconf())
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+	QString s = QFileDialog::getSaveFileName(".config", NULL, this);
+	if (s.isNull())
+		return;
+	if (conf_write(QFile::encodeName(s)))
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+	if (conf_write_autoconf())
+		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::searchConfig(void)
+{
+	if (!searchWindow)
+		searchWindow = new ConfigSearchWindow(this, "search");
+	searchWindow->show();
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+	configList->setRootMenu(menu);
+	if (configList->rootEntry->parent == &rootmenu)
+		backAction->setEnabled(FALSE);
+	else
+		backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+	struct menu *parent;
+	ConfigList* list = NULL;
+	ConfigItem* item;
+
+	if (!menu_is_visible(menu) && !configView->showAll())
+		return;
+
+	switch (configList->mode) {
+	case singleMode:
+		list = configList;
+		parent = menu_get_parent_menu(menu);
+		if (!parent)
+			return;
+		list->setRootMenu(parent);
+		break;
+	case symbolMode:
+		if (menu->flags & MENU_ROOT) {
+			configList->setRootMenu(menu);
+			configList->clearSelection();
+			list = menuList;
+		} else {
+			list = configList;
+			parent = menu_get_parent_menu(menu->parent);
+			if (!parent)
+				return;
+			item = menuList->findConfigItem(parent);
+			if (item) {
+				menuList->setSelected(item, TRUE);
+				menuList->ensureItemVisible(item);
+			}
+			list->setRootMenu(parent);
+		}
+		break;
+	case fullMode:
+		list = configList;
+		break;
+	}
+
+	if (list) {
+		item = list->findConfigItem(menu);
+		if (item) {
+			list->setSelected(item, TRUE);
+			list->ensureItemVisible(item);
+			list->setFocus();
+		}
+	}
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+	if (menuList->mode == menuMode)
+		configList->clearSelection();
+}
+
+void ConfigMainWindow::goBack(void)
+{
+	ConfigItem* item;
+
+	configList->setParentMenu();
+	if (configList->rootEntry == &rootmenu)
+		backAction->setEnabled(FALSE);
+	item = (ConfigItem*)menuList->selectedItem();
+	while (item) {
+		if (item->menu == configList->rootEntry) {
+			menuList->setSelected(item, TRUE);
+			break;
+		}
+		item = (ConfigItem*)item->parent();
+	}
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+	menuView->hide();
+	menuList->setRootMenu(0);
+	configList->mode = singleMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(TRUE);
+	configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+	configList->mode = symbolMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(TRUE);
+	configApp->processEvents();
+	menuList->mode = menuMode;
+	menuList->setRootMenu(&rootmenu);
+	menuList->setAllOpen(TRUE);
+	menuView->show();
+	menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+	menuView->hide();
+	menuList->setRootMenu(0);
+	configList->mode = fullMode;
+	if (configList->rootEntry == &rootmenu)
+		configList->updateListAll();
+	else
+		configList->setRootMenu(&rootmenu);
+	configList->setAllOpen(FALSE);
+	configList->setFocus();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+	if (!conf_get_changed()) {
+		e->accept();
+		return;
+	}
+	QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
+			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+	mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
+	mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
+	mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
+	switch (mb.exec()) {
+	case QMessageBox::Yes:
+		conf_write(NULL);
+		conf_write_autoconf();
+	case QMessageBox::No:
+		e->accept();
+		break;
+	case QMessageBox::Cancel:
+		e->ignore();
+		break;
+	}
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+	static const QString str = _("Welcome to the qconf graphical configuration tool for FILO.\n\n"
+		"For each option, a blank box indicates the feature is disabled, a check\n"
+		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
+		"as a module.  Clicking on the box will cycle through the three states.\n\n"
+		"If you do not see an option (e.g., a device driver) that you believe\n"
+		"should be present, try turning on Show All Options under the Options menu.\n"
+		"Although there is no cross reference yet to help you figure out what other\n"
+		"options must be enabled to support the option you are interested in, you can\n"
+		"still view the help of a grayed-out option.\n\n"
+		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+		"which you can then match by examining other options.\n\n");
+
+	QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+	static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>.\n\n"
+		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
+
+	QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+	configSettings->writeEntry("/window x", pos().x());
+	configSettings->writeEntry("/window y", pos().y());
+	configSettings->writeEntry("/window width", size().width());
+	configSettings->writeEntry("/window height", size().height());
+
+	QString entry;
+	switch(configList->mode) {
+	case singleMode :
+		entry = "single";
+		break;
+
+	case symbolMode :
+		entry = "split";
+		break;
+
+	case fullMode :
+		entry = "full";
+		break;
+	}
+	configSettings->writeEntry("/listMode", entry);
+
+	configSettings->writeSizes("/split1", split1->sizes());
+	configSettings->writeSizes("/split2", split2->sizes());
+}
+
+void ConfigMainWindow::conf_changed(void)
+{
+	if (saveAction)
+		saveAction->setEnabled(conf_get_changed());
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+	struct menu *child;
+	static int menu_cnt = 0;
+
+	menu->flags |= MENU_ROOT;
+	for (child = menu->list; child; child = child->next) {
+		if (child->prompt && child->prompt->type == P_MENU) {
+			menu_cnt++;
+			fixup_rootmenu(child);
+			menu_cnt--;
+		} else if (!menu_cnt)
+			fixup_rootmenu(child);
+	}
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+	printf(_("%s <config>\n"), progname);
+	exit(0);
+}
+
+int main(int ac, char** av)
+{
+	ConfigMainWindow* v;
+	const char *name;
+
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+#ifndef LKC_DIRECT_LINK
+	kconfig_load();
+#endif
+
+	progname = av[0];
+	configApp = new QApplication(ac, av);
+	if (ac > 1 && av[1][0] == '-') {
+		switch (av[1][1]) {
+		case 'h':
+		case '?':
+			usage();
+		}
+		name = av[2];
+	} else
+		name = av[1];
+	if (!name)
+		usage();
+
+	conf_parse(name);
+	fixup_rootmenu(&rootmenu);
+	conf_read(NULL);
+	//zconfdump(stdout);
+
+	configSettings = new ConfigSettings();
+	configSettings->beginGroup("/kconfig/qconf");
+	v = new ConfigMainWindow();
+
+	//zconfdump(stdout);
+	configApp->setMainWidget(v);
+	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+	v->show();
+	configApp->exec();
+
+	configSettings->endGroup();
+	delete configSettings;
+
+	return 0;
+}

Added: trunk/filo/util/kconfig/qconf.h
===================================================================
--- trunk/filo/util/kconfig/qconf.h	                        (rev 0)
+++ trunk/filo/util/kconfig/qconf.h	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qlistview.h>
+#if QT_VERSION >= 300
+#include <qsettings.h>
+#else
+class QSettings {
+public:
+	void beginGroup(const QString& group) { }
+	void endGroup(void) { }
+	bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	QStringList readListEntry(const QString& key, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return QStringList(); }
+	template <class t>
+	bool writeEntry(const QString& key, t value)
+	{ return TRUE; }
+};
+#endif
+
+class ConfigView;
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+
+class ConfigSettings : public QSettings {
+public:
+	QValueList<int> readSizes(const QString& key, bool *ok);
+	bool writeSizes(const QString& key, const QValueList<int>& value);
+};
+
+enum colIdx {
+	promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+	singleMode, menuMode, symbolMode, fullMode, listMode
+};
+
+class ConfigList : public QListView {
+	Q_OBJECT
+	typedef class QListView Parent;
+public:
+	ConfigList(ConfigView* p, const char *name = 0);
+	void reinit(void);
+	ConfigView* parent(void) const
+	{
+		return (ConfigView*)Parent::parent();
+	}
+	ConfigItem* findConfigItem(struct menu *);
+
+protected:
+	void keyPressEvent(QKeyEvent *e);
+	void contentsMousePressEvent(QMouseEvent *e);
+	void contentsMouseReleaseEvent(QMouseEvent *e);
+	void contentsMouseMoveEvent(QMouseEvent *e);
+	void contentsMouseDoubleClickEvent(QMouseEvent *e);
+	void focusInEvent(QFocusEvent *e);
+	void contextMenuEvent(QContextMenuEvent *e);
+
+public slots:
+	void setRootMenu(struct menu *menu);
+
+	void updateList(ConfigItem *item);
+	void setValue(ConfigItem* item, tristate val);
+	void changeValue(ConfigItem* item);
+	void updateSelection(void);
+	void saveSettings(void);
+signals:
+	void menuChanged(struct menu *menu);
+	void menuSelected(struct menu *menu);
+	void parentSelected(void);
+	void gotFocus(struct menu *);
+
+public:
+	void updateListAll(void)
+	{
+		updateAll = true;
+		updateList(NULL);
+		updateAll = false;
+	}
+	ConfigList* listView()
+	{
+		return this;
+	}
+	ConfigItem* firstChild() const
+	{
+		return (ConfigItem *)Parent::firstChild();
+	}
+	int mapIdx(colIdx idx)
+	{
+		return colMap[idx];
+	}
+	void addColumn(colIdx idx, const QString& label)
+	{
+		colMap[idx] = Parent::addColumn(label);
+		colRevMap[colMap[idx]] = idx;
+	}
+	void removeColumn(colIdx idx)
+	{
+		int col = colMap[idx];
+		if (col >= 0) {
+			Parent::removeColumn(col);
+			colRevMap[col] = colMap[idx] = -1;
+		}
+	}
+	void setAllOpen(bool open);
+	void setParentMenu(void);
+
+	template <class P>
+	void updateMenuList(P*, struct menu*);
+
+	bool updateAll;
+
+	QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+	QPixmap choiceYesPix, choiceNoPix;
+	QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+	bool showAll, showName, showRange, showData;
+	enum listMode mode;
+	struct menu *rootEntry;
+	QColorGroup disabledColorGroup;
+	QColorGroup inactivedColorGroup;
+	QPopupMenu* headerPopup;
+
+private:
+	int colMap[colNr];
+	int colRevMap[colNr];
+};
+
+class ConfigItem : public QListViewItem {
+	typedef class QListViewItem Parent;
+public:
+	ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v)
+	: Parent(parent, after), menu(m), visible(v), goParent(false)
+	{
+		init();
+	}
+	ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+	: Parent(parent, after), menu(m), visible(v), goParent(false)
+	{
+		init();
+	}
+	ConfigItem(QListView *parent, ConfigItem *after, bool v)
+	: Parent(parent, after), menu(0), visible(v), goParent(true)
+	{
+		init();
+	}
+	~ConfigItem(void);
+	void init(void);
+#if QT_VERSION >= 300
+	void okRename(int col);
+#endif
+	void updateMenu(void);
+	void testUpdateMenu(bool v);
+	ConfigList* listView() const
+	{
+		return (ConfigList*)Parent::listView();
+	}
+	ConfigItem* firstChild() const
+	{
+		return (ConfigItem *)Parent::firstChild();
+	}
+	ConfigItem* nextSibling() const
+	{
+		return (ConfigItem *)Parent::nextSibling();
+	}
+	void setText(colIdx idx, const QString& text)
+	{
+		Parent::setText(listView()->mapIdx(idx), text);
+	}
+	QString text(colIdx idx) const
+	{
+		return Parent::text(listView()->mapIdx(idx));
+	}
+	void setPixmap(colIdx idx, const QPixmap& pm)
+	{
+		Parent::setPixmap(listView()->mapIdx(idx), pm);
+	}
+	const QPixmap* pixmap(colIdx idx) const
+	{
+		return Parent::pixmap(listView()->mapIdx(idx));
+	}
+	void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+	ConfigItem* nextItem;
+	struct menu *menu;
+	bool visible;
+	bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+	Q_OBJECT
+	typedef class QLineEdit Parent;
+public:
+	ConfigLineEdit(ConfigView* parent);
+	ConfigView* parent(void) const
+	{
+		return (ConfigView*)Parent::parent();
+	}
+	void show(ConfigItem *i);
+	void keyPressEvent(QKeyEvent *e);
+
+public:
+	ConfigItem *item;
+};
+
+class ConfigView : public QVBox {
+	Q_OBJECT
+	typedef class QVBox Parent;
+public:
+	ConfigView(QWidget* parent, const char *name = 0);
+	~ConfigView(void);
+	static void updateList(ConfigItem* item);
+	static void updateListAll(void);
+
+	bool showAll(void) const { return list->showAll; }
+	bool showName(void) const { return list->showName; }
+	bool showRange(void) const { return list->showRange; }
+	bool showData(void) const { return list->showData; }
+public slots:
+	void setShowAll(bool);
+	void setShowName(bool);
+	void setShowRange(bool);
+	void setShowData(bool);
+signals:
+	void showAllChanged(bool);
+	void showNameChanged(bool);
+	void showRangeChanged(bool);
+	void showDataChanged(bool);
+public:
+	ConfigList* list;
+	ConfigLineEdit* lineEdit;
+
+	static ConfigView* viewList;
+	ConfigView* nextView;
+};
+
+class ConfigInfoView : public QTextBrowser {
+	Q_OBJECT
+	typedef class QTextBrowser Parent;
+public:
+	ConfigInfoView(QWidget* parent, const char *name = 0);
+	bool showDebug(void) const { return _showDebug; }
+
+public slots:
+	void setInfo(struct menu *menu);
+	void saveSettings(void);
+	void setSource(const QString& name);
+	void setShowDebug(bool);
+
+signals:
+	void showDebugChanged(bool);
+	void menuSelected(struct menu *);
+
+protected:
+	void symbolInfo(void);
+	void menuInfo(void);
+	QString debug_info(struct symbol *sym);
+	static QString print_filter(const QString &str);
+	static void expr_print_help(void *data, struct symbol *sym, const char *str);
+	QPopupMenu* createPopupMenu(const QPoint& pos);
+	void contentsContextMenuEvent(QContextMenuEvent *e);
+
+	struct symbol *sym;
+	struct menu *menu;
+	bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+	Q_OBJECT
+	typedef class QDialog Parent;
+public:
+	ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
+
+public slots:
+	void saveSettings(void);
+	void search(void);
+
+protected:
+	QLineEdit* editField;
+	QPushButton* searchButton;
+	QSplitter* split;
+	ConfigView* list;
+	ConfigInfoView* info;
+
+	struct symbol **result;
+};
+
+class ConfigMainWindow : public QMainWindow {
+	Q_OBJECT
+
+	static QAction *saveAction;
+	static void conf_changed(void);
+public:
+	ConfigMainWindow(void);
+public slots:
+	void changeMenu(struct menu *);
+	void setMenuLink(struct menu *);
+	void listFocusChanged(void);
+	void goBack(void);
+	void loadConfig(void);
+	void saveConfig(void);
+	void saveConfigAs(void);
+	void searchConfig(void);
+	void showSingleView(void);
+	void showSplitView(void);
+	void showFullView(void);
+	void showIntro(void);
+	void showAbout(void);
+	void saveSettings(void);
+
+protected:
+	void closeEvent(QCloseEvent *e);
+
+	ConfigSearchWindow *searchWindow;
+	ConfigView *menuView;
+	ConfigList *menuList;
+	ConfigView *configView;
+	ConfigList *configList;
+	ConfigInfoView *helpText;
+	QToolBar *toolBar;
+	QAction *backAction;
+	QSplitter* split1;
+	QSplitter* split2;
+};

Added: trunk/filo/util/kconfig/symbol.c
===================================================================
--- trunk/filo/util/kconfig/symbol.c	                        (rev 0)
+++ trunk/filo/util/kconfig/symbol.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+	.name = "y",
+	.curr = { "y", yes },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+	.name = "m",
+	.curr = { "m", mod },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+	.name = "n",
+	.curr = { "n", no },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+	.name = "",
+	.curr = { "", no },
+	.flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+void sym_add_default(struct symbol *sym, const char *def)
+{
+	struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+	prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+}
+
+void sym_init(void)
+{
+	struct symbol *sym;
+	struct utsname uts;
+	static bool inited = false;
+
+	if (inited)
+		return;
+	inited = true;
+
+	uname(&uts);
+
+	sym = sym_lookup("UNAME_RELEASE", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+	enum symbol_type type = sym->type;
+
+	if (type == S_TRISTATE) {
+		if (sym_is_choice_value(sym) && sym->visible == yes)
+			type = S_BOOLEAN;
+		else if (modules_val == no)
+			type = S_BOOLEAN;
+	}
+	return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+	switch (type) {
+	case S_BOOLEAN:
+		return "boolean";
+	case S_TRISTATE:
+		return "tristate";
+	case S_INT:
+		return "integer";
+	case S_HEX:
+		return "hex";
+	case S_STRING:
+		return "string";
+	case S_UNKNOWN:
+		return "unknown";
+	case S_OTHER:
+		break;
+	}
+	return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_choices(sym, prop)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_ENV)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_RANGE) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+	sym_calc_value(sym);
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		break;
+	}
+	return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+	struct property *prop;
+	int base, val, val2;
+	char str[64];
+
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		return;
+	}
+	prop = sym_get_range_prop(sym);
+	if (!prop)
+		return;
+	val = strtol(sym->curr.val, NULL, base);
+	val2 = sym_get_range_val(prop->expr->left.sym, base);
+	if (val >= val2) {
+		val2 = sym_get_range_val(prop->expr->right.sym, base);
+		if (val <= val2)
+			return;
+	}
+	if (sym->type == S_INT)
+		sprintf(str, "%d", val2);
+	else
+		sprintf(str, "0x%x", val2);
+	sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+	struct property *prop;
+	tristate tri;
+
+	/* any prompt visible? */
+	tri = no;
+	for_all_prompts(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		tri = EXPR_OR(tri, prop->visible.tri);
+	}
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+		tri = yes;
+	if (sym->visible != tri) {
+		sym->visible = tri;
+		sym_set_changed(sym);
+	}
+	if (sym_is_choice_value(sym))
+		return;
+	tri = no;
+	if (sym->rev_dep.expr)
+		tri = expr_calc_value(sym->rev_dep.expr);
+	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+		tri = yes;
+	if (sym->rev_dep.tri != tri) {
+		sym->rev_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* any of the defaults visible? */
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri == no)
+			continue;
+		def_sym = prop_get_symbol(prop);
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* just get the first visible value */
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* no choice? reset tristate value */
+	sym->curr.tri = no;
+	return NULL;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+	struct symbol_value newval, oldval;
+	struct property *prop;
+	struct expr *e;
+
+	if (!sym)
+		return;
+
+	if (sym->flags & SYMBOL_VALID)
+		return;
+	sym->flags |= SYMBOL_VALID;
+
+	oldval = sym->curr;
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		newval = symbol_empty.curr;
+		break;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		newval = symbol_no.curr;
+		break;
+	default:
+		sym->curr.val = sym->name;
+		sym->curr.tri = no;
+		return;
+	}
+	if (!sym_is_choice_value(sym))
+		sym->flags &= ~SYMBOL_WRITE;
+
+	sym_calc_visibility(sym);
+
+	/* set default if recursively called */
+	sym->curr = newval;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		if (sym_is_choice_value(sym) && sym->visible == yes) {
+			prop = sym_get_choice_prop(sym);
+			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+		} else {
+			if (sym->visible != no) {
+				/* if the symbol is visible use the user value
+				 * if available, otherwise try the default value
+				 */
+				sym->flags |= SYMBOL_WRITE;
+				if (sym_has_value(sym)) {
+					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+							      sym->visible);
+					goto calc_newval;
+				}
+			}
+			if (sym->rev_dep.tri != no)
+				sym->flags |= SYMBOL_WRITE;
+			if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop) {
+					sym->flags |= SYMBOL_WRITE;
+					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+							      prop->visible.tri);
+				}
+			}
+		calc_newval:
+			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+		}
+		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+			newval.tri = yes;
+		break;
+	case S_STRING:
+	case S_HEX:
+	case S_INT:
+		if (sym->visible != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym)) {
+				newval.val = sym->def[S_DEF_USER].val;
+				break;
+			}
+		}
+		prop = sym_get_default_prop(sym);
+		if (prop) {
+			struct symbol *ds = prop_get_symbol(prop);
+			if (ds) {
+				sym->flags |= SYMBOL_WRITE;
+				sym_calc_value(ds);
+				newval.val = ds->curr.val;
+			}
+		}
+		break;
+	default:
+		;
+	}
+
+	if (sym->flags & SYMBOL_AUTO)
+		sym->flags &= ~SYMBOL_WRITE;
+
+	sym->curr = newval;
+	if (sym_is_choice(sym) && newval.tri == yes)
+		sym->curr.val = sym_calc_choice(sym);
+	sym_validate_range(sym);
+
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+		sym_set_changed(sym);
+		if (modules_sym == sym) {
+			sym_set_all_changed();
+			modules_val = modules_sym->curr.tri;
+		}
+	}
+
+	if (sym_is_choice(sym)) {
+		struct symbol *choice_sym;
+		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+
+		prop = sym_get_choice_prop(sym);
+		expr_list_for_each_sym(prop->expr, e, choice_sym) {
+			choice_sym->flags |= flags;
+			if (flags & SYMBOL_CHANGED)
+				sym_set_changed(choice_sym);
+		}
+	}
+}
+
+void sym_clear_all_valid(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym->flags &= ~SYMBOL_VALID;
+	sym_add_change_count(1);
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+	struct property *prop;
+
+	sym->flags |= SYMBOL_CHANGED;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu)
+			prop->menu->flags |= MENU_CHANGED;
+	}
+}
+
+void sym_set_all_changed(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+	int type = sym_get_type(sym);
+
+	if (sym->visible == no)
+		return false;
+
+	if (type != S_BOOLEAN && type != S_TRISTATE)
+		return false;
+
+	if (type == S_BOOLEAN && val == mod)
+		return false;
+	if (sym->visible <= sym->rev_dep.tri)
+		return false;
+	if (sym_is_choice_value(sym) && sym->visible == yes)
+		return val == yes;
+	return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+	tristate oldval = sym_get_tristate_value(sym);
+
+	if (oldval != val && !sym_tristate_within_range(sym, val))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+	/*
+	 * setting a choice value also resets the new flag of the choice
+	 * symbol and all other choice values.
+	 */
+	if (sym_is_choice_value(sym) && val == yes) {
+		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+		struct property *prop;
+		struct expr *e;
+
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
+		prop = sym_get_choice_prop(cs);
+		for (e = prop->expr; e; e = e->left.expr) {
+			if (e->right.sym->visible != no)
+				e->right.sym->flags |= SYMBOL_DEF_USER;
+		}
+	}
+
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
+		sym_clear_all_valid();
+
+	return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+	tristate oldval, newval;
+
+	oldval = newval = sym_get_tristate_value(sym);
+	do {
+		switch (newval) {
+		case no:
+			newval = mod;
+			break;
+		case mod:
+			newval = yes;
+			break;
+		case yes:
+			newval = no;
+			break;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			break;
+	} while (oldval != newval);
+	return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+	signed char ch;
+
+	switch (sym->type) {
+	case S_STRING:
+		return true;
+	case S_INT:
+		ch = *str++;
+		if (ch == '-')
+			ch = *str++;
+		if (!isdigit(ch))
+			return false;
+		if (ch == '0' && *str != 0)
+			return false;
+		while ((ch = *str++)) {
+			if (!isdigit(ch))
+				return false;
+		}
+		return true;
+	case S_HEX:
+		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+			str += 2;
+		ch = *str++;
+		do {
+			if (!isxdigit(ch))
+				return false;
+		} while ((ch = *str++));
+		return true;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+		case 'm': case 'M':
+		case 'n': case 'N':
+			return true;
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+	struct property *prop;
+	int val;
+
+	switch (sym->type) {
+	case S_STRING:
+		return sym_string_valid(sym, str);
+	case S_INT:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 10);
+		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 10);
+	case S_HEX:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 16);
+		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 16);
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+			return sym_tristate_within_range(sym, yes);
+		case 'm': case 'M':
+			return sym_tristate_within_range(sym, mod);
+		case 'n': case 'N':
+			return sym_tristate_within_range(sym, no);
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+	const char *oldval;
+	char *val;
+	int size;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (newval[0]) {
+		case 'y': case 'Y':
+			return sym_set_tristate_value(sym, yes);
+		case 'm': case 'M':
+			return sym_set_tristate_value(sym, mod);
+		case 'n': case 'N':
+			return sym_set_tristate_value(sym, no);
+		}
+		return false;
+	default:
+		;
+	}
+
+	if (!sym_string_within_range(sym, newval))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+
+	oldval = sym->def[S_DEF_USER].val;
+	size = strlen(newval) + 1;
+	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+		size += 2;
+		sym->def[S_DEF_USER].val = val = malloc(size);
+		*val++ = '0';
+		*val++ = 'x';
+	} else if (!oldval || strcmp(oldval, newval))
+		sym->def[S_DEF_USER].val = val = malloc(size);
+	else
+		return true;
+
+	strcpy(val, newval);
+	free((void *)oldval);
+	sym_clear_all_valid();
+
+	return true;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+	tristate val;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			return "n";
+		case mod:
+			return "m";
+		case yes:
+			return "y";
+		}
+		break;
+	default:
+		;
+	}
+	return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+	return sym->visible > sym->rev_dep.tri;
+}
+
+struct symbol *sym_lookup(const char *name, int isconst)
+{
+	struct symbol *symbol;
+	const char *ptr;
+	char *new_name;
+	int hash = 0;
+
+	if (name) {
+		if (name[0] && !name[1]) {
+			switch (name[0]) {
+			case 'y': return &symbol_yes;
+			case 'm': return &symbol_mod;
+			case 'n': return &symbol_no;
+			}
+		}
+		for (ptr = name; *ptr; ptr++)
+			hash += *ptr;
+		hash &= 0xff;
+
+		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+			if (!strcmp(symbol->name, name)) {
+				if ((isconst && symbol->flags & SYMBOL_CONST) ||
+				    (!isconst && !(symbol->flags & SYMBOL_CONST)))
+					return symbol;
+			}
+		}
+		new_name = strdup(name);
+	} else {
+		new_name = NULL;
+		hash = 256;
+	}
+
+	symbol = malloc(sizeof(*symbol));
+	memset(symbol, 0, sizeof(*symbol));
+	symbol->name = new_name;
+	symbol->type = S_UNKNOWN;
+	if (isconst)
+		symbol->flags |= SYMBOL_CONST;
+
+	symbol->next = symbol_hash[hash];
+	symbol_hash[hash] = symbol;
+
+	return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+	struct symbol *symbol = NULL;
+	const char *ptr;
+	int hash = 0;
+
+	if (!name)
+		return NULL;
+
+	if (name[0] && !name[1]) {
+		switch (name[0]) {
+		case 'y': return &symbol_yes;
+		case 'm': return &symbol_mod;
+		case 'n': return &symbol_no;
+		}
+	}
+	for (ptr = name; *ptr; ptr++)
+		hash += *ptr;
+	hash &= 0xff;
+
+	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+		if (!strcmp(symbol->name, name) &&
+		    !(symbol->flags & SYMBOL_CONST))
+				break;
+	}
+
+	return symbol;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+	struct symbol *sym, **sym_arr = NULL;
+	int i, cnt, size;
+	regex_t re;
+
+	cnt = size = 0;
+	/* Skip if empty */
+	if (strlen(pattern) == 0)
+		return NULL;
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+		return NULL;
+
+	for_all_symbols(i, sym) {
+		if (sym->flags & SYMBOL_CONST || !sym->name)
+			continue;
+		if (regexec(&re, sym->name, 0, NULL, 0))
+			continue;
+		if (cnt + 1 >= size) {
+			void *tmp = sym_arr;
+			size += 16;
+			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+			if (!sym_arr) {
+				free(tmp);
+				return NULL;
+			}
+		}
+		sym_arr[cnt++] = sym;
+	}
+	if (sym_arr)
+		sym_arr[cnt] = NULL;
+	regfree(&re);
+
+	return sym_arr;
+}
+
+
+struct symbol *sym_check_deps(struct symbol *sym);
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+	struct symbol *sym;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_OR:
+	case E_AND:
+		sym = sym_check_expr_deps(e->left.expr);
+		if (sym)
+			return sym;
+		return sym_check_expr_deps(e->right.expr);
+	case E_NOT:
+		return sym_check_expr_deps(e->left.expr);
+	case E_EQUAL:
+	case E_UNEQUAL:
+		sym = sym_check_deps(e->left.sym);
+		if (sym)
+			return sym;
+		return sym_check_deps(e->right.sym);
+	case E_SYMBOL:
+		return sym_check_deps(e->left.sym);
+	default:
+		break;
+	}
+	printf("Oops! How to check %d?\n", e->type);
+	return NULL;
+}
+
+/* return NULL when dependencies are OK */
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK) {
+		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
+		        sym->prop->file->name, sym->prop->lineno, sym->name);
+		return sym;
+	}
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
+
+	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+	if (sym2)
+		goto out;
+
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->type == P_CHOICE || prop->type == P_SELECT)
+			continue;
+		sym2 = sym_check_expr_deps(prop->visible.expr);
+		if (sym2)
+			goto out;
+		if (prop->type != P_DEFAULT || sym_is_choice(sym))
+			continue;
+		sym2 = sym_check_expr_deps(prop->expr);
+		if (sym2)
+			goto out;
+	}
+out:
+	if (sym2)
+		fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
+	sym->flags &= ~SYMBOL_CHECK;
+	return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+	struct property *prop;
+	struct property **propp;
+
+	prop = malloc(sizeof(*prop));
+	memset(prop, 0, sizeof(*prop));
+	prop->type = type;
+	prop->sym = sym;
+	prop->file = current_file;
+	prop->lineno = zconf_lineno();
+
+	/* append property to the prop list of symbol */
+	if (sym) {
+		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+			;
+		*propp = prop;
+	}
+
+	return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+	if (prop->expr && (prop->expr->type == E_SYMBOL ||
+			   prop->expr->type == E_LIST))
+		return prop->expr->left.sym;
+	return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+	switch (type) {
+	case P_PROMPT:
+		return "prompt";
+	case P_ENV:
+		return "env";
+	case P_COMMENT:
+		return "comment";
+	case P_MENU:
+		return "menu";
+	case P_DEFAULT:
+		return "default";
+	case P_CHOICE:
+		return "choice";
+	case P_SELECT:
+		return "select";
+	case P_RANGE:
+		return "range";
+	case P_UNKNOWN:
+		break;
+	}
+	return "unknown";
+}
+
+void prop_add_env(const char *env)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	char *p;
+
+	sym = current_entry->sym;
+	sym->flags |= SYMBOL_AUTO;
+	for_all_properties(sym, prop, P_ENV) {
+		sym2 = prop_get_symbol(prop);
+		if (strcmp(sym2->name, env))
+			menu_warn(current_entry, "redefining environment symbol from %s",
+				  sym2->name);
+		return;
+	}
+
+	prop = prop_alloc(P_ENV, sym);
+	prop->expr = expr_alloc_symbol(sym_lookup(env, 1));
+
+	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+	sym_env_list->right.sym = sym;
+
+	p = getenv(env);
+	if (p)
+		sym_add_default(sym, p);
+	else
+		menu_warn(current_entry, "environment variable %s undefined", env);
+}

Added: trunk/filo/util/kconfig/util.c
===================================================================
--- trunk/filo/util/kconfig/util.c	                        (rev 0)
+++ trunk/filo/util/kconfig/util.c	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel at linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam at ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+	struct file *file;
+
+	for (file = file_list; file; file = file->next) {
+		if (!strcmp(name, file->name))
+			return file;
+	}
+
+	file = malloc(sizeof(*file));
+	memset(file, 0, sizeof(*file));
+	file->name = strdup(name);
+	file->next = file_list;
+	file_list = file;
+	return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+	struct symbol *sym, *env_sym;
+	struct expr *e;
+	struct file *file;
+	FILE *out;
+
+	if (!name)
+		name = ".kconfig.d";
+	out = fopen("..config.tmp", "w");
+	if (!out)
+		return 1;
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next) {
+		if (file->next)
+			fprintf(out, "\t%s \\\n", file->name);
+		else
+			fprintf(out, "\t%s\n", file->name);
+	}
+	fprintf(out, "\nbuild/auto.conf: \\\n"
+		     "\t$(deps_config)\n\n");
+
+	expr_list_for_each_sym(sym_env_list, e, sym) {
+		struct property *prop;
+		const char *value;
+
+		prop = sym_get_env_prop(sym);
+		env_sym = prop_get_symbol(prop);
+		if (!env_sym)
+			continue;
+		value = getenv(env_sym->name);
+		if (!value)
+			value = "";
+		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+		fprintf(out, "build/auto.conf: FORCE\n");
+		fprintf(out, "endif\n");
+	}
+
+	fprintf(out, "\n$(deps_config): ;\n");
+	fclose(out);
+	rename("..config.tmp", name);
+	return 0;
+}
+
+
+/* Allocate initial growable sting */
+struct gstr str_new(void)
+{
+	struct gstr gs;
+	gs.s = malloc(sizeof(char) * 64);
+	gs.len = 16;
+	strcpy(gs.s, "\0");
+	return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+	struct gstr gs;
+	gs.s = strdup(s);
+	gs.len = strlen(s) + 1;
+	return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+	if (gs->s)
+		free(gs->s);
+	gs->s = NULL;
+	gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+	size_t l;
+	if (s) {
+		l = strlen(gs->s) + strlen(s) + 1;
+		if (l > gs->len) {
+			gs->s   = realloc(gs->s, l);
+			gs->len = l;
+		}
+		strcat(gs->s, s);
+	}
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+	va_list ap;
+	char s[10000]; /* big enough... */
+	va_start(ap, fmt);
+	vsnprintf(s, sizeof(s), fmt, ap);
+	str_append(gs, s);
+	va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+	return gs->s;
+}
+

Added: trunk/filo/util/kconfig/zconf.gperf
===================================================================
--- trunk/filo/util/kconfig/zconf.gperf	                        (rev 0)
+++ trunk/filo/util/kconfig/zconf.gperf	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,44 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+%%
+mainmenu,	T_MAINMENU,	TF_COMMAND
+menu,		T_MENU,		TF_COMMAND
+endmenu,	T_ENDMENU,	TF_COMMAND
+source,		T_SOURCE,	TF_COMMAND
+choice,		T_CHOICE,	TF_COMMAND
+endchoice,	T_ENDCHOICE,	TF_COMMAND
+comment,	T_COMMENT,	TF_COMMAND
+config,		T_CONFIG,	TF_COMMAND
+menuconfig,	T_MENUCONFIG,	TF_COMMAND
+help,		T_HELP,		TF_COMMAND
+if,		T_IF,		TF_COMMAND|TF_PARAM
+endif,		T_ENDIF,	TF_COMMAND
+depends,	T_DEPENDS,	TF_COMMAND
+optional,	T_OPTIONAL,	TF_COMMAND
+default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
+prompt,		T_PROMPT,	TF_COMMAND
+tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
+def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE
+bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
+boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
+def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
+int,		T_TYPE,		TF_COMMAND, S_INT
+hex,		T_TYPE,		TF_COMMAND, S_HEX
+string,		T_TYPE,		TF_COMMAND, S_STRING
+select,		T_SELECT,	TF_COMMAND
+range,		T_RANGE,	TF_COMMAND
+option,		T_OPTION,	TF_COMMAND
+on,		T_ON,		TF_PARAM
+modules,	T_OPT_MODULES,	TF_OPTION
+defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION
+env,		T_OPT_ENV,	TF_OPTION
+%%

Added: trunk/filo/util/kconfig/zconf.hash.c_shipped
===================================================================
--- trunk/filo/util/kconfig/zconf.hash.c_shipped	                        (rev 0)
+++ trunk/filo/util/kconfig/zconf.hash.c_shipped	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,237 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf at gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 47, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 11,  5,
+       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
+       5,  0, 30, 49,  0, 15,  0, 10,  0, 49,
+      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str15[sizeof("bool")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("boolean")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str21[sizeof("string")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("source")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("hex")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("prompt")];
+    char kconf_id_strings_str37[sizeof("depends")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "env",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "bool",
+    "config",
+    "def_tristate",
+    "boolean",
+    "defconfig_list",
+    "string",
+    "if",
+    "int",
+    "select",
+    "modules",
+    "tristate",
+    "menu",
+    "source",
+    "comment",
+    "hex",
+    "menuconfig",
+    "prompt",
+    "depends",
+    "mainmenu"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 31,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 48
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_OPT_ENV,	TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_HELP,		TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_INT},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SOURCE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_TYPE,		TF_COMMAND, S_HEX},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_DEPENDS,	TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,	T_MAINMENU,	TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+

Added: trunk/filo/util/kconfig/zconf.l
===================================================================
--- trunk/filo/util/kconfig/zconf.l	                        (rev 0)
+++ trunk/filo/util/kconfig/zconf.l	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,355 @@
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+	text = malloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+	text = malloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+%}
+
+ws	[ \n\t]
+n	[A-Za-z0-9_]
+
+%%
+	int str = 0;
+	int ts, i;
+
+[ \t]*#.*\n	|
+[ \t]*\n	{
+	current_file->lineno++;
+	return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+	{
+	BEGIN(COMMAND);
+}
+
+.	{
+	unput(yytext[0]);
+	BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+	{n}+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	.
+	\n	{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+}
+
+<PARAM>{
+	"&&"	return T_AND;
+	"||"	return T_OR;
+	"("	return T_OPEN_PAREN;
+	")"	return T_CLOSE_PAREN;
+	"!"	return T_NOT;
+	"="	return T_EQUAL;
+	"!="	return T_UNEQUAL;
+	\"|\'	{
+		str = yytext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	---	/* ignore */
+	({n}|[-/.])+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	#.*	/* comment */
+	\\\n	current_file->lineno++;
+	.
+	<<EOF>> {
+		BEGIN(INITIAL);
+	}
+}
+
+<STRING>{
+	[^'"\\\n]+/\n	{
+		append_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	[^'"\\\n]+	{
+		append_string(yytext, yyleng);
+	}
+	\\.?/\n	{
+		append_string(yytext + 1, yyleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	\\.?	{
+		append_string(yytext + 1, yyleng - 1);
+	}
+	\'|\"	{
+		if (str == yytext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(yytext, 1);
+	}
+	\n	{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	<<EOF>>	{
+		BEGIN(INITIAL);
+	}
+}
+
+<HELP>{
+	[ \t]+	{
+		ts = 0;
+		for (i = 0; i < yyleng; i++) {
+			if (yytext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	[ \t]*\n/[^ \t\n] {
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	[ \t]*\n	{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	[^ \t\n].* {
+		while (yyleng) {
+			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+				break;
+			yyleng--;
+		}
+		append_string(yytext, yyleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	<<EOF>>	{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+}
+
+<<EOF>>	{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(yyin);
+	yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	yyin = zconf_fopen(name);
+	if (!yyin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = malloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+	current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+	struct file *file = file_lookup(name);
+	struct buffer *buf = malloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	yyin = zconf_fopen(name);
+	if (!yyin) {
+		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+		exit(1);
+	}
+	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	if (file->flags & FILE_BUSY) {
+		printf("recursive scan (%s)?\n", name);
+		exit(1);
+	}
+	if (file->flags & FILE_SCANNED) {
+		printf("file %s already scanned?\n", name);
+		exit(1);
+	}
+	file->flags |= FILE_BUSY;
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file->flags |= FILE_SCANNED;
+	current_file->flags &= ~FILE_BUSY;
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(yyin);
+		yy_delete_buffer(YY_CURRENT_BUFFER);
+		yy_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}

Added: trunk/filo/util/kconfig/zconf.tab.c_shipped
===================================================================
--- trunk/filo/util/kconfig/zconf.tab.c_shipped	                        (rev 0)
+++ trunk/filo/util/kconfig/zconf.tab.c_shipped	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,2479 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   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, 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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse zconfparse
+#define yylex   zconflex
+#define yyerror zconferror
+#define yylval  zconflval
+#define yychar  zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_TYPE = 274,
+     T_DEFAULT = 275,
+     T_SELECT = 276,
+     T_RANGE = 277,
+     T_OPTION = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
+   };
+#endif
+/* Tokens.  */
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_TYPE 274
+#define T_DEFAULT 275
+#define T_SELECT 276
+#define T_RANGE 277
+#define T_OPTION 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
+
+
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+
+{
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	struct kconf_id *id;
+}
+/* Line 187 of yacc.c.  */
+
+	YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   258
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  35
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  45
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  108
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  178
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   289
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   103,   107,
+     112,   117,   122,   128,   132,   133,   137,   138,   141,   144,
+     147,   149,   153,   154,   157,   160,   163,   166,   169,   174,
+     178,   181,   186,   187,   190,   194,   196,   200,   201,   204,
+     207,   210,   214,   217,   219,   223,   224,   227,   230,   233,
+     237,   241,   244,   247,   250,   251,   254,   257,   260,   265,
+     266,   269,   271,   273,   276,   279,   282,   284,   287,   288,
+     291,   293,   297,   301,   305,   308,   312,   316,   318
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      53,    -1,    37,    64,    -1,    37,     3,    74,    76,    -1,
+      37,    75,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    18,
+      -1,    19,    -1,    21,    -1,    17,    -1,    22,    -1,    20,
+      -1,    30,    -1,    59,    -1,    68,    -1,    42,    -1,    44,
+      -1,    66,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    47,
+      -1,    45,    72,    -1,    45,    70,    -1,    45,    40,    -1,
+      45,    30,    -1,    19,    73,    30,    -1,    18,    74,    77,
+      30,    -1,    20,    78,    77,    30,    -1,    21,    25,    77,
+      30,    -1,    22,    79,    79,    77,    30,    -1,    23,    48,
+      30,    -1,    -1,    48,    25,    49,    -1,    -1,    33,    74,
+      -1,     7,    30,    -1,    50,    54,    -1,    75,    -1,    51,
+      56,    52,    -1,    -1,    54,    55,    -1,    54,    72,    -1,
+      54,    70,    -1,    54,    30,    -1,    54,    40,    -1,    18,
+      74,    77,    30,    -1,    19,    73,    30,    -1,    17,    30,
+      -1,    20,    25,    77,    30,    -1,    -1,    56,    39,    -1,
+      14,    78,    76,    -1,    75,    -1,    57,    60,    58,    -1,
+      -1,    60,    39,    -1,    60,    64,    -1,    60,    53,    -1,
+       4,    74,    30,    -1,    61,    71,    -1,    75,    -1,    62,
+      65,    63,    -1,    -1,    65,    39,    -1,    65,    64,    -1,
+      65,    53,    -1,     6,    74,    30,    -1,     9,    74,    30,
+      -1,    67,    71,    -1,    12,    30,    -1,    69,    13,    -1,
+      -1,    71,    72,    -1,    71,    30,    -1,    71,    40,    -1,
+      16,    24,    78,    30,    -1,    -1,    74,    77,    -1,    25,
+      -1,    26,    -1,     5,    30,    -1,     8,    30,    -1,    15,
+      30,    -1,    30,    -1,    76,    30,    -1,    -1,    14,    78,
+      -1,    79,    -1,    79,    33,    79,    -1,    79,    27,    79,
+      -1,    29,    78,    28,    -1,    34,    78,    -1,    78,    31,
+      78,    -1,    78,    32,    78,    -1,    25,    -1,    26,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   104,   104,   106,   108,   109,   110,   111,   112,   113,
+     114,   118,   122,   122,   122,   122,   122,   122,   122,   126,
+     127,   128,   129,   130,   131,   135,   136,   142,   150,   156,
+     164,   174,   176,   177,   178,   179,   180,   181,   184,   192,
+     198,   208,   214,   220,   223,   225,   236,   237,   242,   251,
+     256,   264,   267,   269,   270,   271,   272,   273,   276,   282,
+     293,   299,   309,   311,   316,   324,   332,   335,   337,   338,
+     339,   344,   351,   356,   364,   367,   369,   370,   371,   374,
+     382,   389,   396,   402,   409,   411,   412,   413,   416,   424,
+     426,   431,   432,   435,   436,   437,   441,   442,   445,   446,
+     449,   450,   451,   452,   453,   454,   455,   458,   459
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+  "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
+  "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
+  "comment_stmt", "help_start", "help", "depends_list", "depends",
+  "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    45,    46,    46,
+      46,    46,    46,    47,    48,    48,    49,    49,    50,    51,
+      52,    53,    54,    54,    54,    54,    54,    54,    55,    55,
+      55,    55,    56,    56,    57,    58,    59,    60,    60,    60,
+      60,    61,    62,    63,    64,    65,    65,    65,    65,    66,
+      67,    68,    69,    70,    71,    71,    71,    71,    72,    73,
+      73,    74,    74,    75,    75,    75,    76,    76,    77,    77,
+      78,    78,    78,    78,    78,    78,    78,    79,    79
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     2,     3,     4,
+       4,     4,     5,     3,     0,     3,     0,     2,     2,     2,
+       1,     3,     0,     2,     2,     2,     2,     2,     4,     3,
+       2,     4,     0,     2,     3,     1,     3,     0,     2,     2,
+       2,     3,     2,     1,     3,     0,     2,     2,     2,     3,
+       3,     2,     2,     2,     0,     2,     2,     2,     4,     0,
+       2,     1,     1,     2,     2,     2,     1,     2,     0,     2,
+       1,     3,     3,     3,     2,     3,     3,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    52,    62,     5,    67,    20,    84,    75,     6,    24,
+      84,    21,     8,    11,    91,    92,     0,     0,    93,     0,
+      48,    94,     0,     0,     0,   107,   108,     0,     0,     0,
+     100,    95,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    96,     7,    71,    79,    80,    27,    29,     0,
+     104,     0,     0,    64,     0,     0,     9,    10,     0,     0,
+       0,     0,    89,     0,     0,     0,    44,     0,    37,    36,
+      32,    33,     0,    35,    34,     0,     0,    89,     0,    56,
+      57,    53,    55,    54,    63,    51,    50,    68,    70,    66,
+      69,    65,    86,    87,    85,    76,    78,    74,    77,    73,
+      97,   103,   105,   106,   102,   101,    26,    82,     0,    98,
+       0,    98,    98,    98,     0,     0,     0,    83,    60,    98,
+       0,    98,     0,     0,     0,    38,    90,     0,     0,    98,
+      46,    43,    25,     0,    59,     0,    88,    99,    39,    40,
+      41,     0,     0,    45,    58,    61,    42,    47
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     2,    25,    26,    99,    27,    28,    29,    30,
+      64,   100,   101,   145,   173,    31,    32,   115,    33,    66,
+     111,    67,    34,   119,    35,    68,    36,    37,   127,    38,
+      70,    39,    40,    41,   102,   103,    69,   104,   140,   141,
+      42,    73,   154,    59,    60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -78
+static const yytype_int16 yypact[] =
+{
+     -78,    33,   130,   -78,   -28,    73,    73,     7,    73,    36,
+      41,    73,    26,    52,    -4,    58,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,    90,   -78,    94,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    74,    85,   -78,    96,
+     -78,   -78,   131,   134,   147,   -78,   -78,    -4,    -4,   193,
+     -10,   -78,   162,   164,    38,   102,    64,   148,     5,   192,
+       5,   165,   -78,   174,   -78,   -78,   -78,   -78,   -78,    65,
+     -78,    -4,    -4,   174,   103,   103,   -78,   -78,   175,   185,
+     197,    73,    73,    -4,   194,   103,   -78,   231,   -78,   -78,
+     -78,   -78,   220,   -78,   -78,   204,    73,    73,   210,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   205,   -78,   -78,   -78,   -78,   -78,    -4,   222,
+     208,   222,   195,   222,   103,     2,   209,   -78,   -78,   222,
+     211,   222,   199,    -4,   212,   -78,   -78,   213,   214,   222,
+     207,   -78,   -78,   215,   -78,   216,   -78,   111,   -78,   -78,
+     -78,   217,    73,   -78,   -78,   -78,   -78,   -78
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -78,   -78,   -78,   -78,   121,   -35,   -78,   -78,   -78,   -78,
+     219,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -44,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,    -6,
+     -78,   -78,   -78,   -78,   -78,   183,   218,    21,   143,    -5,
+     146,   196,    69,   -53,   -77
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -82
+static const yytype_int16 yytable[] =
+{
+      46,    47,    43,    49,    79,    80,    52,   134,   135,     6,
+       7,     8,     9,    10,    11,    12,    13,    84,   144,    14,
+      15,    55,    56,    85,   118,    57,   126,   160,   132,   133,
+      58,   110,   161,     3,   123,    24,   123,    48,   -28,    88,
+     142,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+      89,    53,   -28,   -28,    90,   -28,    91,    92,    93,    94,
+      95,    96,   120,    97,   128,    88,    50,   159,    98,   -49,
+     -49,    51,   -49,   -49,   -49,   -49,    89,    54,   -49,   -49,
+      90,   105,   106,   107,   108,   152,   139,   113,    61,    97,
+     124,    62,   124,   131,   109,    63,    81,    82,    44,    45,
+     167,   149,   -30,    88,    72,   -30,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,    89,    74,   -30,   -30,    90,   -30,
+      91,    92,    93,    94,    95,    96,    75,    97,    55,    56,
+      -2,     4,    98,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    81,    82,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,     7,     8,    23,    10,    11,    12,    13,
+      24,    76,    14,    15,    77,   -81,    88,   177,   -81,   -81,
+     -81,   -81,   -81,   -81,   -81,   -81,   -81,    78,    24,   -81,
+     -81,    90,   -81,   -81,   -81,   -81,   -81,   -81,   114,   117,
+      97,   125,    86,    88,    87,   122,   -72,   -72,   -72,   -72,
+     -72,   -72,   -72,   -72,   130,   136,   -72,   -72,    90,   153,
+     156,   157,   158,   116,   121,   137,   129,    97,   163,   143,
+     165,   138,   122,    72,    81,    82,    81,    82,   171,   166,
+      81,    82,   146,   147,   148,   151,   153,    82,   155,   162,
+     172,   164,   168,   169,   170,   174,   175,   176,    65,   112,
+     150,     0,     0,     0,     0,    83,     0,     0,    71
+};
+
+static const yytype_int16 yycheck[] =
+{
+       5,     6,    30,     8,    57,    58,    11,    84,    85,     4,
+       5,     6,     7,     8,     9,    10,    11,    27,    95,    14,
+      15,    25,    26,    33,    68,    29,    70,    25,    81,    82,
+      34,    66,    30,     0,    69,    30,    71,    30,     0,     1,
+      93,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    25,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    68,    25,    70,     1,    30,   144,    30,     5,
+       6,    30,     8,     9,    10,    11,    12,    25,    14,    15,
+      16,    17,    18,    19,    20,   138,    91,    66,    30,    25,
+      69,     1,    71,    28,    30,     1,    31,    32,    25,    26,
+     153,   106,     0,     1,    30,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    30,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    30,    25,    25,    26,
+       0,     1,    30,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    31,    32,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,     5,     6,    25,     8,     9,    10,    11,
+      30,    30,    14,    15,    30,     0,     1,   172,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    30,    30,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    67,    68,
+      25,    70,    30,     1,    30,    30,     4,     5,     6,     7,
+       8,     9,    10,    11,    30,    30,    14,    15,    16,    14,
+     141,   142,   143,    67,    68,    30,    70,    25,   149,    25,
+     151,    24,    30,    30,    31,    32,    31,    32,   159,    30,
+      31,    32,     1,    13,    30,    25,    14,    32,    30,    30,
+      33,    30,    30,    30,    30,    30,    30,    30,    29,    66,
+     107,    -1,    -1,    -1,    -1,    59,    -1,    -1,    40
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    25,    30,    38,    39,    41,    42,    43,
+      44,    50,    51,    53,    57,    59,    61,    62,    64,    66,
+      67,    68,    75,    30,    25,    26,    74,    74,    30,    74,
+      30,    30,    74,    25,    25,    25,    26,    29,    34,    78,
+      79,    30,     1,     1,    45,    45,    54,    56,    60,    71,
+      65,    71,    30,    76,    30,    30,    30,    30,    30,    78,
+      78,    31,    32,    76,    27,    33,    30,    30,     1,    12,
+      16,    18,    19,    20,    21,    22,    23,    25,    30,    40,
+      46,    47,    69,    70,    72,    17,    18,    19,    20,    30,
+      40,    55,    70,    72,    39,    52,    75,    39,    53,    58,
+      64,    75,    30,    40,    72,    39,    53,    63,    64,    75,
+      30,    28,    78,    78,    79,    79,    30,    30,    24,    74,
+      73,    74,    78,    25,    79,    48,     1,    13,    30,    74,
+      73,    25,    78,    14,    77,    30,    77,    77,    77,    79,
+      25,    30,    30,    77,    30,    77,    30,    78,    30,    30,
+      30,    77,    33,    49,    30,    30,    30,    74
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+	 constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+		    + sizeof yyexpecting - 1
+		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+		       * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+	 YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	  {
+	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+	      {
+		yycount = 1;
+		yysize = yysize0;
+		yyformat[sizeof yyunexpected - 1] = '\0';
+		break;
+	      }
+	    yyarg[yycount++] = yytname[yyx];
+	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+	    yysize_overflow |= (yysize1 < yysize);
+	    yysize = yysize1;
+	    yyfmt = yystpcpy (yyfmt, yyprefix);
+	    yyprefix = yyor;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+	{
+	  /* Avoid sprintf, as that infringes on the user's name space.
+	     Don't have undefined behavior even if the translation
+	     produced a string with the wrong number of "%s"s.  */
+	  char *yyp = yyresult;
+	  int yyi = 0;
+	  while ((*yyp = *yyf) != '\0')
+	    {
+	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		{
+		  yyp += yytnamerr (yyp, yyarg[yyi++]);
+		  yyf += 2;
+		}
+	      else
+		{
+		  yyp++;
+		  yyf++;
+		}
+	    }
+	}
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 51: /* "choice_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+      case 57: /* "if_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+      case 62: /* "menu_entry" */
+
+	{
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+	break;
+
+      default:
+	break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 8:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 9:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+    break;
+
+  case 10:
+
+    {
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+;}
+    break;
+
+  case 11:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 28:
+
+    {
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 29:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 30:
+
+    {
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 38:
+
+    {
+	menu_set_type((yyvsp[(1) - (3)].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[(1) - (3)].id)->stype);
+;}
+    break;
+
+  case 39:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 40:
+
+    {
+	menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+	if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+		menu_set_type((yyvsp[(1) - (4)].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[(1) - (4)].id)->stype);
+;}
+    break;
+
+  case 41:
+
+    {
+	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 45:
+
+    {
+	struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+	else
+		zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+	free((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 46:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 47:
+
+    { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+    break;
+
+  case 48:
+
+    {
+	struct symbol *sym = sym_lookup(NULL, 0);
+	sym->flags |= SYMBOL_CHOICE;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 49:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 50:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 58:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 59:
+
+    {
+	if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+		menu_set_type((yyvsp[(1) - (3)].id)->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			(yyvsp[(1) - (3)].id)->stype);
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 60:
+
+    {
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 61:
+
+    {
+	if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 64:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep((yyvsp[(2) - (3)].expr));
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 65:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 71:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 72:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 73:
+
+    {
+	if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 79:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+	zconf_nextfile((yyvsp[(2) - (3)].string));
+;}
+    break;
+
+  case 80:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 81:
+
+    {
+	menu_end_entry();
+;}
+    break;
+
+  case 82:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+;}
+    break;
+
+  case 83:
+
+    {
+	current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+    break;
+
+  case 88:
+
+    {
+	menu_add_dep((yyvsp[(3) - (4)].expr));
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 90:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+    break;
+
+  case 93:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 94:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 95:
+
+    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    break;
+
+  case 98:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 99:
+
+    { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+    break;
+
+  case 100:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+    break;
+
+  case 101:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 102:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    break;
+
+  case 103:
+
+    { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+    break;
+
+  case 104:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+    break;
+
+  case 105:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    break;
+
+  case 107:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+  case 108:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 1); free((yyvsp[(1) - (1)].string)); ;}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+	  {
+	    YYSIZE_T yyalloc = 2 * yysize;
+	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
+	    if (yymsg != yymsgbuf)
+	      YYSTACK_FREE (yymsg);
+	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+	    if (yymsg)
+	      yymsg_alloc = yyalloc;
+	    else
+	      {
+		yymsg = yymsgbuf;
+		yymsg_alloc = sizeof yymsgbuf;
+	      }
+	  }
+
+	if (0 < yysize && yysize <= yymsg_alloc)
+	  {
+	    (void) yysyntax_error (yymsg, yystate, yychar);
+	    yyerror (yymsg);
+	  }
+	else
+	  {
+	    yyerror (YY_("syntax error"));
+	    if (yysize != 0)
+	      goto yyexhaustedlab;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, "FILO Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+        }
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "choice\n");
+	else
+		fprintf(out, "config %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+	fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+			fputs("\n", out);
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+

Added: trunk/filo/util/kconfig/zconf.y
===================================================================
--- trunk/filo/util/kconfig/zconf.y	                        (rev 0)
+++ trunk/filo/util/kconfig/zconf.y	2008-08-29 13:36:25 UTC (rev 55)
@@ -0,0 +1,703 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel at linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 26
+
+%union
+{
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg
+
+%destructor {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		$$->file->name, $$->lineno);
+	if (current_menu == $$)
+		menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%%
+input: stmt_list;
+
+stmt_list:
+	  /* empty */
+	| stmt_list common_stmt
+	| stmt_list choice_stmt
+	| stmt_list menu_stmt
+	| stmt_list T_MAINMENU prompt nl
+	| stmt_list end			{ zconf_error("unexpected end statement"); }
+	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
+	| stmt_list option_name error T_EOL
+{
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+	| stmt_list error T_EOL		{ zconf_error("invalid statement"); }
+;
+
+option_name:
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
+;
+
+common_stmt:
+	  T_EOL
+	| if_stmt
+	| comment_stmt
+	| config_stmt
+	| menuconfig_stmt
+	| source_stmt
+;
+
+option_error:
+	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); }
+	| error T_EOL			{ zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+	  /* empty */
+	| config_option_list config_option
+	| config_option_list symbol_option
+	| config_option_list depends
+	| config_option_list help
+	| config_option_list option_error
+	| config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+	menu_add_expr(P_DEFAULT, $2, $3);
+	if ($1->stype != S_UNKNOWN)
+		menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+	  /* empty */
+	| symbol_option_list T_WORD symbol_option_arg
+{
+	struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, $3);
+	else
+		zconfprint("warning: ignoring unknown option %s", $2);
+	free($2);
+};
+
+symbol_option_arg:
+	  /* empty */		{ $$ = NULL; }
+	| T_EQUAL prompt	{ $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE T_EOL
+{
+	struct symbol *sym = sym_lookup(NULL, 0);
+	sym->flags |= SYMBOL_CHOICE;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+	$$ = menu_add_menu();
+};
+
+choice_end: end
+{
+	if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+	  /* empty */
+	| choice_option_list choice_option
+	| choice_option_list depends
+	| choice_option_list help
+	| choice_option_list T_EOL
+	| choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+		menu_set_type($1->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			$1->stype);
+	} else
+		YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+	if ($1->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+};
+
+choice_block:
+	  /* empty */
+	| choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep($2);
+	$$ = menu_add_menu();
+};
+
+if_end: end
+{
+	if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+	  /* empty */
+	| if_block common_stmt
+	| if_block menu_stmt
+	| if_block choice_stmt
+;
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu depends_list
+{
+	$$ = menu_add_menu();
+};
+
+menu_end: end
+{
+	if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+	  /* empty */
+	| menu_block common_stmt
+	| menu_block menu_stmt
+	| menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+	zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+	menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+	current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+	  /* empty */
+	| depends_list depends
+	| depends_list T_EOL
+	| depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+	menu_add_dep($3);
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+	  /* empty */
+	| prompt if_expr
+{
+	menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt:	  T_WORD
+	| T_WORD_QUOTE
+;
+
+end:	  T_ENDMENU T_EOL	{ $$ = $1; }
+	| T_ENDCHOICE T_EOL	{ $$ = $1; }
+	| T_ENDIF T_EOL		{ $$ = $1; }
+;
+
+nl:
+	  T_EOL
+	| nl T_EOL
+;
+
+if_expr:  /* empty */			{ $$ = NULL; }
+	| T_IF expr			{ $$ = $2; }
+;
+
+expr:	  symbol				{ $$ = expr_alloc_symbol($1); }
+	| symbol T_EQUAL symbol			{ $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+	| symbol T_UNEQUAL symbol		{ $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+	| T_OPEN_PAREN expr T_CLOSE_PAREN	{ $$ = $2; }
+	| T_NOT expr				{ $$ = expr_alloc_one(E_NOT, $2); }
+	| expr T_OR expr			{ $$ = expr_alloc_two(E_OR, $1, $3); }
+	| expr T_AND expr			{ $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
+	| T_WORD_QUOTE	{ $$ = sym_lookup($1, 1); free($1); }
+;
+
+%%
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, "FILO Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+        }
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "choice\n");
+	else
+		fprintf(out, "config %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+	fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+			fputs("\n", out);
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"

Added: trunk/filo/util/vmser.c
===================================================================
--- trunk/filo/util/vmser.c	                        (rev 0)
+++ trunk/filo/util/vmser.c	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
+ */
+
+
+/*
+ * Simple terminal for VMware serial port
+ */
+#include <stdio.h>
+#include <curses.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+int main()
+{
+    int s;
+    struct sockaddr_un addr;
+    char buf[1024];
+    int n;
+
+    s = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s < 0) {
+	perror("socket");
+	return 1;
+    }
+
+    memset(&addr, 0, sizeof addr);
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, "/tmp/vmserial");
+
+    if (connect(s, (void *) &addr, sizeof addr) < 0) {
+	perror("connect");
+	return 1;
+    }
+
+    initscr();
+    cbreak();
+    if (fork()) {
+	while ((n = read(s, buf, sizeof buf)) > 0)
+	    write(1, buf, n);
+	if (n < 0)
+	    perror("read from socket");
+    } else {
+	while ((n = read(0, buf, sizeof buf)) > 0)
+	    write(s, buf, n);
+    }
+    endwin();
+
+    return 0;
+}





More information about the coreboot mailing list