[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 (®s->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (®s->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 (®s->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 (®s->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (®s->intrenable));
+ // intrdisable always same as intrenable
+ // ohci_dump_intr_mask ("intrdisable", readl (®s->intrdisable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (®s->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), ¤t_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 = ¤t_entry->list;
+ return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = ¤t_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