This commit was manufactured by cvs2svn to create branch
authorPlanet-Lab Support <support@planet-lab.org>
Fri, 21 Jan 2005 03:34:24 +0000 (03:34 +0000)
committerPlanet-Lab Support <support@planet-lab.org>
Fri, 21 Jan 2005 03:34:24 +0000 (03:34 +0000)
'planetlab-3_0-branch'.

172 files changed:
Documentation/powerpc/hvcs.txt [new file with mode: 0644]
Documentation/powerpc/mpc52xx.txt [new file with mode: 0644]
arch/arm/configs/ixp4xx_defconfig [new file with mode: 0644]
arch/arm/configs/mainstone_defconfig [new file with mode: 0644]
arch/arm/configs/smdk2410_defconfig [new file with mode: 0644]
arch/arm/mach-ixp4xx/common-pci.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/coyote-setup.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixdp425-setup.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/prpmc1100-setup.c [new file with mode: 0644]
arch/arm/mach-s3c2410/gpio.c [new file with mode: 0644]
arch/arm/mach-s3c2410/mach-smdk2410.c [new file with mode: 0644]
arch/arm/mach-sa1100/collie.c [new file with mode: 0644]
arch/i386/crypto/Makefile [new file with mode: 0644]
arch/i386/crypto/aes-i586-asm.S [new file with mode: 0644]
arch/i386/crypto/aes.c [new file with mode: 0644]
arch/i386/mm/mmap.c [new file with mode: 0644]
arch/mips/configs/ocelot_g_defconfig [new file with mode: 0644]
arch/parisc/kernel/unwind.c [new file with mode: 0644]
arch/ppc/boot/simple/mpc52xx_tty.c [new file with mode: 0644]
arch/ppc/configs/ads8272_defconfig [new file with mode: 0644]
arch/ppc/configs/bubinga_defconfig [new file with mode: 0644]
arch/ppc/configs/lite5200_defconfig [new file with mode: 0644]
arch/ppc/configs/rpx8260_defconfig [new file with mode: 0644]
arch/ppc/kernel/dma-mapping.c [new file with mode: 0644]
arch/ppc/kernel/head_e500.S [new file with mode: 0644]
arch/ppc/kernel/vecemu.c [new file with mode: 0644]
arch/ppc/lib/rheap.c [new file with mode: 0644]
arch/ppc/platforms/85xx/Kconfig [new file with mode: 0644]
arch/ppc/platforms/85xx/Makefile [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8540_ads.c [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8540_ads.h [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8555.c [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8555_cds.h [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8560_ads.c [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc8560_ads.h [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc85xx_cds_common.c [new file with mode: 0644]
arch/ppc/platforms/85xx/mpc85xx_cds_common.h [new file with mode: 0644]
arch/ppc/platforms/85xx/sbc8560.c [new file with mode: 0644]
arch/ppc/platforms/85xx/sbc8560.h [new file with mode: 0644]
arch/ppc/platforms/lite5200.c [new file with mode: 0644]
arch/ppc/platforms/lite5200.h [new file with mode: 0644]
arch/ppc/platforms/mpc5200.c [new file with mode: 0644]
arch/ppc/platforms/rpx8260.c [new file with mode: 0644]
arch/ppc/platforms/rpx8260.h [new file with mode: 0644]
arch/ppc/syslib/cpm2_common.c [new file with mode: 0644]
arch/ppc/syslib/m8260_pci_erratum9.c [new file with mode: 0644]
arch/ppc/syslib/mpc52xx_pic.c [new file with mode: 0644]
arch/ppc/syslib/mpc52xx_setup.c [new file with mode: 0644]
arch/ppc/syslib/ppc4xx_sgdma.c [new file with mode: 0644]
arch/ppc/syslib/ppc85xx_setup.c [new file with mode: 0644]
arch/ppc/syslib/ppc85xx_setup.h [new file with mode: 0644]
arch/ppc64/kernel/hvcserver.c [new file with mode: 0644]
arch/ppc64/mm/mmap.c [new file with mode: 0644]
arch/ppc64/mm/slb.c [new file with mode: 0644]
arch/ppc64/mm/slb_low.S [new file with mode: 0644]
arch/s390/mm/mmap.c [new file with mode: 0644]
arch/sh/configs/rts7751r2d_defconfig [new file with mode: 0644]
arch/sh64/configs/cayman_defconfig [new file with mode: 0644]
arch/sh64/defconfig [new file with mode: 0644]
arch/sparc64/lib/splock.S [new file with mode: 0644]
arch/um/drivers/cow.h [new file with mode: 0644]
arch/um/drivers/cow_kern.c [new file with mode: 0644]
arch/um/drivers/cow_sys.h [new file with mode: 0644]
arch/um/drivers/cow_user.c [new file with mode: 0644]
arch/um/include/aio.h [new file with mode: 0644]
arch/um/include/filehandle.h [new file with mode: 0644]
arch/um/include/irq_kern.h [new file with mode: 0644]
arch/um/include/mem_kern.h [new file with mode: 0644]
arch/um/include/skas_ptregs.h [new file with mode: 0644]
arch/um/kernel/filehandle.c [new file with mode: 0644]
arch/um/kernel/physmem.c [new file with mode: 0644]
arch/um/kernel/skas/uaccess.c [new file with mode: 0644]
arch/um/kernel/tt/uaccess.c [new file with mode: 0644]
arch/um/os-Linux/aio.c [new file with mode: 0644]
arch/um/os-Linux/time.c [new file with mode: 0644]
arch/um/os-Linux/user_syms.c [new file with mode: 0644]
arch/um/sys-i386/bitops.c [new file with mode: 0644]
arch/um/sys-i386/semaphore.c [new file with mode: 0644]
arch/x86_64/mm/mmap.c [new file with mode: 0644]
configs/kernel-2.6.8-i586-smp.config [new file with mode: 0644]
configs/kernel-2.6.8-i586.config [new file with mode: 0644]
configs/kernel-2.6.8-i686-smp.config [new file with mode: 0644]
configs/kernel-2.6.8-i686.config [new file with mode: 0644]
crypto/signature/ksign-keyring.c [new file with mode: 0644]
crypto/signature/ksign.c [new file with mode: 0644]
drivers/char/drm/drm_irq.h [new file with mode: 0644]
drivers/char/hpet.c [new file with mode: 0644]
drivers/char/hvcs.c [new file with mode: 0644]
drivers/char/watchdog/ixp2000_wdt.c [new file with mode: 0644]
drivers/char/watchdog/ixp4xx_wdt.c [new file with mode: 0644]
drivers/firmware/pcdp.c [new file with mode: 0644]
drivers/firmware/pcdp.h [new file with mode: 0644]
drivers/mtd/devices/phram.c [new file with mode: 0644]
drivers/mtd/maps/ichxrom.c [new file with mode: 0644]
drivers/mtd/nand/diskonchip.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c [new file with mode: 0644]
drivers/mtd/nand/tx4925ndfmc.c [new file with mode: 0644]
drivers/net/via-velocity.c [new file with mode: 0644]
drivers/pcmcia/pd6729.c [new file with mode: 0644]
drivers/s390/net/ctcdbug.c [new file with mode: 0644]
drivers/s390/net/ctcdbug.h [new file with mode: 0644]
drivers/scsi/3w-9xxx.c [new file with mode: 0644]
drivers/scsi/sata_nv.c [new file with mode: 0644]
drivers/serial/cpm_uart/cpm_uart_core.c [new file with mode: 0644]
drivers/serial/cpm_uart/cpm_uart_cpm1.c [new file with mode: 0644]
drivers/serial/cpm_uart/cpm_uart_cpm1.h [new file with mode: 0644]
drivers/serial/cpm_uart/cpm_uart_cpm2.c [new file with mode: 0644]
drivers/serial/cpm_uart/cpm_uart_cpm2.h [new file with mode: 0644]
drivers/serial/mpc52xx_uart.c [new file with mode: 0644]
drivers/serial/sn_console.c [new file with mode: 0644]
drivers/video/pxafb.c [new file with mode: 0644]
drivers/w1/Kconfig [new file with mode: 0644]
drivers/w1/matrox_w1.c [new file with mode: 0644]
drivers/w1/w1.c [new file with mode: 0644]
drivers/w1/w1_int.c [new file with mode: 0644]
drivers/w1/w1_io.c [new file with mode: 0644]
fs/hostfs/Makefile [new file with mode: 0644]
fs/hostfs/externfs.c [new file with mode: 0644]
fs/hostfs/host_file.c [new file with mode: 0644]
fs/hostfs/host_fs.c [new file with mode: 0644]
fs/hostfs/hostfs.h [new file with mode: 0644]
fs/hostfs/humfs.c [new file with mode: 0644]
fs/hostfs/meta_fs.c [new file with mode: 0644]
fs/hostfs/metadata.h [new file with mode: 0644]
fs/hppfs/Makefile [new file with mode: 0644]
fs/hppfs/hppfs_kern.c [new file with mode: 0644]
fs/jffs2/compr.h [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_sysctl.c [new file with mode: 0644]
include/asm-parisc/unwind.h [new file with mode: 0644]
include/asm-ppc/cpm2.h [new file with mode: 0644]
include/asm-ppc/mpc52xx.h [new file with mode: 0644]
include/asm-ppc/mpc52xx_psc.h [new file with mode: 0644]
include/asm-ppc/mpc85xx.h [new file with mode: 0644]
include/asm-ppc/ppc4xx_dma.h [new file with mode: 0644]
include/asm-ppc64/hvcserver.h [new file with mode: 0644]
include/asm-sh64/page.h [new file with mode: 0644]
include/asm-um/cpufeature.h [new file with mode: 0644]
include/asm-um/local.h [new file with mode: 0644]
include/asm-um/module-generic.h [new file with mode: 0644]
include/asm-um/module-i386.h [new file with mode: 0644]
include/asm-um/sections.h [new file with mode: 0644]
include/linux/ghash.h [new file with mode: 0644]
include/linux/mtd/physmap.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_conntrack_pptp.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_nat_pptp.h [new file with mode: 0644]
include/linux/proc_mm.h [new file with mode: 0644]
include/linux/snmp.h [new file with mode: 0644]
include/mtd/mtd-abi.h [new file with mode: 0644]
mm/proc_mm.c [new file with mode: 0644]
mm/thrash.c [new file with mode: 0644]
net/bluetooth/hidp/core.c [new file with mode: 0644]
net/ipv4/datagram.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_pptp.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_pptp_priv.h [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_proto_gre.c [new file with mode: 0644]
net/ipv4/netfilter/ip_nat_pptp.c [new file with mode: 0644]
net/ipv4/netfilter/ip_nat_proto_gre.c [new file with mode: 0644]
net/ipv4/xfrm4_output.c [new file with mode: 0644]
net/ipv6/xfrm6_output.c [new file with mode: 0644]
net/ipv6/xfrm6_tunnel.c [new file with mode: 0644]
net/sched/sch_netem.c [new file with mode: 0644]
scripts/mkmakefile [new file with mode: 0644]
scripts/mod/Makefile [new file with mode: 0644]
scripts/mod/empty.c [new file with mode: 0644]
scripts/mod/file2alias.c [new file with mode: 0644]
scripts/mod/mk_elfconfig.c [new file with mode: 0644]
scripts/mod/modpost.c [new file with mode: 0644]
scripts/mod/modpost.h [new file with mode: 0644]
scripts/mod/sumversion.c [new file with mode: 0644]
scripts/package/Makefile [new file with mode: 0644]
scripts/package/mkspec [new file with mode: 0644]

diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt
new file mode 100644 (file)
index 0000000..111ad15
--- /dev/null
@@ -0,0 +1,534 @@
+===========================================================================
+                                  HVCS
+       IBM "Hypervisor Virtual Console Server" Installation Guide
+                         for Linux Kernel 2.6.4+
+                   Copyright (C) 2004 IBM Corporation
+
+===========================================================================
+NOTE:Eight space tabs are the optimum editor setting for reading this file.
+===========================================================================
+
+              Author(s) :  Ryan S. Arnold <rsa@us.ibm.com>
+                      Date Created: March, 02, 2004
+                      Last Changed: July, 07, 2004
+
+---------------------------------------------------------------------------
+Table of contents:
+
+       1.  Driver Introduction:
+       2.  System Requirements
+       3.  Build Options:
+               3.1  Built-in:
+               3.2  Module:
+       4.  Installation:
+       5.  Connection:
+       6.  Disconnection:
+       7.  Configuration:
+       8.  Questions & Answers:
+       9.  Reporting Bugs:
+
+---------------------------------------------------------------------------
+1. Driver Introduction:
+
+This is the device driver for the IBM Hypervisor Virtual Console Server,
+"hvcs".  The IBM hvcs provides a tty driver interface to allow Linux user
+space applications access to the system consoles of logically partitioned
+operating systems (Linux and AIX) running on the same partitioned Power5
+ppc64 system.  Physical hardware consoles per partition are not practical
+on this hardware so system consoles are accessed by this driver using
+firmware interfaces to virtual terminal devices.
+
+---------------------------------------------------------------------------
+2. System Requirements:
+
+This device driver was written using 2.6.4 Linux kernel APIs and will only
+build and run on kernels of this version or later.
+
+This driver was written to operate solely on IBM Power5 ppc64 hardware
+though some care was taken to abstract the architecture dependent firmware
+calls from the driver code.
+
+Sysfs must be mounted on the system so that the user can determine which
+major and minor numbers are associated with each vty-server.  Directions
+for sysfs mounting are outside the scope of this document.
+
+---------------------------------------------------------------------------
+3. Build Options:
+
+The hvcs driver registers itself as a tty driver.  The tty layer
+dynamically allocates a block of major and minor numbers in a quantity
+requested by the registering driver.  The hvcs driver asks the tty layer
+for 64 of these major/minor numbers by default to use for hvcs device node
+entries.
+
+If the default number of device entries is adequate then this driver can be
+built into the kernel.  If not, the default can be over-ridden by inserting
+the driver as a module with insmod parameters.
+
+---------------------------------------------------------------------------
+3.1 Built-in:
+
+The following menuconfig example demonstrates selecting to build this
+driver into the kernel.
+
+       Device Drivers  --->
+               Character devices  --->
+                       <*> IBM Hypervisor Virtual Console Server Support
+
+Begin the kernel make process.
+
+---------------------------------------------------------------------------
+3.2 Module:
+
+The following menuconfig example demonstrates selecting to build this
+driver as a kernel module.
+
+       Device Drivers  --->
+               Character devices  --->
+                       <M> IBM Hypervisor Virtual Console Server Support
+
+The make process will build the following kernel modules:
+
+       hvcs.ko
+       hvcserver.ko
+
+To insert the module with the default allocation execute the following
+commands in the order they appear:
+
+       insmod hvcserver.ko
+       insmod hvcs.ko
+
+The hvcserver module contains architecture specific firmware calls and must
+be inserted first, otherwise the hvcs module will not find some of the
+symbols it expects.
+
+To override the default use an insmod parameter as follows (requesting 4
+tty devices as an example):
+
+       insmod hvcs.ko hvcs_parm_num_devs=4
+
+There is a maximum number of dev entries that can be specified on insmod.
+We think that 1024 is currently a decent maximum number of server adapters
+to allow.  This can always be changed by modifying the constant in the
+source file before building.
+
+NOTE: The length of time it takes to insmod the driver seems to be related
+to the number of tty interfaces the registering driver requests.
+
+In order to remove the driver module execute the following command:
+
+       rmmod hvcs.ko
+
+The recommended method for installing hvcs as a module is to use depmod to
+build a current modules.dep file in /lib/modules/`uname -r` and then
+execute:
+
+modprobe hvcs hvcs_parm_num_devs=4
+
+The modules.dep file indicates that hvcserver.ko needs to be inserted
+before hvcs.ko and modprobe uses this file to smartly insert the modules in
+the proper order.
+
+The following modprobe command is used to remove hvcs and hvcserver in the
+proper order:
+
+modprobe -r hvcs
+
+---------------------------------------------------------------------------
+4. Installation:
+
+The tty layer creates sysfs entries which contain the major and minor
+numbers allocated for the hvcs driver.  The following snippet of "tree"
+output of the sysfs directory shows where these numbers are presented:
+
+       sys/
+       |-- *other sysfs base dirs*
+       |
+       |-- class
+       |   |-- *other classes of devices*
+       |   |
+       |   `-- tty
+       |       |-- *other tty devices*
+       |       |
+       |       |-- hvcs0
+       |       |   `-- dev
+       |       |-- hvcs1
+       |       |   `-- dev
+       |       |-- hvcs2
+       |       |   `-- dev
+       |       |-- hvcs3
+       |       |   `-- dev
+       |       |
+       |       |-- *other tty devices*
+       |
+       |-- *other sysfs base dirs*
+
+For the above examples the following output is a result of cat'ing the
+"dev" entry in the hvcs directory:
+
+       Pow5:/sys/class/tty/hvcs0/ # cat dev
+       254:0
+
+       Pow5:/sys/class/tty/hvcs1/ # cat dev
+       254:1
+
+       Pow5:/sys/class/tty/hvcs2/ # cat dev
+       254:2
+
+       Pow5:/sys/class/tty/hvcs3/ # cat dev
+       254:3
+
+The output from reading the "dev" attribute is the char device major and
+minor numbers that the tty layer has allocated for this driver's use.  Most
+systems running hvcs will already have the device entries created or udev
+will do it automatically.
+
+Given the example output above, to manually create a /dev/hvcs* node entry
+mknod can be used as follows:
+
+       mknod /dev/hvcs0 c 254 0
+       mknod /dev/hvcs1 c 254 1
+       mknod /dev/hvcs2 c 254 2
+       mknod /dev/hvcs3 c 254 3
+
+Using mknod to manually create the device entries makes these device nodes
+persistent.  Once created they will exist prior to the driver insmod.
+
+Attempting to connect an application to /dev/hvcs* prior to insertion of
+the hvcs module will result in an error message similar to the following:
+
+       "/dev/hvcs*: No such device".
+
+NOTE: Just because there is a device node present doesn't mean that there
+is a vty-server device configured for that node.
+
+---------------------------------------------------------------------------
+5. Connection
+
+Since this driver controls devices that provide a tty interface a user can
+interact with the device node entries using any standard tty-interactive
+method (e.g. "cat", "dd", "echo").  The intent of this driver however, is
+to provide real time console interaction with a Linux partition's console,
+which requires the use of applications that provide bi-directional,
+interactive I/O with a tty device.
+
+Applications (e.g. "minicom" and "screen") that act as terminal emulators
+or perform terminal type control sequence conversion on the data being
+passed through them are NOT acceptable for providing interactive console
+I/O.  These programs often emulate antiquated terminal types (vt100 and
+ANSI) and expect inbound data to take the form of one of these supported
+terminal types but they either do not convert, or do not _adequately_
+convert, outbound data into the terminal type of the terminal which invoked
+them (though screen makes an attempt and can apparently be configured with
+much termcap wrestling.)
+
+For this reason kermit and cu are two of the recommended applications for
+interacting with a Linux console via an hvcs device.  These programs simply
+act as a conduit for data transfer to and from the tty device.  They do not
+require inbound data to take the form of a particular terminal type, nor do
+they cook outbound data to a particular terminal type.
+
+In order to ensure proper functioning of console applications one must make
+sure that once connected to a /dev/hvcs console that the console's $TERM
+env variable is set to the exact terminal type of the terminal emulator
+used to launch the interactive I/O application.  If one is using xterm and
+kermit to connect to /dev/hvcs0 when the console prompt becomes available
+one should "export TERM=xterm" on the console.  This tells ncurses
+applications that are invoked from the console that they should output
+control sequences that xterm can understand.
+
+As a precautionary measure an hvcs user should always "exit" from their
+session before disconnecting an application such as kermit from the device
+node.  If this is not done, the next user to connect to the console will
+continue using the previous user's logged in session which includes
+using the $TERM variable that the previous user supplied.
+
+---------------------------------------------------------------------------
+6. Disconnection
+
+As a security feature to prevent the delivery of stale data to an
+unintended target the Power5 system firmware disables the fetching of data
+and discards that data when a connection between a vty-server and a vty has
+been severed.  As an example, when a vty-server is immediately disconnected
+from a vty following output of data to the vty the vty adapter may not have
+enough time between when it received the data interrupt and when the
+connection was severed to fetch the data from firmware before the fetch is
+disabled by firmware.
+
+When hvcs is being used to serve consoles this behavior is not a huge issue
+because the adapter stays connected for large amounts of time following
+almost all data writes.  When hvcs is being used as a tty conduit to tunnel
+data between two partitions [see Q & A below] this is a huge problem
+because the standard Linux behavior when cat'ing or dd'ing data to a device
+is to open the tty, send the data, and then close the tty.  If this driver
+manually terminated vty-server connections on tty close this would close
+the vty-server and vty connection before the target vty has had a chance to
+fetch the data.
+
+Additionally, disconnecting a vty-server and vty only on module removal or
+adapter removal is impractical because other vty-servers in other
+partitions may require the usage of the target vty at any time.
+
+Due to this behavioral restriction disconnection of vty-servers from the
+connected vty is a manual procedure using a write to a sysfs attribute
+outlined below, on the other hand the initial vty-server connection to a
+vty is established automatically by this driver.  Manual vty-server
+connection is never required.
+
+In order to terminate the connection between a vty-server and vty the
+"vterm_state" sysfs attribute within each vty-server's sysfs entry is used.
+Reading this attribute reveals the current connection state of the
+vty-server adapter.  A zero means that the vty-server is not connected to a
+vty.  A one indicates that a connection is active.
+
+Writing a '0' (zero) to the vterm_state attribute will disconnect the VTERM
+connection between the vty-server and target vty ONLY if the vterm_state
+previously read '1'.  The write directive is ignored if the vterm_state
+read '0' or if any value other than '0' was written to the vterm_state
+attribute.  The following example will show the method used for verifying
+the vty-server connection status and disconnecting a vty-server connection.
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # cat vterm_state
+       1
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # echo 0 > vterm_state
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # cat vterm_state
+       0
+
+All vty-server connections are automatically terminated when the device is
+hotplug removed and when the module is removed.
+
+---------------------------------------------------------------------------
+7. Configuration
+
+Each vty-server has a sysfs entry in the /sys/devices/vio directory, which
+is symlinked in several other sysfs tree directories, notably under the
+hvcs driver entry, which looks like the following example:
+
+       Pow5:/sys/bus/vio/drivers/hvcs # ls
+       .  ..  30000003  30000004  rescan
+
+By design, firmware notifies the hvcs driver of vty-server lifetimes and
+partner vty removals but not the addition of partner vtys.  Since an HMC
+Super Admin can add partner info dynamically we have provided the hvcs
+driver sysfs directory with the "rescan" update attribute which will query
+firmware and update the partner info for all the vty-servers that this
+driver manages.  Writing a '1' to the attribute triggers the update.  An
+explicit example follows:
+
+       Pow5:/sys/bus/vio/drivers/hvcs # echo 1 > rescan
+
+Reading the attribute will indicate a state of '1' or '0'.  A one indicates
+that an update is in process.  A zero indicates that an update has
+completed or was never executed.
+
+Vty-server entries in this directory are a 32 bit partition unique unit
+address that is created by firmware.  An example vty-server sysfs entry
+looks like the following:
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls
+       .   current_vty   devspec  partner_clcs  vterm_state
+       ..  detach_state  name     partner_vtys
+
+Each entry is provided, by default with a "name" attribute.  Reading the
+"name" attribute will reveal the device type as shown in the following
+example:
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000003 # cat name
+       vty-server
+
+Each entry is also provided, by default, with a "devspec" attribute which
+reveals the full device specification when read, as shown in the following
+example:
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # cat devspec
+       /vdevice/vty-server@30000004
+
+Each vty-server sysfs dir is provided with two read-only attributes that
+provide lists of easily parsed partner vty data: "partner_vtys" and
+"partner_clcs".
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # cat partner_vtys
+       30000000
+       30000001
+       30000002
+       30000000
+       30000000
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # cat partner_clcs
+       U5112.428.103048A-V3-C0
+       U5112.428.103048A-V3-C2
+       U5112.428.103048A-V3-C3
+       U5112.428.103048A-V4-C0
+       U5112.428.103048A-V5-C0
+
+Reading partner_vtys returns a list of partner vtys.  Vty unit address
+numbering is only per-partition-unique so entries will frequently repeat.
+
+Reading partner_clcs returns a list of "converged location codes" which are
+composed of a system serial number followed by "-V*", where the '*' is the
+target partition number, and "-C*", where the '*' is the slot of the
+adapter.  The first vty partner corresponds to the first clc item, the
+second vty partner to the second clc item, etc.
+
+A vty-server can only be connected to a single vty at a time.  The entry,
+"current_vty" prints the clc of the currently selected partner vty when
+read.
+
+The current_vty can be changed by writing a valid partner clc to the entry
+as in the following example:
+
+       Pow5:/sys/bus/vio/drivers/hvcs/30000004 # echo U5112.428.10304
+       8A-V4-C0 > current_vty
+
+Changing the current_vty when a vty-server is already connected to a vty
+does not affect the current connection.  The change takes effect when the
+currently open connection is freed.
+
+Information on the "vterm_state" attribute was covered earlier on the
+chapter entitled "disconnection".
+
+---------------------------------------------------------------------------
+8. Questions & Answers:
+===========================================================================
+Q: What are the security concerns involving hvcs?
+
+A: There are three main security concerns:
+
+       1. The creator of the /dev/hvcs* nodes has the ability to restrict
+       the access of the device entries to certain users or groups.  It
+       may be best to create a special hvcs group privilege for providing
+       access to system consoles.
+
+       2. To provide network security when grabbing the console it is
+       suggested that the user connect to the console hosting partition
+       using a secure method, such as SSH or sit at a hardware console.
+
+       3. Make sure to exit the user session when done with a console or
+       the next vty-server connection (which may be from another
+       partition) will experience the previously logged in session.
+
+---------------------------------------------------------------------------
+Q: How do I multiplex a console that I grab through hvcs so that other
+people can see it:
+
+A: You can use "screen" to directly connect to the /dev/hvcs* device and
+setup a session on your machine with the console group privileges.  As
+pointed out earlier by default screen doesn't provide the termcap settings
+for most terminal emulators to provide adequate character conversion from
+term type "screen" to others.  This means that curses based programs may
+not display properly in screen sessions.
+
+---------------------------------------------------------------------------
+Q: Why are the colors all messed up?
+Q: Why are the control characters acting strange or not working?
+Q: Why is the console output all strange and unintelligible?
+
+A: Please see the preceding section on "Connection" for a discussion of how
+applications can affect the display of character control sequences.
+Additionally, just because you logged into the console using and xterm
+doesn't mean someone else didn't log into the console with the HMC console
+(vt320) before you and leave the session logged in.  The best thing to do
+is to export TERM to the terminal type of your terminal emulator when you
+get the console.  Additionally make sure to "exit" the console before you
+disconnect from the console.  This will ensure that the next user gets
+their own TERM type set when they login.
+
+---------------------------------------------------------------------------
+Q: When I try to CONNECT kermit to an hvcs device I get:
+"Sorry, can't open connection: /dev/hvcs*"What is happening?
+
+A: Some other Power5 console mechanism has a connection to the vty and
+isn't giving it up.  You can try to force disconnect the consoles from the
+HMC by right clicking on the partition and then selecting "close terminal".
+Otherwise you have to hunt down the people who have console authority.  It
+is possible that you already have the console open using another kermit
+session and just forgot about it.  Please review the console options for
+Power5 systems to determine the many ways a system console can be held.
+
+OR
+
+A: Another user may not have a connectivity method currently attached to a
+/dev/hvcs device but the vterm_state may reveal that they still have the
+vty-server connection established.  They need to free this using the method
+outlined in the section on "Disconnection" in order for others to connect
+to the target vty.
+
+OR
+
+A: The user profile you are using to execute kermit probably doesn't have
+permissions to use the /dev/hvcs* device.
+
+OR
+
+A: You probably haven't inserted the hvcs.ko module yet but the /dev/hvcs*
+entry still exists (on systems without udev).
+
+OR
+
+A: There is not a corresponding vty-server device that maps to an existing
+/dev/hvcs* entry.
+
+---------------------------------------------------------------------------
+Q: When I try to CONNECT kermit to an hvcs device I get:
+"Sorry, write access to UUCP lockfile directory denied."
+
+A: The /dev/hvcs* entry you have specified doesn't exist where you said it
+does?  Maybe you haven't inserted the module (on systems with udev).
+
+---------------------------------------------------------------------------
+Q: If I already have one Linux partition installed can I use hvcs on said
+partition to provide the console for the install of a second Linux
+partition?
+
+A: Yes granted that your are connected to the /dev/hvcs* device using
+kermit or cu or some other program that doesn't provide terminal emulation.
+
+---------------------------------------------------------------------------
+Q: Can I connect to more than one partition's console at a time using this
+driver?
+
+A: Yes.  Of course this means that there must be more than one vty-server
+configured for this partition and each must point to a disconnected vty.
+
+---------------------------------------------------------------------------
+Q: Does the hvcs driver support dynamic (hotplug) addition of devices?
+
+A: Yes, if you have dlpar and hotplug enabled for your system and it has
+been built into the kernel the hvcs drivers is configured to dynamically
+handle additions of new devices and removals of unused devices.
+
+---------------------------------------------------------------------------
+Q: Can I use /dev/hvcs* as a conduit to another partition and use a tty
+device on that partition as the other end of the pipe?
+
+A: Yes, on Power5 platforms the hvc_console driver provides a tty interface
+for extra /dev/hvc* devices (where /dev/hvc0 is most likely the console).
+In order to get a tty conduit working between the two partitions the HMC
+Super Admin must create an additional "serial server" for the target
+partition with the HMC gui which will show up as /dev/hvc* when the target
+partition is rebooted.
+
+The HMC Super Admin then creates an additional "serial client" for the
+current partition and points this at the target partition's newly created
+"serial server" adapter (remember the slot).  This shows up as an
+additional /dev/hvcs* device.
+
+Now a program on the target system can be configured to read or write to
+/dev/hvc* and another program on the current partition can be configured to
+read or write to /dev/hvcs*.  Now you have a tty conduit between two
+partitions.
+
+---------------------------------------------------------------------------
+9. Reporting Bugs:
+
+The proper channel for reporting bugs is either through the Linux OS
+distribution company that provided your OS or by posting issues to the
+ppc64 development mailing list at:
+
+linuxppc64-dev@lists.linuxppc.org
+
+This request is to provide a documented and searchable public exchange
+of the problems and solutions surrounding this driver for the benefit of
+all users.
diff --git a/Documentation/powerpc/mpc52xx.txt b/Documentation/powerpc/mpc52xx.txt
new file mode 100644 (file)
index 0000000..6efe0a0
--- /dev/null
@@ -0,0 +1,48 @@
+Linux 2.6.x on MPC52xx family
+-----------------------------
+
+For the latest info, go to http://www.246tNt.com/mpc52xx/state.txt
+To compile/use :
+
+  - U-Boot:
+     # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION
+        if you wish to ).
+     # make lite5200_defconfig
+     # make uImage
+    
+     then, on U-boot:
+     => tftpboot 200000 uImage
+     => tftpboot 400000 pRamdisk
+     => bootm 200000 400000
+    
+  - DBug:
+     # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION
+        if you wish to ).
+     # make lite5200_defconfig
+     # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz
+     # make zImage.initrd 
+     # make 
+
+     then in DBug:
+     DBug> dn -i zImage.initrd.lite5200
+     
+
+Some remarks :
+ - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100
+   is not supported, and I'm not sure anyone is interesting in working on it
+   so. I didn't took 5xxx because there's apparently a lot of 5xxx that have
+   nothing to do with the MPC5200. I also included the 'MPC' for the same
+   reason.
+ - Of course, I inspired myself from the 2.4 port. If you think I forgot to
+   mention you/your company in the copyright of some code, I'll correct it
+   ASAP.
+ - The codes wants the MBAR to be set at 0xf0000000 by the bootloader. It's
+   mapped 1:1 with the MMU. If for whatever reason, you want to change this,
+   beware that some code depends on the 0xf0000000 address and other depends
+   on the 1:1 mapping.
+ - Most of the code assumes that port multiplexing, frequency selection, ...
+   has already been done. IMHO this should be done as early as possible, in
+   the bootloader. If for whatever reason you can't do it there, do it in the
+   platform setup code (if U-Boot) or in the arch/ppc/boot/simple/... (if
+   DBug)
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
new file mode 100644 (file)
index 0000000..1933c70
--- /dev/null
@@ -0,0 +1,1080 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP4xx Implementation Options
+#
+
+#
+# IXP4xx Platforms
+#
+CONFIG_ARCH_IXDP425=y
+CONFIG_ARCH_IXCDP1100=y
+CONFIG_ARCH_PRPMC1100=y
+CONFIG_ARCH_ADI_COYOTE=y
+# CONFIG_ARCH_AVILA is not set
+CONFIG_ARCH_IXDP4XX=y
+
+#
+# IXP4xx Options
+#
+# CONFIG_IXP4XX_INDIRECT_PCI is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+
+#
+# OMAP Board Type
+#
+
+#
+# OMAP Feature Selections
+#
+
+#
+# S3C2410 Implementations
+#
+
+#
+# LH7A40X Implementations
+#
+CONFIG_DMABOUNCE=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP4XX=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=m
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+CONFIG_IP_VS_DEBUG=y
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+# CONFIG_IP_VS_PROTO_TCP is not set
+# CONFIG_IP_VS_PROTO_UDP is not set
+# CONFIG_IP_VS_PROTO_ESP is not set
+# CONFIG_IP_VS_PROTO_AH is not set
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+# CONFIG_IP_VS_SED is not set
+# CONFIG_IP_VS_NQ is not set
+
+#
+# IPVS application helper
+#
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_PHYSDEV is not set
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+# CONFIG_IP_NF_TARGET_CLASSIFY is not set
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+# CONFIG_IP_NF_ARP_MANGLE is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+# CONFIG_IP_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+# CONFIG_NET_DIVERT is not set
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_CSZ=m
+# CONFIG_NET_SCH_ATM is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_DELAY is not set
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+CONFIG_HERMES=y
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+CONFIG_PCI_HERMES=y
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+CONFIG_HDLC_X25=y
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_WAN_ROUTER_DRIVERS=y
+# CONFIG_CYCLADES_SYNC is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP4XX_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+CONFIG_I2C_IXP4XX=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig
new file mode 100644 (file)
index 0000000..4ab6e26
--- /dev/null
@@ -0,0 +1,713 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+CONFIG_MACH_MAINSTONE=y
+# CONFIG_ARCH_PXA_IDP is not set
+CONFIG_PXA27x=y
+CONFIG_IWMMXT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PXA2XX=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+# CONFIG_MTD_CFI_B2 is not set
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/smdk2410_defconfig b/arch/arm/configs/smdk2410_defconfig
new file mode 100644 (file)
index 0000000..1309997
--- /dev/null
@@ -0,0 +1,666 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+CONFIG_ARCH_S3C2410=y
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+
+#
+# OMAP Board Type
+#
+
+#
+# OMAP Feature Selections
+#
+
+#
+# S3C2410 Implementations
+#
+# CONFIG_ARCH_BAST is not set
+# CONFIG_ARCH_H1940 is not set
+CONFIG_ARCH_SMDK2410=y
+# CONFIG_MACH_VR1000 is not set
+
+#
+# LH7A40X Implementations
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+
+#
+# At least one math emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="root=1f04 mem=32M"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_CONCAT is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_S3C2410=y
+CONFIG_SERIAL_S3C2410_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_LL_PRINTK=y
+CONFIG_DEBUG_S3C2410_PORT=y
+CONFIG_DEBUG_S3C2410_UART=0
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
new file mode 100644 (file)
index 0000000..6645218
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * arch/arm/mach-ixp4xx/common-pci.c 
+ *
+ * IXP4XX PCI routines for all platforms
+ *
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <asm/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/system.h>
+#include <asm/mach/pci.h>
+#include <asm/hardware.h>
+#include <asm/sizes.h>
+
+
+/*
+ * IXP4xx PCI read function is dependent on whether we are 
+ * running A0 or B0 (AppleGate) silicon.
+ */
+int (*ixp4xx_pci_read)(u32 addr, u32 cmd, u32* data);
+
+/*
+ * Base address for PCI regsiter region
+ */
+unsigned long ixp4xx_pci_reg_base = 0;
+
+/*
+ * PCI cfg an I/O routines are done by programming a 
+ * command/byte enable register, and then read/writing
+ * the data from a data regsiter. We need to ensure
+ * these transactions are atomic or we will end up
+ * with corrupt data on the bus or in a driver.
+ */
+static spinlock_t ixp4xx_pci_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Read from PCI config space
+ */
+static void crp_read(u32 ad_cbe, u32 *data)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+       *PCI_CRP_AD_CBE = ad_cbe;
+       *data = *PCI_CRP_RDATA;
+       spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+}
+
+/*
+ * Write to PCI config space
+ */
+static void crp_write(u32 ad_cbe, u32 data)
+{ 
+       unsigned long flags;
+       spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+       *PCI_CRP_AD_CBE = CRP_AD_CBE_WRITE | ad_cbe;
+       *PCI_CRP_WDATA = data;
+       spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+}
+
+static inline int check_master_abort(void)
+{
+       /* check Master Abort bit after access */
+       unsigned long isr = *PCI_ISR;
+
+       if (isr & PCI_ISR_PFE) {
+               /* make sure the Master Abort bit is reset */    
+               *PCI_ISR = PCI_ISR_PFE;
+               pr_debug("%s failed\n", __FUNCTION__);
+               return 1;
+       }
+
+       return 0;
+}
+
+int ixp4xx_pci_read_errata(u32 addr, u32 cmd, u32* data)
+{
+       unsigned long flags;
+       int retval = 0;
+       int i;
+
+       spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+
+       *PCI_NP_AD = addr;
+
+       /* 
+        * PCI workaround  - only works if NP PCI space reads have 
+        * no side effects!!! Read 8 times. last one will be good.
+        */
+       for (i = 0; i < 8; i++) {
+               *PCI_NP_CBE = cmd;
+               *data = *PCI_NP_RDATA;
+               *data = *PCI_NP_RDATA;
+       }
+
+       if(check_master_abort())
+               retval = 1;
+
+       spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+       return retval;
+}
+
+int ixp4xx_pci_read_no_errata(u32 addr, u32 cmd, u32* data)
+{
+       unsigned long flags;
+       int retval = 0;
+
+       spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+
+       *PCI_NP_AD = addr;
+
+       /* set up and execute the read */    
+       *PCI_NP_CBE = cmd;
+
+       /* the result of the read is now in NP_RDATA */
+       *data = *PCI_NP_RDATA; 
+
+       if(check_master_abort())
+               retval = 1;
+
+       spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+       return retval;
+}
+
+int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data)
+{    
+       unsigned long flags;
+       int retval = 0;
+
+       spin_lock_irqsave(&ixp4xx_pci_lock, flags);
+
+       *PCI_NP_AD = addr;
+
+       /* set up the write */
+       *PCI_NP_CBE = cmd;
+
+       /* execute the write by writing to NP_WDATA */
+       *PCI_NP_WDATA = data;
+
+       if(check_master_abort())
+               retval = 1;
+
+       spin_unlock_irqrestore(&ixp4xx_pci_lock, flags);
+       return retval;
+}
+
+static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where)
+{
+       u32 addr;
+       if (!bus_num) {
+               /* type 0 */
+               addr = BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | 
+                   (where & ~3);       
+       } else {
+               /* type 1 */
+               addr = (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | 
+                       ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1;
+       }
+       return addr;
+}
+
+/*
+ * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
+ * 0 and 3 are not valid indexes...
+ */
+static u32 bytemask[] = {
+       /*0*/   0,
+       /*1*/   0xff,
+       /*2*/   0xffff,
+       /*3*/   0,
+       /*4*/   0xffffffff,
+};
+
+static u32 local_byte_lane_enable_bits(u32 n, int size)
+{
+       if (size == 1)
+               return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL;
+       if (size == 2)
+               return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL;
+       if (size == 4)
+               return 0;
+       return 0xffffffff;
+}
+
+static int local_read_config(int where, int size, u32 *value)
+{ 
+       u32 n, data;
+       pr_debug("local_read_config from %d size %d\n", where, size);
+       n = where % 4;
+       crp_read(where & ~3, &data);
+       *value = (data >> (8*n)) & bytemask[size];
+       pr_debug("local_read_config read %#x\n", *value);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int local_write_config(int where, int size, u32 value)
+{
+       u32 n, byte_enables, data;
+       pr_debug("local_write_config %#x to %d size %d\n", value, where, size);
+       n = where % 4;
+       byte_enables = local_byte_lane_enable_bits(n, size);
+       if (byte_enables == 0xffffffff)
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       data = value << (8*n);
+       crp_write((where & ~3) | byte_enables, data);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static u32 byte_lane_enable_bits(u32 n, int size)
+{
+       if (size == 1)
+               return (0xf & ~BIT(n)) << 4;
+       if (size == 2)
+               return (0xf & ~(BIT(n) | BIT(n+1))) << 4;
+       if (size == 4)
+               return 0;
+       return 0xffffffff;
+}
+
+static int read_config(u8 bus_num, u16 devfn, int where, int size, u32 *value)
+{
+       u32 n, byte_enables, addr, data;
+
+       pr_debug("read_config from %d size %d dev %d:%d:%d\n", where, size,
+               bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+       *value = 0xffffffff;
+       n = where % 4;
+       byte_enables = byte_lane_enable_bits(n, size);
+       if (byte_enables == 0xffffffff)
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       addr = ixp4xx_config_addr(bus_num, devfn, where);
+       if (ixp4xx_pci_read(addr, byte_enables | NP_CMD_CONFIGREAD, &data))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       *value = (data >> (8*n)) & bytemask[size];
+       pr_debug("read_config_byte read %#x\n", *value);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int write_config(u8 bus_num, u16 devfn, int where, int size, u32 value)
+{
+       u32 n, byte_enables, addr, data;
+
+       pr_debug("write_config_byte %#x to %d size %d dev %d:%d:%d\n", value, where,
+               size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+       n = where % 4;
+       byte_enables = byte_lane_enable_bits(n, size);
+       if (byte_enables == 0xffffffff)
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       addr = ixp4xx_config_addr(bus_num, devfn, where);
+       data = value << (8*n);
+       if (ixp4xx_pci_write(addr, byte_enables | NP_CMD_CONFIGWRITE, data))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ *     Generalized PCI config access functions.
+ */
+static int ixp4xx_read_config(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 *value)
+{
+       if (bus->number && !PCI_SLOT(devfn))
+               return local_read_config(where, size, value);
+       return read_config(bus->number, devfn, where, size, value);
+}
+
+static int ixp4xx_write_config(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 value)
+{
+       if (bus->number && !PCI_SLOT(devfn))
+               return local_write_config(where, size, value);
+       return write_config(bus->number, devfn, where, size, value);
+}
+
+struct pci_ops ixp4xx_ops = {
+       .read =  ixp4xx_read_config,
+       .write = ixp4xx_write_config,
+};
+
+
+/*
+ * PCI abort handler
+ */
+static int abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+       u32 isr, status;
+
+       isr = *PCI_ISR;
+       local_read_config(PCI_STATUS, 2, &status);
+       pr_debug("PCI: abort_handler addr = %#lx, isr = %#x, "
+               "status = %#x\n", addr, isr, status);
+
+       /* make sure the Master Abort bit is reset */    
+       *PCI_ISR = PCI_ISR_PFE;
+       status |= PCI_STATUS_REC_MASTER_ABORT;
+       local_write_config(PCI_STATUS, 2, status);
+
+       /*
+        * If it was an imprecise abort, then we need to correct the
+        * return address to be _after_ the instruction.
+        */
+       if (fsr & (1 << 10))
+               regs->ARM_pc += 4;
+
+       return 0;
+}
+
+
+/*
+ * Setup DMA mask to 64MB on PCI devices. Ignore all other devices.
+ */
+static int ixp4xx_pci_platform_notify(struct device *dev)
+{
+       if(dev->bus == &pci_bus_type) {
+               *dev->dma_mask =  SZ_64M - 1;
+               dev->coherent_dma_mask = SZ_64M - 1;
+               dmabounce_register_dev(dev, 2048, 4096);
+       }
+       return 0;
+}
+
+static int ixp4xx_pci_platform_notify_remove(struct device *dev)
+{
+       if(dev->bus == &pci_bus_type) {
+               dmabounce_unregister_dev(dev);
+       }
+       return 0;
+}
+
+int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
+{
+       return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M);
+}
+
+void __init ixp4xx_pci_preinit(void)
+{  
+       unsigned long processor_id;
+
+       asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
+
+       /*
+        * Determine which PCI read method to use
+        */
+       if (!(processor_id & 0xf)) {
+               printk("PCI: IXP4xx A0 silicon detected - "
+                       "PCI Non-Prefetch Workaround Enabled\n");
+               ixp4xx_pci_read = ixp4xx_pci_read_errata;
+       } else
+               ixp4xx_pci_read = ixp4xx_pci_read_no_errata;
+
+
+       /* hook in our fault handler for PCI errors */
+       hook_fault_code(16+6, abort_handler, SIGBUS, "imprecise external abort");
+
+       pr_debug("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n");
+
+       /* 
+        * We use identity AHB->PCI address translation
+        * in the 0x48000000 to 0x4bffffff address space
+        */
+       *PCI_PCIMEMBASE = 0x48494A4B;
+
+       /* 
+        * We also use identity PCI->AHB address translation
+        * in 4 16MB BARs that begin at the physical memory start
+        */
+       *PCI_AHBMEMBASE = (PHYS_OFFSET & 0xFF000000) + 
+               ((PHYS_OFFSET & 0xFF000000) >> 8) +
+               ((PHYS_OFFSET & 0xFF000000) >> 16) +
+               ((PHYS_OFFSET & 0xFF000000) >> 24) +
+               0x00010203;
+
+       if (*PCI_CSR & PCI_CSR_HOST) {
+               printk("PCI: IXP4xx is host\n");
+
+               pr_debug("setup BARs in controller\n");
+
+               /*
+                * We configure the PCI inbound memory windows to be 
+                * 1:1 mapped to SDRAM
+                */
+               local_write_config(PCI_BASE_ADDRESS_0, 4, PHYS_OFFSET + 0x00000000);
+               local_write_config(PCI_BASE_ADDRESS_1, 4, PHYS_OFFSET + 0x01000000);
+               local_write_config(PCI_BASE_ADDRESS_2, 4, PHYS_OFFSET + 0x02000000);
+               local_write_config(PCI_BASE_ADDRESS_3, 4, PHYS_OFFSET + 0x03000000);
+
+               /*
+                * Enable CSR window at 0xff000000.
+                */
+               local_write_config(PCI_BASE_ADDRESS_4, 4, 0xff000008);
+
+               /*
+                * Enable the IO window to be way up high, at 0xfffffc00
+                */
+               local_write_config(PCI_BASE_ADDRESS_5, 4, 0xfffffc01);
+       } else {
+               printk("PCI: IXP4xx is target - No bus scan performed\n");
+       }
+
+       printk("PCI: IXP4xx Using %s access for memory space\n",
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+                       "direct"
+#else
+                       "indirect"
+#endif
+               );
+
+       pr_debug("clear error bits in ISR\n");
+       *PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE;
+
+       /*
+        * Set Initialize Complete in PCI Control Register: allow IXP4XX to
+        * respond to PCI configuration cycles. Specify that the AHB bus is
+        * operating in big endian mode. Set up byte lane swapping between 
+        * little-endian PCI and the big-endian AHB bus 
+        */
+#ifdef __ARMEB__
+       *PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS;
+#else
+       *PCI_CSR = PCI_CSR_IC;
+#endif
+
+       pr_debug("DONE\n");
+}
+
+int ixp4xx_setup(int nr, struct pci_sys_data *sys)
+{
+       struct resource *res;
+
+       if (nr >= 1)
+               return 0;
+
+       res = kmalloc(sizeof(*res) * 2, GFP_KERNEL);
+       if (res == NULL) {
+               /* 
+                * If we're out of memory this early, something is wrong,
+                * so we might as well catch it here.
+                */
+               panic("PCI: unable to allocate resources?\n");
+       }
+       memset(res, 0, sizeof(*res) * 2);
+
+       local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+
+       res[0].name = "PCI I/O Space";
+       res[0].start = 0x00001000;
+       res[0].end = 0xffff0000;
+       res[0].flags = IORESOURCE_IO;
+
+       res[1].name = "PCI Memory Space";
+       res[1].start = 0x48000000;
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+       res[1].end = 0x4bffffff;
+#else
+       res[1].end = 0x4fffffff;
+#endif
+       res[1].flags = IORESOURCE_MEM;
+
+       request_resource(&ioport_resource, &res[0]);
+       request_resource(&iomem_resource, &res[1]);
+
+       sys->resource[0] = &res[0];
+       sys->resource[1] = &res[1];
+       sys->resource[2] = NULL;
+
+       platform_notify = ixp4xx_pci_platform_notify;
+       platform_notify_remove = ixp4xx_pci_platform_notify_remove;
+
+       return 1;
+}
+
+struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys)
+{
+       return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
+}
+
+/*
+ * We override these so we properly do dmabounce otherwise drivers
+ * are able to set the dma_mask to 0xffffffff and we can no longer
+ * trap bounces. :(
+ *
+ * We just return true on everyhing except for < 64MB in which case 
+ * we will fail miseralby and die since we can't handle that case.
+ */
+int
+pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       if (mask >= SZ_64M - 1 )
+               return 0;
+
+       return -EIO;
+}
+    
+int
+pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       if (mask >= SZ_64M - 1 )
+               return 0;
+
+       return -EIO;
+}
+
+int
+pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       if (mask >= SZ_64M - 1 )
+               return 0;
+
+       return -EIO;
+}
+
+EXPORT_SYMBOL(pci_set_dma_mask);
+EXPORT_SYMBOL(pci_dac_set_dma_mask);
+EXPORT_SYMBOL(pci_set_consistent_dma_mask);
+EXPORT_SYMBOL(ixp4xx_pci_read);
+EXPORT_SYMBOL(ixp4xx_pci_write);
+
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
new file mode 100644 (file)
index 0000000..03ad0b7
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/arm/mach-ixp4xx/coyote-setup.c
+ *
+ * ADI Engineering Coyote board-setup 
+ *
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+#ifdef __ARMEB__
+#define        REG_OFFSET      3
+#else
+#define        REG_OFFSET      0
+#endif
+
+/*
+ * Only one serial port is connected on the Coyote.
+ */
+static struct uart_port coyote_serial_port = {
+       .membase        = (char*)(IXP4XX_UART2_BASE_VIRT + REG_OFFSET),
+       .mapbase        = (IXP4XX_UART2_BASE_PHYS),
+       .irq            = IRQ_IXP4XX_UART2,
+       .flags          = UPF_SKIP_TEST,
+       .iotype         = UPIO_MEM,     
+       .regshift       = 2,
+       .uartclk        = IXP4XX_UART_XTAL,
+       .line           = 0,
+       .type           = PORT_XSCALE,
+       .fifosize       = 32
+};
+
+void __init coyote_map_io(void)
+{
+       early_serial_setup(&coyote_serial_port);
+
+       ixp4xx_map_io();
+}
+
+static struct flash_platform_data coyote_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+};
+
+static struct resource coyote_flash_resource = {
+       .start          = COYOTE_FLASH_BASE,
+       .end            = COYOTE_FLASH_BASE + COYOTE_FLASH_SIZE,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device coyote_flash = {
+       .name           = "IXP4XX-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &coyote_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &coyote_flash_resource,
+};
+
+static struct platform_device *coyote_devices[] __initdata = {
+       &coyote_flash
+};
+
+static void __init coyote_init(void)
+{
+       platform_add_devices(&coyote_devices, ARRAY_SIZE(coyote_devices));
+}
+
+MACHINE_START(ADI_COYOTE, "ADI Engineering IXP4XX Coyote Development Platform")
+        MAINTAINER("MontaVista Software, Inc.")
+        BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
+                IXP4XX_PERIPHERAL_BASE_VIRT)
+        MAPIO(coyote_map_io)
+        INITIRQ(ixp4xx_init_irq)
+       INITTIME(ixp4xx_init_time)
+        BOOT_PARAMS(0x0100)
+       INIT_MACHINE(coyote_init)
+MACHINE_END
+
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
new file mode 100644 (file)
index 0000000..dbcaa46
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * arch/arm/mach-ixp4xx/ixdp425-setup.c
+ *
+ * IXDP425/IXCDP1100 board-setup 
+ *
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+#ifdef __ARMEB__
+#define        REG_OFFSET      3
+#else
+#define        REG_OFFSET      0
+#endif
+
+/*
+ * IXDP425 uses both chipset serial ports
+ */
+static struct uart_port ixdp425_serial_ports[] = {
+       {
+               .membase        = (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET),
+               .mapbase        = (IXP4XX_UART1_BASE_PHYS),
+               .irq            = IRQ_IXP4XX_UART1,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,     
+               .regshift       = 2,
+               .uartclk        = IXP4XX_UART_XTAL,
+               .line           = 0,
+               .type           = PORT_XSCALE,
+               .fifosize       = 32
+       } , {
+               .membase        = (char*)(IXP4XX_UART2_BASE_VIRT + REG_OFFSET),
+               .mapbase        = (IXP4XX_UART2_BASE_PHYS),
+               .irq            = IRQ_IXP4XX_UART2,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,     
+               .regshift       = 2,
+               .uartclk        = IXP4XX_UART_XTAL,
+               .line           = 1,
+               .type           = PORT_XSCALE,
+               .fifosize       = 32
+       }
+};
+
+void __init ixdp425_map_io(void) 
+{
+       early_serial_setup(&ixdp425_serial_ports[0]);
+       early_serial_setup(&ixdp425_serial_ports[1]);
+
+       ixp4xx_map_io();
+}
+
+static struct flash_platform_data ixdp425_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+};
+
+static struct resource ixdp425_flash_resource = {
+       .start          = IXDP425_FLASH_BASE,
+       .end            = IXDP425_FLASH_BASE + IXDP425_FLASH_SIZE,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp425_flash = {
+       .name           = "IXP4XX-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp425_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &ixdp425_flash_resource,
+};
+
+static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = {
+       .sda_pin        = IXDP425_SDA_PIN,
+       .scl_pin        = IXDP425_SCL_PIN,
+};
+
+static struct platform_device ixdp425_i2c_controller = {
+       .name           = "IXP4XX-I2C",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp425_i2c_gpio_pins,
+       },
+       .num_resources  = 0
+};
+
+static struct platform_device *ixdp425_devices[] __initdata = {
+       &ixdp425_i2c_controller,
+       &ixdp425_flash
+};
+
+static void __init ixdp425_init(void)
+{
+       platform_add_devices(&ixdp425_devices, ARRAY_SIZE(ixdp425_devices));
+}
+
+MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
+               IXP4XX_PERIPHERAL_BASE_VIRT)
+       MAPIO(ixdp425_map_io)
+       INITIRQ(ixp4xx_init_irq)
+       INITTIME(ixp4xx_init_time)
+       BOOT_PARAMS(0x0100)
+       INIT_MACHINE(ixdp425_init)
+MACHINE_END
+
+MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
+               IXP4XX_PERIPHERAL_BASE_VIRT)
+       MAPIO(ixdp425_map_io)
+       INITIRQ(ixp4xx_init_irq)
+       INITTIME(ixp4xx_init_time)
+       BOOT_PARAMS(0x0100)
+       INIT_MACHINE(ixdp425_init)
+MACHINE_END
+
+/*
+ * Avila is functionally equivalent to IXDP425 except that it adds
+ * a CF IDE slot hanging off the expansion bus. When we have a 
+ * driver for IXP4xx CF IDE with driver model support we'll move
+ * Avila to it's own setup file.
+ */
+#ifdef CONFIG_ARCH_AVILA
+MACHINE_START(AVILA, "Gateworks Avila Network Platform")
+       MAINTAINER("Deepak Saxena <dsaxena@plexity.net>")
+       BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
+               IXP4XX_PERIPHERAL_BASE_VIRT)
+       MAPIO(ixdp425_map_io)
+       INITIRQ(ixp4xx_init_irq)
+       INITTIME(ixp4xx_init_time)
+       BOOT_PARAMS(0x0100)
+       INIT_MACHINE(ixdp425_init)
+MACHINE_END
+#endif
+
diff --git a/arch/arm/mach-ixp4xx/prpmc1100-setup.c b/arch/arm/mach-ixp4xx/prpmc1100-setup.c
new file mode 100644 (file)
index 0000000..01e98fd
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/arm/mach-ixp4xx/prpmc1100-setup.c
+ *
+ * Motorola PrPMC1100 board setup
+ *
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+#ifdef __ARMEB__
+#define        REG_OFFSET      3
+#else
+#define        REG_OFFSET      0
+#endif
+
+/*
+ * Only one serial port is connected on the PrPMC1100
+ */
+static struct uart_port prpmc1100_serial_port = {
+       .membase        = (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET),
+       .mapbase        = (IXP4XX_UART1_BASE_PHYS),
+       .irq            = IRQ_IXP4XX_UART1,
+       .flags          = UPF_SKIP_TEST,
+       .iotype         = UPIO_MEM,     
+       .regshift       = 2,
+       .uartclk        = IXP4XX_UART_XTAL,
+       .line           = 0,
+       .type           = PORT_XSCALE,
+       .fifosize       = 32
+};
+
+void __init prpmc1100_map_io(void)
+{
+       early_serial_setup(&prpmc1100_serial_port);
+
+       ixp4xx_map_io();
+}
+
+static struct flash_platform_data prpmc1100_flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+};
+
+static struct resource prpmc1100_flash_resource = {
+       .start          = PRPMC1100_FLASH_BASE,
+       .end            = PRPMC1100_FLASH_BASE + PRPMC1100_FLASH_SIZE,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device prpmc1100_flash = {
+       .name           = "IXP4XX-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &prpmc1100_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &prpmc1100_flash_resource,
+};
+
+static struct platform_device *prpmc1100_devices[] __initdata = {
+       &prpmc1100_flash
+};
+
+static void __init prpmc1100_init(void)
+{
+       platform_add_devices(&prpmc1100_devices, ARRAY_SIZE(prpmc1100_devices));
+}
+
+MACHINE_START(PRPMC1100, "Motorola PrPMC1100")
+        MAINTAINER("MontaVista Software, Inc.")
+        BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
+                IXP4XX_PERIPHERAL_BASE_VIRT)
+        MAPIO(prpmc1100_map_io)
+        INITIRQ(ixp4xx_init_irq)
+       INITTIME(ixp4xx_init_time)
+        BOOT_PARAMS(0x0100)
+       INIT_MACHINE(prpmc1100_init)
+MACHINE_END
+
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
new file mode 100644 (file)
index 0000000..450b132
--- /dev/null
@@ -0,0 +1,98 @@
+/* linux/arch/arm/mach-s3c2410/gpio.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 GPIO support
+ *
+ * This program is free software; 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
+{
+       unsigned long base = S3C2410_GPIO_BASE(pin);
+       unsigned long shift = 1;
+       unsigned long mask = 3;
+       unsigned long con;
+       unsigned long flags;
+
+       if (pin < S3C2410_GPIO_BANKB) {
+               shift = 0;
+               mask  = 1;
+       }
+
+       mask <<= S3C2410_GPIO_OFFSET(pin);
+
+       local_irq_save(flags);
+
+       con = __raw_readl(base + 0x00);
+
+       con &= mask << shift;
+       con |= function;
+
+       __raw_writel(con, base + 0x00);
+
+       local_irq_restore(flags);
+}
+
+void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
+{
+       unsigned long base = S3C2410_GPIO_BASE(pin);
+       unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+       unsigned long flags;
+       unsigned long up;
+
+       if (pin < S3C2410_GPIO_BANKB)
+               return;
+
+       local_irq_save(flags);
+
+       up = __raw_readl(base + 0x08);
+       up &= 1 << offs;
+       up |= to << offs;
+       __raw_writel(up, base + 0x08);
+
+       local_irq_restore(flags);
+}
+
+void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
+{
+       unsigned long base = S3C2410_GPIO_BASE(pin);
+       unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+       unsigned long flags;
+       unsigned long dat;
+
+       local_irq_save(flags);
+
+       dat = __raw_readl(base + 0x04);
+       dat &= 1 << offs;
+       dat |= to << offs;
+       __raw_writel(dat, base + 0x04);
+
+       local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
new file mode 100644 (file)
index 0000000..bfadbd4
--- /dev/null
@@ -0,0 +1,115 @@
+/***********************************************************************
+ *
+ * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
+ *
+ * Copyright (C) 2004 by FS Forth-Systeme GmbH
+ * All rights reserved.
+ *
+ * $Id: mach-smdk2410.c,v 1.1 2004/05/11 14:15:38 mpietrek Exp $
+ * @Author: Jonas Dietsche
+ *
+ * This program is free software; 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
+ *
+ * @History:
+ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
+ * Ben Dooks <ben@simtec.co.uk>
+ ***********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+
+#include "s3c2410.h"
+
+
+static struct map_desc smdk2410_iodesc[] __initdata = {
+  /* nothing here yet */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+/* base baud rate for all our UARTs */
+static unsigned long smdk2410_serial_clock = 24*1000*1000;
+
+static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .clock       = &smdk2410_serial_clock,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .clock       = &smdk2410_serial_clock,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .clock       = &smdk2410_serial_clock,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+
+void __init smdk2410_map_io(void)
+{
+       s3c2410_map_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
+       s3c2410_uartcfgs = smdk2410_uartcfgs;
+}
+
+void __init smdk2410_init_irq(void)
+{
+       s3c2410_init_irq();
+}
+
+void __init smdk2410_init_time(void)
+{
+       s3c2410_init_time();
+}
+
+MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
+                                   * to SMDK2410 */
+     MAINTAINER("Jonas Dietsche")
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+     MAPIO(smdk2410_map_io)
+     INITIRQ(smdk2410_init_irq)
+     INITTIME(smdk2410_init_time)
+MACHINE_END
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
new file mode 100644 (file)
index 0000000..23bf73e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * linux/arch/arm/mach-sa1100/collie.c
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains all Collie-specific tweaks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ChangeLog:
+ *  03-06-2004 John Lenz <jelenz@wisc.edu>
+ *  06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
+ *  04-16-2001 Lineo Japan,Inc. ...
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/timer.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/arch/collie.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include <asm/hardware/locomo.h>
+
+#include "generic.h"
+
+static void __init scoop_init(void)
+{
+
+#define        COLLIE_SCP_INIT_DATA(adr,dat)   (((adr)<<16)|(dat))
+#define        COLLIE_SCP_INIT_DATA_END        ((unsigned long)-1)
+       static const unsigned long scp_init[] = {
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_MCR, 0x0140),   // 00
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_MCR, 0x0100),
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_CDR, 0x0000),   // 04
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_CPR, 0x0000),   // 0C
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_CCR, 0x0000),   // 10
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_IMR, 0x0000),   // 18
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_IRM, 0x00FF),   // 14
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_ISR, 0x0000),   // 1C
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_IRM, 0x0000),
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_GPCR, COLLIE_SCP_IO_DIR),       // 20
+               COLLIE_SCP_INIT_DATA(COLLIE_SCP_GPWR, COLLIE_SCP_IO_OUT),       // 24
+               COLLIE_SCP_INIT_DATA_END
+       };
+       int i;
+       for (i = 0; scp_init[i] != COLLIE_SCP_INIT_DATA_END; i++) {
+               int adr = scp_init[i] >> 16;
+               COLLIE_SCP_REG(adr) = scp_init[i] & 0xFFFF;
+       }
+
+}
+
+static struct resource locomo_resources[] = {
+       [0] = {
+               .start          = 0x40000000,
+               .end            = 0x40001fff,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IRQ_GPIO25,
+               .end            = IRQ_GPIO25,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device locomo_device = {
+       .name           = "locomo",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(locomo_resources),
+       .resource       = locomo_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &locomo_device,
+};
+
+static void __init collie_init(void)
+{
+       int ret = 0;
+
+       /* cpu initialize */
+       GAFR = ( GPIO_SSP_TXD | \
+                GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK | GPIO_TIC_ACK | \
+                GPIO_32_768kHz );
+
+       GPDR = ( GPIO_LDD8 | GPIO_LDD9 | GPIO_LDD10 | GPIO_LDD11 | GPIO_LDD12 | \
+                GPIO_LDD13 | GPIO_LDD14 | GPIO_LDD15 | GPIO_SSP_TXD | \
+                GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SDLC_SCLK | \
+                GPIO_SDLC_AAF | GPIO_UART_SCLK1 | GPIO_32_768kHz );
+       GPLR = GPIO_GPIO18;
+
+       // PPC pin setting
+       PPDR = ( PPC_LDD0 | PPC_LDD1 | PPC_LDD2 | PPC_LDD3 | PPC_LDD4 | PPC_LDD5 | \
+                PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | \
+                PPC_TXD1 | PPC_TXD2 | PPC_RXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM );
+
+       PSDR = ( PPC_RXD1 | PPC_RXD2 | PPC_RXD3 | PPC_RXD4 );
+
+       GAFR |= GPIO_32_768kHz;
+       GPDR |= GPIO_32_768kHz;
+       TUCR  = TUCR_32_768kHz;
+
+       scoop_init();
+
+       ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+       if (ret) {
+               printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
+       }
+}
+
+static struct map_desc collie_io_desc[] __initdata = {
+       /* virtual     physical    length      type */
+       {0xe8000000, 0x00000000, 0x02000000, MT_DEVICE},        /* 32M main flash (cs0) */
+       {0xea000000, 0x08000000, 0x02000000, MT_DEVICE},        /* 32M boot flash (cs1) */
+       {0xf0000000, 0x40000000, 0x01000000, MT_DEVICE},        /* 16M LOCOMO  & SCOOP (cs4) */
+};
+
+static void __init collie_map_io(void)
+{
+       sa1100_map_io();
+       iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
+}
+
+MACHINE_START(COLLIE, "Sharp-Collie")
+       BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+       MAPIO(collie_map_io)
+       INITIRQ(sa1100_init_irq)
+       INIT_MACHINE(collie_init)
+       INITTIME(sa1100_init_time)
+MACHINE_END
diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile
new file mode 100644 (file)
index 0000000..103c353
--- /dev/null
@@ -0,0 +1,9 @@
+# 
+# i386/crypto/Makefile 
+# 
+# Arch-specific CryptoAPI modules.
+# 
+
+obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
+
+aes-i586-y := aes-i586-asm.o aes.o
diff --git a/arch/i386/crypto/aes-i586-asm.S b/arch/i386/crypto/aes-i586-asm.S
new file mode 100644 (file)
index 0000000..e8a0471
--- /dev/null
@@ -0,0 +1,341 @@
+// -------------------------------------------------------------------------
+// Copyright (c) 2001, Dr Brian Gladman <                 >, Worcester, UK.
+// All rights reserved.
+//
+// LICENSE TERMS
+//
+// The free distribution and use of this software in both source and binary 
+// form is allowed (with or without changes) provided that:
+//
+//   1. distributions of this source code include the above copyright 
+//      notice, this list of conditions and the following disclaimer//
+//
+//   2. distributions in binary form include the above copyright
+//      notice, this list of conditions and the following disclaimer
+//      in the documentation and/or other associated materials//
+//
+//   3. the copyright holder's name is not used to endorse products 
+//      built using this software without specific written permission.
+//
+//
+// ALTERNATIVELY, provided that this notice is retained in full, this product
+// may be distributed under the terms of the GNU General Public License (GPL),
+// in which case the provisions of the GPL apply INSTEAD OF those given above.
+//
+// Copyright (c) 2004 Linus Torvalds <torvalds@osdl.org>
+// Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
+
+// DISCLAIMER
+//
+// This software is provided 'as is' with no explicit or implied warranties
+// in respect of its properties including, but not limited to, correctness 
+// and fitness for purpose.
+// -------------------------------------------------------------------------
+// Issue Date: 29/07/2002
+
+.file "aes-i586-asm.S"
+.text
+
+// aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])//
+// aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])//
+       
+#define tlen 1024   // length of each of 4 'xor' arrays (256 32-bit words)
+
+// offsets to parameters with one register pushed onto stack
+
+#define in_blk    8  // input byte array address parameter
+#define out_blk  12  // output byte array address parameter
+#define ctx      16  // AES context structure
+
+// offsets in context structure
+
+#define ekey     0   // encryption key schedule base address
+#define nrnd   256   // number of rounds
+#define dkey   260   // decryption key schedule base address
+
+// register mapping for encrypt and decrypt subroutines
+
+#define r0  eax
+#define r1  ebx
+#define r2  ecx
+#define r3  edx
+#define r4  esi
+#define r5  edi
+#define r6  ebp
+
+#define eaxl  al
+#define eaxh  ah
+#define ebxl  bl
+#define ebxh  bh
+#define ecxl  cl
+#define ecxh  ch
+#define edxl  dl
+#define edxh  dh
+
+#define _h(reg) reg##h
+#define h(reg) _h(reg)
+
+#define _l(reg) reg##l
+#define l(reg) _l(reg)
+
+// This macro takes a 32-bit word representing a column and uses
+// each of its four bytes to index into four tables of 256 32-bit
+// words to obtain values that are then xored into the appropriate
+// output registers r0, r1, r4 or r5.  
+
+// Parameters:
+//   %1  out_state[0]
+//   %2  out_state[1]
+//   %3  out_state[2]
+//   %4  out_state[3]
+//   %5  table base address
+//   %6  input register for the round (destroyed)
+//   %7  scratch register for the round
+
+#define do_col(a1, a2, a3, a4, a5, a6, a7)     \
+       movzx   %l(a6),%a7;                     \
+       xor     a5(,%a7,4),%a1;                 \
+       movzx   %h(a6),%a7;                     \
+       shr     $16,%a6;                        \
+       xor     a5+tlen(,%a7,4),%a2;            \
+       movzx   %l(a6),%a7;                     \
+       movzx   %h(a6),%a6;                     \
+       xor     a5+2*tlen(,%a7,4),%a3;          \
+       xor     a5+3*tlen(,%a6,4),%a4;
+
+// initialise output registers from the key schedule
+
+#define do_fcol(a1, a2, a3, a4, a5, a6, a7, a8)        \
+       mov     0 a8,%a1;                       \
+       movzx   %l(a6),%a7;                     \
+       mov     12 a8,%a2;                      \
+       xor     a5(,%a7,4),%a1;                 \
+       mov     4 a8,%a4;                       \
+       movzx   %h(a6),%a7;                     \
+       shr     $16,%a6;                        \
+       xor     a5+tlen(,%a7,4),%a2;            \
+       movzx   %l(a6),%a7;                     \
+       movzx   %h(a6),%a6;                     \
+       xor     a5+3*tlen(,%a6,4),%a4;          \
+       mov     %a3,%a6;                        \
+       mov     8 a8,%a3;                       \
+       xor     a5+2*tlen(,%a7,4),%a3;
+
+// initialise output registers from the key schedule
+
+#define do_icol(a1, a2, a3, a4, a5, a6, a7, a8)        \
+       mov     0 a8,%a1;                       \
+       movzx   %l(a6),%a7;                     \
+       mov     4 a8,%a2;                       \
+       xor     a5(,%a7,4),%a1;                 \
+       mov     12 a8,%a4;                      \
+       movzx   %h(a6),%a7;                     \
+       shr     $16,%a6;                        \
+       xor     a5+tlen(,%a7,4),%a2;            \
+       movzx   %l(a6),%a7;                     \
+       movzx   %h(a6),%a6;                     \
+       xor     a5+3*tlen(,%a6,4),%a4;          \
+       mov     %a3,%a6;                        \
+       mov     8 a8,%a3;                       \
+       xor     a5+2*tlen(,%a7,4),%a3;
+
+
+// original Gladman had conditional saves to MMX regs.
+#define save(a1, a2)           \
+       mov     %a2,4*a1(%esp)
+
+#define restore(a1, a2)                \
+       mov     4*a2(%esp),%a1
+
+// This macro performs a forward encryption cycle. It is entered with
+// the first previous round column values in r0, r1, r4 and r5 and
+// exits with the final values in the same registers, using the MMX
+// registers mm0-mm1 or the stack for temporary storage
+
+// mov current column values into the MMX registers
+#define fwd_rnd(arg, table)                                    \
+       /* mov current column values into the MMX registers */  \
+       mov     %r0,%r2;                                        \
+       save   (0,r1);                                          \
+       save   (1,r5);                                          \
+                                                               \
+       /* compute new column values */                         \
+       do_fcol(r0,r5,r4,r1,table, r2,r3, arg);                 \
+       do_col (r4,r1,r0,r5,table, r2,r3);                      \
+       restore(r2,0);                                          \
+       do_col (r1,r0,r5,r4,table, r2,r3);                      \
+       restore(r2,1);                                          \
+       do_col (r5,r4,r1,r0,table, r2,r3);
+
+// This macro performs an inverse encryption cycle. It is entered with
+// the first previous round column values in r0, r1, r4 and r5 and
+// exits with the final values in the same registers, using the MMX
+// registers mm0-mm1 or the stack for temporary storage
+
+#define inv_rnd(arg, table)                                    \
+       /* mov current column values into the MMX registers */  \
+       mov     %r0,%r2;                                        \
+       save    (0,r1);                                         \
+       save    (1,r5);                                         \
+                                                               \
+       /* compute new column values */                         \
+       do_icol(r0,r1,r4,r5, table, r2,r3, arg);                \
+       do_col (r4,r5,r0,r1, table, r2,r3);                     \
+       restore(r2,0);                                          \
+       do_col (r1,r4,r5,r0, table, r2,r3);                     \
+       restore(r2,1);                                          \
+       do_col (r5,r0,r1,r4, table, r2,r3);
+
+// AES (Rijndael) Encryption Subroutine
+
+.global  aes_enc_blk
+
+.extern  ft_tab
+.extern  fl_tab
+
+.align 4
+
+aes_enc_blk:
+       push    %ebp
+       mov     ctx(%esp),%ebp      // pointer to context
+       xor     %eax,%eax
+
+// CAUTION: the order and the values used in these assigns 
+// rely on the register mappings
+
+1:     push    %ebx
+       mov     in_blk+4(%esp),%r2
+       push    %esi
+       mov     nrnd(%ebp),%r3   // number of rounds
+       push    %edi
+       lea     ekey(%ebp),%r6   // key pointer
+
+// input four columns and xor in first round key
+
+       mov     (%r2),%r0
+       mov     4(%r2),%r1
+       mov     8(%r2),%r4
+       mov     12(%r2),%r5
+       xor     (%r6),%r0
+       xor     4(%r6),%r1
+       xor     8(%r6),%r4
+       xor     12(%r6),%r5
+
+       sub     $8,%esp           // space for register saves on stack
+       add     $16,%r6           // increment to next round key   
+       sub     $10,%r3          
+       je      4f              // 10 rounds for 128-bit key
+       add     $32,%r6
+       sub     $2,%r3
+       je      3f              // 12 rounds for 128-bit key
+       add     $32,%r6
+
+2:     fwd_rnd( -64(%r6) ,ft_tab)      // 14 rounds for 128-bit key
+       fwd_rnd( -48(%r6) ,ft_tab)
+3:     fwd_rnd( -32(%r6) ,ft_tab)      // 12 rounds for 128-bit key
+       fwd_rnd( -16(%r6) ,ft_tab)
+4:     fwd_rnd(    (%r6) ,ft_tab)      // 10 rounds for 128-bit key
+       fwd_rnd( +16(%r6) ,ft_tab)
+       fwd_rnd( +32(%r6) ,ft_tab)
+       fwd_rnd( +48(%r6) ,ft_tab)
+       fwd_rnd( +64(%r6) ,ft_tab)
+       fwd_rnd( +80(%r6) ,ft_tab)
+       fwd_rnd( +96(%r6) ,ft_tab)
+       fwd_rnd(+112(%r6) ,ft_tab)
+       fwd_rnd(+128(%r6) ,ft_tab)
+       fwd_rnd(+144(%r6) ,fl_tab)      // last round uses a different table
+
+// move final values to the output array.  CAUTION: the 
+// order of these assigns rely on the register mappings
+
+       add     $8,%esp
+       mov     out_blk+12(%esp),%r6
+       mov     %r5,12(%r6)
+       pop     %edi
+       mov     %r4,8(%r6)
+       pop     %esi
+       mov     %r1,4(%r6)
+       pop     %ebx
+       mov     %r0,(%r6)
+       pop     %ebp
+       mov     $1,%eax
+       ret
+
+// AES (Rijndael) Decryption Subroutine
+
+.global  aes_dec_blk
+
+.extern  it_tab
+.extern  il_tab
+
+.align 4
+
+aes_dec_blk:
+       push    %ebp
+       mov     ctx(%esp),%ebp       // pointer to context
+       xor     %eax,%eax
+
+// CAUTION: the order and the values used in these assigns 
+// rely on the register mappings
+
+1:     push    %ebx
+       mov     in_blk+4(%esp),%r2
+       push    %esi
+       mov     nrnd(%ebp),%r3   // number of rounds
+       push    %edi
+       lea     dkey(%ebp),%r6   // key pointer
+       mov     %r3,%r0
+       shl     $4,%r0
+       add     %r0,%r6
+       
+// input four columns and xor in first round key
+
+       mov     (%r2),%r0
+       mov     4(%r2),%r1
+       mov     8(%r2),%r4
+       mov     12(%r2),%r5
+       xor     (%r6),%r0
+       xor     4(%r6),%r1
+       xor     8(%r6),%r4
+       xor     12(%r6),%r5
+
+       sub     $8,%esp           // space for register saves on stack
+       sub     $16,%r6           // increment to next round key   
+       sub     $10,%r3          
+       je      4f              // 10 rounds for 128-bit key
+       sub     $32,%r6
+       sub     $2,%r3
+       je      3f              // 12 rounds for 128-bit key
+       sub     $32,%r6
+
+2:     inv_rnd( +64(%r6), it_tab)      // 14 rounds for 128-bit key 
+       inv_rnd( +48(%r6), it_tab)
+3:     inv_rnd( +32(%r6), it_tab)      // 12 rounds for 128-bit key
+       inv_rnd( +16(%r6), it_tab)
+4:     inv_rnd(    (%r6), it_tab)      // 10 rounds for 128-bit key
+       inv_rnd( -16(%r6), it_tab)
+       inv_rnd( -32(%r6), it_tab)
+       inv_rnd( -48(%r6), it_tab)
+       inv_rnd( -64(%r6), it_tab)
+       inv_rnd( -80(%r6), it_tab)
+       inv_rnd( -96(%r6), it_tab)
+       inv_rnd(-112(%r6), it_tab)
+       inv_rnd(-128(%r6), it_tab)
+       inv_rnd(-144(%r6), il_tab)      // last round uses a different table
+
+// move final values to the output array.  CAUTION: the 
+// order of these assigns rely on the register mappings
+
+       add     $8,%esp
+       mov     out_blk+12(%esp),%r6
+       mov     %r5,12(%r6)
+       pop     %edi
+       mov     %r4,8(%r6)
+       pop     %esi
+       mov     %r1,4(%r6)
+       pop     %ebx
+       mov     %r0,(%r6)
+       pop     %ebp
+       mov     $1,%eax
+       ret
+
diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes.c
new file mode 100644 (file)
index 0000000..5a34ee9
--- /dev/null
@@ -0,0 +1,520 @@
+/* 
+ * 
+ * Glue Code for optimized 586 assembler version of AES
+ *
+ * Copyright (c) 2002, Dr Brian Gladman <>, Worcester, UK.
+ * All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ *
+ * Copyright (c) 2003, Adam J. Richter <adam@yggdrasil.com> (conversion to
+ * 2.5 API).
+ * Copyright (c) 2003, 2004 Fruhwirth Clemens <clemens@endorphin.org>
+ * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/linkage.h>
+
+asmlinkage void aes_enc_blk(const u8 *src, u8 *dst, void *ctx);
+asmlinkage void aes_dec_blk(const u8 *src, u8 *dst, void *ctx);
+
+#define AES_MIN_KEY_SIZE       16
+#define AES_MAX_KEY_SIZE       32
+#define AES_BLOCK_SIZE         16
+#define AES_KS_LENGTH          4 * AES_BLOCK_SIZE
+#define RC_LENGTH              29
+
+struct aes_ctx {
+       u32 ekey[AES_KS_LENGTH];
+       u32 rounds;
+       u32 dkey[AES_KS_LENGTH];
+};
+
+#define WPOLY 0x011b
+#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
+#define bytes2word(b0, b1, b2, b3)  \
+       (((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0))
+
+/* define the finite field multiplies required for Rijndael */
+#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
+#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
+#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
+#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
+#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
+#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
+#define fi(x) ((x) ?   pow[255 - log[x]]: 0)
+
+static inline u32 upr(u32 x, int n)
+{
+       return (x << 8 * n) | (x >> (32 - 8 * n));
+}
+
+static inline u8 bval(u32 x, int n)
+{
+       return x >> 8 * n;
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+#define fwd_affine(x) \
+       (w = (u32)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(u8)(w^(w>>8)))
+
+#define inv_affine(x) \
+       (w = (u32)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(u8)(w^(w>>8)))
+
+static u32 rcon_tab[RC_LENGTH];
+
+u32 ft_tab[4][256];
+u32 fl_tab[4][256];
+u32 ls_tab[4][256];
+u32 im_tab[4][256];
+u32 il_tab[4][256];
+u32 it_tab[4][256];
+
+void gen_tabs(void)
+{
+       u32 i, w;
+       u8 pow[512], log[256];
+
+       /*
+        * log and power tables for GF(2^8) finite field with
+        * WPOLY as modular polynomial - the simplest primitive
+        * root is 0x03, used here to generate the tables.
+        */
+       i = 0; w = 1; 
+       
+       do {
+               pow[i] = (u8)w;
+               pow[i + 255] = (u8)w;
+               log[w] = (u8)i++;
+               w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
+       } while (w != 1);
+       
+       for(i = 0, w = 1; i < RC_LENGTH; ++i) {
+               rcon_tab[i] = bytes2word(w, 0, 0, 0);
+               w = f2(w);
+       }
+
+       for(i = 0; i < 256; ++i) {
+               u8 b;
+               
+               b = fwd_affine(fi((u8)i));
+               w = bytes2word(f2(b), b, b, f3(b));
+
+               /* tables for a normal encryption round */
+               ft_tab[0][i] = w;
+               ft_tab[1][i] = upr(w, 1);
+               ft_tab[2][i] = upr(w, 2);
+               ft_tab[3][i] = upr(w, 3);
+               w = bytes2word(b, 0, 0, 0);
+               
+               /*
+                * tables for last encryption round
+                * (may also be used in the key schedule)
+                */
+               fl_tab[0][i] = w;
+               fl_tab[1][i] = upr(w, 1);
+               fl_tab[2][i] = upr(w, 2);
+               fl_tab[3][i] = upr(w, 3);
+               
+               /*
+                * table for key schedule if fl_tab above is
+                * not of the required form
+                */
+               ls_tab[0][i] = w;
+               ls_tab[1][i] = upr(w, 1);
+               ls_tab[2][i] = upr(w, 2);
+               ls_tab[3][i] = upr(w, 3);
+               
+               b = fi(inv_affine((u8)i));
+               w = bytes2word(fe(b), f9(b), fd(b), fb(b));
+
+               /* tables for the inverse mix column operation  */
+               im_tab[0][b] = w;
+               im_tab[1][b] = upr(w, 1);
+               im_tab[2][b] = upr(w, 2);
+               im_tab[3][b] = upr(w, 3);
+
+               /* tables for a normal decryption round */
+               it_tab[0][i] = w;
+               it_tab[1][i] = upr(w,1);
+               it_tab[2][i] = upr(w,2);
+               it_tab[3][i] = upr(w,3);
+
+               w = bytes2word(b, 0, 0, 0);
+               
+               /* tables for last decryption round */
+               il_tab[0][i] = w;
+               il_tab[1][i] = upr(w,1);
+               il_tab[2][i] = upr(w,2);
+               il_tab[3][i] = upr(w,3);
+    }
+}
+
+#define four_tables(x,tab,vf,rf,c)             \
+(      tab[0][bval(vf(x,0,c),rf(0,c))] ^       \
+       tab[1][bval(vf(x,1,c),rf(1,c))] ^       \
+       tab[2][bval(vf(x,2,c),rf(2,c))] ^       \
+       tab[3][bval(vf(x,3,c),rf(3,c))]         \
+)
+
+#define vf1(x,r,c)  (x)
+#define rf1(r,c)    (r)
+#define rf2(r,c)    ((r-c)&3)
+
+#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
+#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
+
+#define ff(x) inv_mcol(x)
+
+#define ke4(k,i)                                                       \
+{                                                                      \
+       k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];            \
+       k[4*(i)+5] = ss[1] ^= ss[0];                                    \
+       k[4*(i)+6] = ss[2] ^= ss[1];                                    \
+       k[4*(i)+7] = ss[3] ^= ss[2];                                    \
+}
+
+#define kel4(k,i)                                                      \
+{                                                                      \
+       k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];            \
+       k[4*(i)+5] = ss[1] ^= ss[0];                                    \
+       k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2];       \
+}
+
+#define ke6(k,i)                                                       \
+{                                                                      \
+       k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];           \
+       k[6*(i)+ 7] = ss[1] ^= ss[0];                                   \
+       k[6*(i)+ 8] = ss[2] ^= ss[1];                                   \
+       k[6*(i)+ 9] = ss[3] ^= ss[2];                                   \
+       k[6*(i)+10] = ss[4] ^= ss[3];                                   \
+       k[6*(i)+11] = ss[5] ^= ss[4];                                   \
+}
+
+#define kel6(k,i)                                                      \
+{                                                                      \
+       k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];           \
+       k[6*(i)+ 7] = ss[1] ^= ss[0];                                   \
+       k[6*(i)+ 8] = ss[2] ^= ss[1];                                   \
+       k[6*(i)+ 9] = ss[3] ^= ss[2];                                   \
+}
+
+#define ke8(k,i)                                                       \
+{                                                                      \
+       k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];           \
+       k[8*(i)+ 9] = ss[1] ^= ss[0];                                   \
+       k[8*(i)+10] = ss[2] ^= ss[1];                                   \
+       k[8*(i)+11] = ss[3] ^= ss[2];                                   \
+       k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0);                         \
+       k[8*(i)+13] = ss[5] ^= ss[4];                                   \
+       k[8*(i)+14] = ss[6] ^= ss[5];                                   \
+       k[8*(i)+15] = ss[7] ^= ss[6];                                   \
+}
+
+#define kel8(k,i)                                                      \
+{                                                                      \
+       k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];           \
+       k[8*(i)+ 9] = ss[1] ^= ss[0];                                   \
+       k[8*(i)+10] = ss[2] ^= ss[1];                                   \
+       k[8*(i)+11] = ss[3] ^= ss[2];                                   \
+}
+
+#define kdf4(k,i)                                                      \
+{                                                                      \
+       ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3];                          \
+       ss[1] = ss[1] ^ ss[3];                                          \
+       ss[2] = ss[2] ^ ss[3];                                          \
+       ss[3] = ss[3];                                                  \
+       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
+       ss[i % 4] ^= ss[4];                                             \
+       ss[4] ^= k[4*(i)];                                              \
+       k[4*(i)+4] = ff(ss[4]);                                         \
+       ss[4] ^= k[4*(i)+1];                                            \
+       k[4*(i)+5] = ff(ss[4]);                                         \
+       ss[4] ^= k[4*(i)+2];                                            \
+       k[4*(i)+6] = ff(ss[4]);                                         \
+       ss[4] ^= k[4*(i)+3];                                            \
+       k[4*(i)+7] = ff(ss[4]);                                         \
+}
+
+#define kd4(k,i)                                                       \
+{                                                                      \
+       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
+       ss[i % 4] ^= ss[4];                                             \
+       ss[4] = ff(ss[4]);                                              \
+       k[4*(i)+4] = ss[4] ^= k[4*(i)];                                 \
+       k[4*(i)+5] = ss[4] ^= k[4*(i)+1];                               \
+       k[4*(i)+6] = ss[4] ^= k[4*(i)+2];                               \
+       k[4*(i)+7] = ss[4] ^= k[4*(i)+3];                               \
+}
+
+#define kdl4(k,i)                                                      \
+{                                                                      \
+       ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];                 \
+       ss[i % 4] ^= ss[4];                                             \
+       k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3];                  \
+       k[4*(i)+5] = ss[1] ^ ss[3];                                     \
+       k[4*(i)+6] = ss[0];                                             \
+       k[4*(i)+7] = ss[1];                                             \
+}
+
+#define kdf6(k,i)                                                      \
+{                                                                      \
+       ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];                         \
+       k[6*(i)+ 6] = ff(ss[0]);                                        \
+       ss[1] ^= ss[0];                                                 \
+       k[6*(i)+ 7] = ff(ss[1]);                                        \
+       ss[2] ^= ss[1];                                                 \
+       k[6*(i)+ 8] = ff(ss[2]);                                        \
+       ss[3] ^= ss[2];                                                 \
+       k[6*(i)+ 9] = ff(ss[3]);                                        \
+       ss[4] ^= ss[3];                                                 \
+       k[6*(i)+10] = ff(ss[4]);                                        \
+       ss[5] ^= ss[4];                                                 \
+       k[6*(i)+11] = ff(ss[5]);                                        \
+}
+
+#define kd6(k,i)                                                       \
+{                                                                      \
+       ss[6] = ls_box(ss[5],3) ^ rcon_tab[i];                          \
+       ss[0] ^= ss[6]; ss[6] = ff(ss[6]);                              \
+       k[6*(i)+ 6] = ss[6] ^= k[6*(i)];                                \
+       ss[1] ^= ss[0];                                                 \
+       k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1];                             \
+       ss[2] ^= ss[1];                                                 \
+       k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2];                             \
+       ss[3] ^= ss[2];                                                 \
+       k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3];                             \
+       ss[4] ^= ss[3];                                                 \
+       k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4];                             \
+       ss[5] ^= ss[4];                                                 \
+       k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5];                             \
+}
+
+#define kdl6(k,i)                                                      \
+{                                                                      \
+       ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];                         \
+       k[6*(i)+ 6] = ss[0];                                            \
+       ss[1] ^= ss[0];                                                 \
+       k[6*(i)+ 7] = ss[1];                                            \
+       ss[2] ^= ss[1];                                                 \
+       k[6*(i)+ 8] = ss[2];                                            \
+       ss[3] ^= ss[2];                                                 \
+       k[6*(i)+ 9] = ss[3];                                            \
+}
+
+#define kdf8(k,i)                                                      \
+{                                                                      \
+       ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];                         \
+       k[8*(i)+ 8] = ff(ss[0]);                                        \
+       ss[1] ^= ss[0];                                                 \
+       k[8*(i)+ 9] = ff(ss[1]);                                        \
+       ss[2] ^= ss[1];                                                 \
+       k[8*(i)+10] = ff(ss[2]);                                        \
+       ss[3] ^= ss[2];                                                 \
+       k[8*(i)+11] = ff(ss[3]);                                        \
+       ss[4] ^= ls_box(ss[3],0);                                       \
+       k[8*(i)+12] = ff(ss[4]);                                        \
+       ss[5] ^= ss[4];                                                 \
+       k[8*(i)+13] = ff(ss[5]);                                        \
+       ss[6] ^= ss[5];                                                 \
+       k[8*(i)+14] = ff(ss[6]);                                        \
+       ss[7] ^= ss[6];                                                 \
+       k[8*(i)+15] = ff(ss[7]);                                        \
+}
+
+#define kd8(k,i)                                                       \
+{                                                                      \
+       u32 __g = ls_box(ss[7],3) ^ rcon_tab[i];                        \
+       ss[0] ^= __g;                                                   \
+       __g = ff(__g);                                                  \
+       k[8*(i)+ 8] = __g ^= k[8*(i)];                                  \
+       ss[1] ^= ss[0];                                                 \
+       k[8*(i)+ 9] = __g ^= k[8*(i)+ 1];                               \
+       ss[2] ^= ss[1];                                                 \
+       k[8*(i)+10] = __g ^= k[8*(i)+ 2];                               \
+       ss[3] ^= ss[2];                                                 \
+       k[8*(i)+11] = __g ^= k[8*(i)+ 3];                               \
+       __g = ls_box(ss[3],0);                                          \
+       ss[4] ^= __g;                                                   \
+       __g = ff(__g);                                                  \
+       k[8*(i)+12] = __g ^= k[8*(i)+ 4];                               \
+       ss[5] ^= ss[4];                                                 \
+       k[8*(i)+13] = __g ^= k[8*(i)+ 5];                               \
+       ss[6] ^= ss[5];                                                 \
+       k[8*(i)+14] = __g ^= k[8*(i)+ 6];                               \
+       ss[7] ^= ss[6];                                                 \
+       k[8*(i)+15] = __g ^= k[8*(i)+ 7];                               \
+}
+
+#define kdl8(k,i)                                                      \
+{                                                                      \
+       ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];                         \
+       k[8*(i)+ 8] = ss[0];                                            \
+       ss[1] ^= ss[0];                                                 \
+       k[8*(i)+ 9] = ss[1];                                            \
+       ss[2] ^= ss[1];                                                 \
+       k[8*(i)+10] = ss[2];                                            \
+       ss[3] ^= ss[2];                                                 \
+       k[8*(i)+11] = ss[3];                                            \
+}
+
+static int
+aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
+{
+       int i;
+       u32 ss[8];
+       struct aes_ctx *ctx = ctx_arg;
+
+       /* encryption schedule */
+       
+       ctx->ekey[0] = ss[0] = u32_in(in_key);
+       ctx->ekey[1] = ss[1] = u32_in(in_key + 4);
+       ctx->ekey[2] = ss[2] = u32_in(in_key + 8);
+       ctx->ekey[3] = ss[3] = u32_in(in_key + 12);
+
+       switch(key_len) {
+       case 16:
+               for (i = 0; i < 9; i++)
+                       ke4(ctx->ekey, i);
+               kel4(ctx->ekey, 9);
+               ctx->rounds = 10;
+               break;
+               
+       case 24:
+               ctx->ekey[4] = ss[4] = u32_in(in_key + 16);
+               ctx->ekey[5] = ss[5] = u32_in(in_key + 20);
+               for (i = 0; i < 7; i++)
+                       ke6(ctx->ekey, i);
+               kel6(ctx->ekey, 7); 
+               ctx->rounds = 12;
+               break;
+
+       case 32:
+               ctx->ekey[4] = ss[4] = u32_in(in_key + 16);
+               ctx->ekey[5] = ss[5] = u32_in(in_key + 20);
+               ctx->ekey[6] = ss[6] = u32_in(in_key + 24);
+               ctx->ekey[7] = ss[7] = u32_in(in_key + 28);
+               for (i = 0; i < 6; i++)
+                       ke8(ctx->ekey, i);
+               kel8(ctx->ekey, 6);
+               ctx->rounds = 14;
+               break;
+
+       default:
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+       
+       /* decryption schedule */
+       
+       ctx->dkey[0] = ss[0] = u32_in(in_key);
+       ctx->dkey[1] = ss[1] = u32_in(in_key + 4);
+       ctx->dkey[2] = ss[2] = u32_in(in_key + 8);
+       ctx->dkey[3] = ss[3] = u32_in(in_key + 12);
+
+       switch (key_len) {
+       case 16:
+               kdf4(ctx->dkey, 0);
+               for (i = 1; i < 9; i++)
+                       kd4(ctx->dkey, i);
+               kdl4(ctx->dkey, 9);
+               break;
+               
+       case 24:
+               ctx->dkey[4] = ff(ss[4] = u32_in(in_key + 16));
+               ctx->dkey[5] = ff(ss[5] = u32_in(in_key + 20));
+               kdf6(ctx->dkey, 0);
+               for (i = 1; i < 7; i++)
+                       kd6(ctx->dkey, i);
+               kdl6(ctx->dkey, 7);
+               break;
+
+       case 32:
+               ctx->dkey[4] = ff(ss[4] = u32_in(in_key + 16));
+               ctx->dkey[5] = ff(ss[5] = u32_in(in_key + 20));
+               ctx->dkey[6] = ff(ss[6] = u32_in(in_key + 24));
+               ctx->dkey[7] = ff(ss[7] = u32_in(in_key + 28));
+               kdf8(ctx->dkey, 0);
+               for (i = 1; i < 6; i++)
+                       kd8(ctx->dkey, i);
+               kdl8(ctx->dkey, 6);
+               break;
+       }
+       return 0;
+}
+
+static inline void aes_encrypt(void *ctx, u8 *dst, const u8 *src)
+{
+       aes_enc_blk(src, dst, ctx);
+}
+static inline void aes_decrypt(void *ctx, u8 *dst, const u8 *src)
+{
+       aes_dec_blk(src, dst, ctx);
+}
+
+
+static struct crypto_alg aes_alg = {
+       .cra_name               =       "aes",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       AES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct aes_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       AES_MAX_KEY_SIZE,
+                       .cia_setkey             =       aes_set_key,
+                       .cia_encrypt            =       aes_encrypt,
+                       .cia_decrypt            =       aes_decrypt
+               }
+       }
+};
+
+static int __init aes_init(void)
+{
+       gen_tabs();
+       return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_fini(void)
+{
+       crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, i586 asm optimized");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Fruhwirth Clemens, James Morris, Brian Gladman, Adam Richter");
+MODULE_ALIAS("aes");
diff --git a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap.c
new file mode 100644 (file)
index 0000000..f88a6c8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  linux/arch/i386/mm/mmap.c
+ *
+ *  flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; 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
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(struct mm_struct *mm)
+{
+       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+       if (gap < MIN_GAP)
+               gap = MIN_GAP;
+       else if (gap > MAX_GAP)
+               gap = MAX_GAP;
+
+       return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+       /*
+        * Fall back to the standard layout if the personality
+        * bit is set, or if the expected stack growth is unlimited:
+        */
+       if (sysctl_legacy_va_layout || (current->personality & ADDR_COMPAT_LAYOUT) ||
+                       current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) {
+               mm->mmap_base = TASK_UNMAPPED_BASE;
+               mm->get_unmapped_area = arch_get_unmapped_area;
+               mm->unmap_area = arch_unmap_area;
+       } else {
+               mm->mmap_base = mmap_base(mm);
+               mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+               mm->get_unmapped_exec_area = arch_get_unmapped_exec_area;
+               mm->unmap_area = arch_unmap_area_topdown;
+       }
+}
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
new file mode 100644 (file)
index 0000000..a6e9337
--- /dev/null
@@ -0,0 +1,591 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS64=y
+CONFIG_64BIT=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Machine selection
+#
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+CONFIG_MOMENCO_OCELOT_G=y
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_CPU_RM7K=y
+CONFIG_PCI_MARVELL=y
+CONFIG_SWAP_IO_SPACE=y
+# CONFIG_SYSCLK_75 is not set
+# CONFIG_SYSCLK_83 is not set
+CONFIG_SYSCLK_100=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_FB is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+CONFIG_CPU_RM7000=y
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_BOARD_SCACHE=y
+CONFIG_RM7000_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_LLDSCD=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_PREEMPT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_MMU=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_GALILEO_64240_ETH=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC16=y
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
new file mode 100644 (file)
index 0000000..abd7490
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Kernel unwinding support
+ *
+ * (c) 2002-2004 Randolph Chung <tausq@debian.org>
+ *
+ * Derived partially from the IA64 implementation. The PA-RISC
+ * Runtime Architecture Document is also a useful reference to
+ * understand what is happening here
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+
+#include <asm/unwind.h>
+
+/* #define DEBUG 1 */
+#ifdef DEBUG
+#define dbg(x...) printk(x)
+#else
+#define dbg(x...)
+#endif
+
+extern struct unwind_table_entry __start___unwind[];
+extern struct unwind_table_entry __stop___unwind[];
+
+static spinlock_t unwind_lock;
+/*
+ * the kernel unwind block is not dynamically allocated so that
+ * we can call unwind_init as early in the bootup process as 
+ * possible (before the slab allocator is initialized)
+ */
+static struct unwind_table kernel_unwind_table;
+static struct unwind_table *unwind_tables, *unwind_tables_end;
+
+
+static inline const struct unwind_table_entry *
+find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
+{
+       const struct unwind_table_entry *e = 0;
+       unsigned long lo, hi, mid;
+
+       for (lo = 0, hi = table->length; lo < hi; )
+       {
+               mid = (lo + hi) / 2;
+               e = &table->table[mid];
+               if (addr < e->region_start)
+                       hi = mid;
+               else if (addr > e->region_end)
+                       lo = mid + 1;
+               else
+                       break;
+       }
+
+       return e;
+}
+
+static inline const struct unwind_table_entry *
+find_unwind_entry(unsigned long addr)
+{
+       struct unwind_table *table = unwind_tables;
+       const struct unwind_table_entry *e = NULL;
+
+       if (addr >= kernel_unwind_table.start && 
+           addr <= kernel_unwind_table.end)
+               e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
+       else
+               for (; table; table = table->next)
+               {
+                       if (addr >= table->start && 
+                           addr <= table->end)
+                               e = find_unwind_entry_in_table(table, addr);
+                       if (e)
+                               break;
+               }
+
+       return e;
+}
+
+static void
+unwind_table_init(struct unwind_table *table, const char *name,
+                 unsigned long base_addr, unsigned long gp,
+                 void *table_start, void *table_end)
+{
+       struct unwind_table_entry *start = table_start;
+       struct unwind_table_entry *end = 
+               (struct unwind_table_entry *)table_end - 1;
+
+       table->name = name;
+       table->base_addr = base_addr;
+       table->gp = gp;
+       table->start = base_addr + start->region_start;
+       table->end = base_addr + end->region_end;
+       table->table = (struct unwind_table_entry *)table_start;
+       table->length = end - start + 1;
+       table->next = NULL;
+
+       for (; start <= end; start++) {
+               start->region_start += base_addr;
+               start->region_end += base_addr;
+       }
+}
+
+void *
+unwind_table_add(const char *name, unsigned long base_addr, 
+                unsigned long gp,
+                 void *start, void *end)
+{
+       struct unwind_table *table;
+       unsigned long flags;
+
+       table = kmalloc(sizeof(struct unwind_table), GFP_USER);
+       if (table == NULL)
+               return 0;
+       unwind_table_init(table, name, base_addr, gp, start, end);
+       spin_lock_irqsave(&unwind_lock, flags);
+       if (unwind_tables)
+       {
+               unwind_tables_end->next = table;
+               unwind_tables_end = table;
+       }
+       else
+       {
+               unwind_tables = unwind_tables_end = table;
+       }
+       spin_unlock_irqrestore(&unwind_lock, flags);
+
+       return table;
+}
+
+/* Called from setup_arch to import the kernel unwind info */
+static int unwind_init(void)
+{
+       long start, stop;
+       register unsigned long gp __asm__ ("r27");
+
+       start = (long)&__start___unwind[0];
+       stop = (long)&__stop___unwind[0];
+
+       printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
+           start, stop,
+           (stop - start) / sizeof(struct unwind_table_entry));
+
+       unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
+                         gp, 
+                         &__start___unwind[0], &__stop___unwind[0]);
+#if 0
+       {
+               int i;
+               for (i = 0; i < 10; i++)
+               {
+                       printk("region 0x%x-0x%x\n", 
+                               __start___unwind[i].region_start, 
+                               __start___unwind[i].region_end);
+               }
+       }
+#endif
+       return 0;
+}
+
+static void unwind_frame_regs(struct unwind_frame_info *info)
+{
+       const struct unwind_table_entry *e;
+       unsigned long npc;
+       unsigned int insn;
+       long frame_size = 0;
+       int looking_for_rp, rpoffset = 0;
+
+       e = find_unwind_entry(info->ip);
+       if (!e) {
+               unsigned long sp;
+               extern char _stext[], _etext[];
+
+               dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
+
+               /* Since we are doing the unwinding blind, we don't know if
+                  we are adjusting the stack correctly or extracting the rp
+                  correctly. The rp is checked to see if it belongs to the
+                  kernel text section, if not we assume we don't have a 
+                  correct stack frame and we continue to unwind the stack.
+                  This is not quite correct, and will fail for loadable
+                  modules. */
+               sp = info->sp & ~63;
+               do {
+                       info->prev_sp = sp - 64;
+
+                       /* FIXME: what happens if we unwind too far so that 
+                          sp no longer falls in a mapped kernel page? */
+#ifndef __LP64__
+                       info->prev_ip = *(unsigned long *)(info->prev_sp - 20);
+#else
+                       info->prev_ip = *(unsigned long *)(info->prev_sp - 16);
+#endif
+
+                       sp = info->prev_sp;
+               } while (info->prev_ip < (unsigned long)_stext ||
+                        info->prev_ip > (unsigned long)_etext);
+
+               dbg("analyzing func @ %lx with no unwind info, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
+       } else {
+
+               dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
+                               e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size);
+
+               looking_for_rp = e->Save_RP;
+
+               for (npc = e->region_start; 
+                    (frame_size < (e->Total_frame_size << 3) || looking_for_rp) && 
+                    npc < info->ip; 
+                    npc += 4) {
+
+                       insn = *(unsigned int *)npc;
+
+                       if ((insn & 0xffffc000) == 0x37de0000 ||
+                           (insn & 0xffe00000) == 0x6fc00000) {
+                               /* ldo X(sp), sp, or stwm X,D(sp) */
+                               frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
+                                       ((insn & 0x3fff) >> 1);
+                               dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
+                       } else if ((insn & 0xffe00008) == 0x7ec00008) {
+                               /* std,ma X,D(sp) */
+                               frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
+                                       (((insn >> 4) & 0x3ff) << 3);
+                               dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size);
+                       } else if (insn == 0x6bc23fd9) { 
+                               /* stw rp,-20(sp) */
+                               rpoffset = 20;
+                               looking_for_rp = 0;
+                               dbg("analyzing func @ %lx, insn=stw rp,-20(sp) @ %lx\n", info->ip, npc);
+                       } else if (insn == 0x0fc212c1) {
+                               /* std rp,-16(sr0,sp) */
+                               rpoffset = 16;
+                               looking_for_rp = 0;
+                               dbg("analyzing func @ %lx, insn=std rp,-16(sp) @ %lx\n", info->ip, npc);
+                       }
+               }
+
+               info->prev_sp = info->sp - frame_size;
+               if (rpoffset)
+                       info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
+               info->prev_ip = info->rp;
+               info->rp = 0;
+
+               dbg("analyzing func @ %lx, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip);
+       }
+}
+
+void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
+                      unsigned long sp, unsigned long ip, unsigned long rp)
+{
+       memset(info, 0, sizeof(struct unwind_frame_info));
+       info->t = t;
+       info->sp = sp;
+       info->ip = ip;
+       info->rp = rp;
+
+       dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip);
+}
+
+void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
+{
+       struct pt_regs *regs = &t->thread.regs;
+       unwind_frame_init(info, t, regs->ksp, regs->kpc, 0);
+}
+
+void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
+{
+       unwind_frame_init(info, current, regs->gr[30], regs->iaoq[0],
+                         regs->gr[2]);
+}
+
+int unwind_once(struct unwind_frame_info *next_frame)
+{
+       unwind_frame_regs(next_frame);
+
+       if (next_frame->prev_sp == 0 ||
+           next_frame->prev_ip == 0)
+               return -1;
+
+       next_frame->sp = next_frame->prev_sp;
+       next_frame->ip = next_frame->prev_ip;
+       next_frame->prev_sp = 0;
+       next_frame->prev_ip = 0;
+
+       dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip);
+
+       return 0;
+}
+
+int unwind_to_user(struct unwind_frame_info *info)
+{
+       int ret;
+       
+       do {
+               ret = unwind_once(info);
+       } while (!ret && !(info->ip & 3));
+
+       return ret;
+}
+
+module_init(unwind_init);
diff --git a/arch/ppc/boot/simple/mpc52xx_tty.c b/arch/ppc/boot/simple/mpc52xx_tty.c
new file mode 100644 (file)
index 0000000..8a1c663
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * arch/ppc/boot/simple/mpc52xx_tty.c
+ *
+ * Minimal serial functions needed to send messages out a MPC52xx
+ * Programmable Serial Controller (PSC).
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+#include <asm/serial.h>
+#include <asm/time.h>
+
+#if MPC52xx_PF_CONSOLE_PORT == 0
+#define MPC52xx_CONSOLE                MPC52xx_PSC1
+#define MPC52xx_PSC_CONFIG_SHIFT       0
+#elif MPC52xx_PF_CONSOLE_PORT == 1
+#define MPC52xx_CONSOLE                MPC52xx_PSC2
+#define MPC52xx_PSC_CONFIG_SHIFT       4
+#elif MPC52xx_PF_CONSOLE_PORT == 2
+#define MPC52xx_CONSOLE                MPC52xx_PSC3
+#define MPC52xx_PSC_CONFIG_SHIFT       8
+#else
+#error "MPC52xx_PF_CONSOLE_PORT not defined"
+#endif
+
+static struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE;
+
+/* The decrementer counts at the system bus clock frequency
+ * divided by four.  The most accurate time base is connected to the
+ * rtc.  We read the decrementer change during one rtc tick (one second)
+ * and multiply by 4 to get the system bus clock frequency.
+ */
+int
+mpc52xx_ipbfreq(void)
+{
+       struct mpc52xx_rtc *rtc = (struct mpc52xx_rtc*)MPC52xx_RTC;
+       struct mpc52xx_cdm *cdm = (struct mpc52xx_cdm*)MPC52xx_CDM;
+       int current_time, previous_time;
+       int tbl_start, tbl_end;
+       int xlbfreq, ipbfreq;
+
+       out_be32(&rtc->dividers, 0x8f1f0000);   /* Set RTC 64x faster */
+       previous_time = in_be32(&rtc->time);
+       while ((current_time = in_be32(&rtc->time)) == previous_time) ;
+       tbl_start = get_tbl();
+       previous_time = current_time;
+       while ((current_time = in_be32(&rtc->time)) == previous_time) ;
+       tbl_end = get_tbl();
+       out_be32(&rtc->dividers, 0xffff0000);   /* Restore RTC */
+
+       xlbfreq = (tbl_end - tbl_start) << 8;
+       ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? xlbfreq / 2 : xlbfreq;
+
+       return ipbfreq;
+}
+
+unsigned long
+serial_init(int ignored, void *ignored2)
+{
+       struct mpc52xx_gpio *gpio = (struct mpc52xx_gpio *)MPC52xx_GPIO;
+       int divisor;
+       int mode1;
+       int mode2;
+       u32 val32;
+
+       static int been_here = 0;
+
+       if (been_here)
+               return 0;
+
+       been_here = 1;
+
+       val32 = in_be32(&gpio->port_config);
+       val32 &= ~(0x7 << MPC52xx_PSC_CONFIG_SHIFT);
+       val32 |= MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD
+                               << MPC52xx_PSC_CONFIG_SHIFT;
+       out_be32(&gpio->port_config, val32);
+
+       out_8(&psc->command, MPC52xx_PSC_RST_TX
+                       | MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+
+       out_be32(&psc->sicr, 0x0);
+       out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
+       out_be16(&psc->tfalarm, 0xf8);
+
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1
+                       | MPC52xx_PSC_RX_ENABLE
+                       | MPC52xx_PSC_TX_ENABLE);
+
+       divisor = ((mpc52xx_ipbfreq()
+                       / (CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD * 16)) + 1) >> 1;
+
+       mode1 = MPC52xx_PSC_MODE_8_BITS | MPC52xx_PSC_MODE_PARNONE
+                       | MPC52xx_PSC_MODE_ERR;
+       mode2 = MPC52xx_PSC_MODE_ONE_STOP;
+
+       out_8(&psc->ctur, divisor>>8);
+       out_8(&psc->ctlr, divisor);
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->mode, mode1);
+       out_8(&psc->mode, mode2);
+
+       return 0;       /* ignored */
+}
+
+void
+serial_putc(void *ignored, const char c)
+{
+       serial_init(0, 0);
+
+       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
+       out_8(&psc->mpc52xx_psc_buffer_8, c);
+       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
+}
+
+char
+serial_getc(void *ignored)
+{
+       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY)) ;
+
+       return in_8(&psc->mpc52xx_psc_buffer_8);
+}
+
+int
+serial_tstc(void *ignored)
+{
+       return (in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY) != 0;
+}
diff --git a/arch/ppc/configs/ads8272_defconfig b/arch/ppc/configs/ads8272_defconfig
new file mode 100644 (file)
index 0000000..d1db7d1
--- /dev/null
@@ -0,0 +1,582 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+CONFIG_PPC_STD_MMU=y
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_WILLOW is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_EV64260 is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+CONFIG_ADS8272=y
+CONFIG_PQ2ADS=y
+CONFIG_8260=y
+CONFIG_8272=y
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_OAKNET is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+CONFIG_FEC_ENET=y
+# CONFIG_USE_MDIO is not set
+
+#
+# CPM2 Options
+#
+CONFIG_SCC_CONSOLE=y
+CONFIG_FCC1_ENET=y
+# CONFIG_FCC2_ENET is not set
+# CONFIG_FCC3_ENET is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_KGDB_CONSOLE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/bubinga_defconfig b/arch/ppc/configs/bubinga_defconfig
new file mode 100644 (file)
index 0000000..ebec801
--- /dev/null
@@ -0,0 +1,592 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_STANDALONE is not set
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_4xx=y
+
+#
+# IBM 4xx options
+#
+# CONFIG_ASH is not set
+CONFIG_BUBINGA=y
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_OAK is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_WALNUT is not set
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM_OCP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_405EP=y
+CONFIG_IBM_OPENBIOS=y
+# CONFIG_PM is not set
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_OAKNET is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+CONFIG_IBM_EMAC=y
+# CONFIG_IBM_EMAC_ERRMSG is not set
+CONFIG_IBM_EMAC_RXB=64
+CONFIG_IBM_EMAC_TXB=8
+CONFIG_IBM_EMAC_FGAP=8
+CONFIG_IBM_EMAC_SKBRES=0
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# IBM 40x options
+#
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_PPC_OCP=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/lite5200_defconfig b/arch/ppc/configs/lite5200_defconfig
new file mode 100644 (file)
index 0000000..7e7a943
--- /dev/null
@@ -0,0 +1,436 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_FSL_OCP=y
+CONFIG_PPC_STD_MMU=y
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_WILLOW is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_EV64260 is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+CONFIG_LITE5200=y
+CONFIG_PPC_MPC52xx=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0 root=/dev/ram0 rw"
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_BOOT_LOAD_BOOL is not set
+CONFIG_BOOT_LOAD=0x00800000
+#
+# Device Drivers
+#
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+#
+# Plug and Play support
+#
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+#
+# Fusion MPT device support
+#
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+#
+# Macintosh device drivers
+#
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+#
+# ISDN subsystem
+#
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+#
+# Input device support
+#
+CONFIG_INPUT=y
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_MPC52xx=y
+CONFIG_SERIAL_MPC52xx_CONSOLE=y
+CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=9600
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+#
+# Misc devices
+#
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+#
+# Digital Video Broadcasting Devices
+#
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+#
+# USB support
+#
+# CONFIG_USB is not set
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+#
+# Library routines
+#
+# CONFIG_CRC16 is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_SERIAL_TEXT_DEBUG=y
+CONFIG_PPC_OCP=y
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/configs/rpx8260_defconfig b/arch/ppc/configs/rpx8260_defconfig
new file mode 100644 (file)
index 0000000..a9c4544
--- /dev/null
@@ -0,0 +1,555 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+CONFIG_6xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+CONFIG_PPC_STD_MMU=y
+
+#
+# Platform options
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_WILLOW is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_EV64260 is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+CONFIG_RPX8260=y
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+CONFIG_8260=y
+CONFIG_CPM2=y
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_OAKNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+# CONFIG_SCC_ENET is not set
+CONFIG_FEC_ENET=y
+# CONFIG_USE_MDIO is not set
+
+#
+# CPM2 Options
+#
+# CONFIG_FCC1_ENET is not set
+# CONFIG_FCC2_ENET is not set
+CONFIG_FCC3_ENET=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_KGDB_CONSOLE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c
new file mode 100644 (file)
index 0000000..54f9a3e
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ *  PowerPC version derived from arch/arm/mm/consistent.c
+ *    Copyright (C) 2001 Dan Malek (dmalek@jlc.net)
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * Consistent memory allocators.  Used for DMA devices that want to
+ * share uncached memory with the processor core.  The function return
+ * is the virtual address and 'dma_handle' is the physical address.
+ * Mostly stolen from the ARM port, with some changes for PowerPC.
+ *                                             -- Dan
+ *
+ * Reorganized to get rid of the arch-specific consistent_* functions
+ * and provide non-coherent implementations for the DMA API. -Matt
+ *
+ * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent()
+ * implementation. This is pulled straight from ARM and barely
+ * modified. -Matt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+
+int map_page(unsigned long va, phys_addr_t pa, int flags);
+
+#include <asm/tlbflush.h>
+
+/*
+ * This address range defaults to a value that is safe for all
+ * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It
+ * can be further configured for specific applications under
+ * the "Advanced Setup" menu. -Matt
+ */
+#define CONSISTENT_BASE        (CONFIG_CONSISTENT_START)
+#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE)
+#define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
+
+/*
+ * This is the page table (2MB) covering uncached, DMA consistent allocations
+ */
+static pte_t *consistent_pte;
+static spinlock_t consistent_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * VM region handling support.
+ *
+ * This should become something generic, handling VM region allocations for
+ * vmalloc and similar (ioremap, module space, etc).
+ *
+ * I envisage vmalloc()'s supporting vm_struct becoming:
+ *
+ *  struct vm_struct {
+ *    struct vm_region region;
+ *    unsigned long    flags;
+ *    struct page      **pages;
+ *    unsigned int     nr_pages;
+ *    unsigned long    phys_addr;
+ *  };
+ *
+ * get_vm_area() would then call vm_region_alloc with an appropriate
+ * struct vm_region head (eg):
+ *
+ *  struct vm_region vmalloc_head = {
+ *     .vm_list        = LIST_HEAD_INIT(vmalloc_head.vm_list),
+ *     .vm_start       = VMALLOC_START,
+ *     .vm_end         = VMALLOC_END,
+ *  };
+ *
+ * However, vmalloc_head.vm_start is variable (typically, it is dependent on
+ * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
+ * would have to initialise this each time prior to calling vm_region_alloc().
+ */
+struct vm_region {
+       struct list_head        vm_list;
+       unsigned long           vm_start;
+       unsigned long           vm_end;
+};
+
+static struct vm_region consistent_head = {
+       .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),
+       .vm_start       = CONSISTENT_BASE,
+       .vm_end         = CONSISTENT_END,
+};
+
+static struct vm_region *
+vm_region_alloc(struct vm_region *head, size_t size, int gfp)
+{
+       unsigned long addr = head->vm_start, end = head->vm_end - size;
+       unsigned long flags;
+       struct vm_region *c, *new;
+
+       new = kmalloc(sizeof(struct vm_region), gfp);
+       if (!new)
+               goto out;
+
+       spin_lock_irqsave(&consistent_lock, flags);
+
+       list_for_each_entry(c, &head->vm_list, vm_list) {
+               if ((addr + size) < addr)
+                       goto nospc;
+               if ((addr + size) <= c->vm_start)
+                       goto found;
+               addr = c->vm_end;
+               if (addr > end)
+                       goto nospc;
+       }
+
+ found:
+       /*
+        * Insert this entry _before_ the one we found.
+        */
+       list_add_tail(&new->vm_list, &c->vm_list);
+       new->vm_start = addr;
+       new->vm_end = addr + size;
+
+       spin_unlock_irqrestore(&consistent_lock, flags);
+       return new;
+
+ nospc:
+       spin_unlock_irqrestore(&consistent_lock, flags);
+       kfree(new);
+ out:
+       return NULL;
+}
+
+static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
+{
+       struct vm_region *c;
+
+       list_for_each_entry(c, &head->vm_list, vm_list) {
+               if (c->vm_start == addr)
+                       goto out;
+       }
+       c = NULL;
+ out:
+       return c;
+}
+
+/*
+ * Allocate DMA-coherent memory space and return both the kernel remapped
+ * virtual and bus address for that space.
+ */
+void *
+__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp)
+{
+       struct page *page;
+       struct vm_region *c;
+       unsigned long order;
+       u64 mask = 0x00ffffff, limit; /* ISA default */
+
+       if (!consistent_pte) {
+               printk(KERN_ERR "%s: not initialised\n", __func__);
+               dump_stack();
+               return NULL;
+       }
+
+       size = PAGE_ALIGN(size);
+       limit = (mask + 1) & ~mask;
+       if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) {
+               printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n",
+                      size, mask);
+               return NULL;
+       }
+
+       order = get_order(size);
+
+       if (mask != 0xffffffff)
+               gfp |= GFP_DMA;
+
+       page = alloc_pages(gfp, order);
+       if (!page)
+               goto no_page;
+
+       /*
+        * Invalidate any data that might be lurking in the
+        * kernel direct-mapped region for device DMA.
+        */
+       {
+               unsigned long kaddr = (unsigned long)page_address(page);
+               memset(page_address(page), 0, size);
+               flush_dcache_range(kaddr, kaddr + size);
+       }
+
+       /*
+        * Allocate a virtual address in the consistent mapping region.
+        */
+       c = vm_region_alloc(&consistent_head, size,
+                           gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+       if (c) {
+               pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+               struct page *end = page + (1 << order);
+
+               /*
+                * Set the "dma handle"
+                */
+               *handle = page_to_bus(page);
+
+               do {
+                       BUG_ON(!pte_none(*pte));
+
+                       set_page_count(page, 1);
+                       SetPageReserved(page);
+                       set_pte(pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
+                       page++;
+                       pte++;
+               } while (size -= PAGE_SIZE);
+
+               /*
+                * Free the otherwise unused pages.
+                */
+               while (page < end) {
+                       set_page_count(page, 1);
+                       __free_page(page);
+                       page++;
+               }
+
+               return (void *)c->vm_start;
+       }
+
+       if (page)
+               __free_pages(page, order);
+ no_page:
+       return NULL;
+}
+EXPORT_SYMBOL(__dma_alloc_coherent);
+
+/*
+ * free a page as defined by the above mapping.
+ */
+void __dma_free_coherent(size_t size, void *vaddr)
+{
+       struct vm_region *c;
+       unsigned long flags;
+       pte_t *ptep;
+
+       size = PAGE_ALIGN(size);
+
+       spin_lock_irqsave(&consistent_lock, flags);
+
+       c = vm_region_find(&consistent_head, (unsigned long)vaddr);
+       if (!c)
+               goto no_area;
+
+       if ((c->vm_end - c->vm_start) != size) {
+               printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+                      __func__, c->vm_end - c->vm_start, size);
+               dump_stack();
+               size = c->vm_end - c->vm_start;
+       }
+
+       ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+       do {
+               pte_t pte = ptep_get_and_clear(ptep);
+               unsigned long pfn;
+
+               ptep++;
+
+               if (!pte_none(pte) && pte_present(pte)) {
+                       pfn = pte_pfn(pte);
+
+                       if (pfn_valid(pfn)) {
+                               struct page *page = pfn_to_page(pfn);
+                               ClearPageReserved(page);
+
+                               __free_page(page);
+                               continue;
+                       }
+               }
+
+               printk(KERN_CRIT "%s: bad page in kernel page table\n",
+                      __func__);
+       } while (size -= PAGE_SIZE);
+
+       flush_tlb_kernel_range(c->vm_start, c->vm_end);
+
+       list_del(&c->vm_list);
+
+       spin_unlock_irqrestore(&consistent_lock, flags);
+
+       kfree(c);
+       return;
+
+ no_area:
+       spin_unlock_irqrestore(&consistent_lock, flags);
+       printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+              __func__, vaddr);
+       dump_stack();
+}
+EXPORT_SYMBOL(__dma_free_coherent);
+
+/*
+ * Initialise the consistent memory allocation.
+ */
+static int __init dma_alloc_init(void)
+{
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       int ret = 0;
+
+       spin_lock(&init_mm.page_table_lock);
+
+       do {
+               pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
+               pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
+               if (!pmd) {
+                       printk(KERN_ERR "%s: no pmd tables\n", __func__);
+                       ret = -ENOMEM;
+                       break;
+               }
+               WARN_ON(!pmd_none(*pmd));
+
+               pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
+               if (!pte) {
+                       printk(KERN_ERR "%s: no pte tables\n", __func__);
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               consistent_pte = pte;
+       } while (0);
+
+       spin_unlock(&init_mm.page_table_lock);
+
+       return ret;
+}
+
+core_initcall(dma_alloc_init);
+
+/*
+ * make an area consistent.
+ */
+void __dma_sync(void *vaddr, size_t size, int direction)
+{
+       unsigned long start = (unsigned long)vaddr;
+       unsigned long end   = start + size;
+
+       switch (direction) {
+       case DMA_NONE:
+               BUG();
+       case DMA_FROM_DEVICE:   /* invalidate only */
+               invalidate_dcache_range(start, end);
+               break;
+       case DMA_TO_DEVICE:             /* writeback only */
+               clean_dcache_range(start, end);
+               break;
+       case DMA_BIDIRECTIONAL: /* writeback and invalidate */
+               flush_dcache_range(start, end);
+               break;
+       }
+}
+
+#ifdef CONFIG_HIGHMEM
+/*
+ * __dma_sync_page() implementation for systems using highmem.
+ * In this case, each page of a buffer must be kmapped/kunmapped
+ * in order to have a virtual address for __dma_sync(). This must
+ * not sleep so kmap_atmomic()/kunmap_atomic() are used.
+ *
+ * Note: yes, it is possible and correct to have a buffer extend
+ * beyond the first page.
+ */
+static inline void __dma_sync_page_highmem(struct page *page,
+               unsigned long offset, size_t size, int direction)
+{
+       size_t seg_size = min((size_t)PAGE_SIZE, size) - offset;
+       size_t cur_size = seg_size;
+       unsigned long flags, start, seg_offset = offset;
+       int nr_segs = PAGE_ALIGN(size + (PAGE_SIZE - offset))/PAGE_SIZE;
+       int seg_nr = 0;
+
+       local_irq_save(flags);
+
+       do {
+               start = (unsigned long)kmap_atomic(page + seg_nr,
+                               KM_PPC_SYNC_PAGE) + seg_offset;
+
+               /* Sync this buffer segment */
+               __dma_sync((void *)start, seg_size, direction);
+               kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE);
+               seg_nr++;
+
+               /* Calculate next buffer segment size */
+               seg_size = min((size_t)PAGE_SIZE, size - cur_size);
+
+               /* Add the segment size to our running total */
+               cur_size += seg_size;
+               seg_offset = 0;
+       } while (seg_nr < nr_segs);
+
+       local_irq_restore(flags);
+}
+#endif /* CONFIG_HIGHMEM */
+
+/*
+ * __dma_sync_page makes memory consistent. identical to __dma_sync, but
+ * takes a struct page instead of a virtual address
+ */
+void __dma_sync_page(struct page *page, unsigned long offset,
+       size_t size, int direction)
+{
+#ifdef CONFIG_HIGHMEM
+       __dma_sync_page_highmem(page, offset, size, direction);
+#else
+       unsigned long start = (unsigned long)page_address(page) + offset;
+       __dma_sync((void *)start, size, direction);
+#endif
+}
diff --git a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S
new file mode 100644 (file)
index 0000000..ceb51d3
--- /dev/null
@@ -0,0 +1,1331 @@
+/*
+ * arch/ppc/kernel/head_e500.S
+ *
+ * Kernel execution entry point code.
+ *
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *     PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ *     Author: MontaVista Software, Inc.
+ *             frank_rowand@mvista.com or source@mvista.com
+ *             debbie_chu@mvista.com
+ *    Copyright 2002-2004 MontaVista Software, Inc.
+ *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
+ *    Copyright 2004 Freescale Semiconductor, Inc
+ *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.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.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+/*
+ * Macros
+ */
+
+#define SET_IVOR(vector_number, vector_label)          \
+               li      r26,vector_label@l;             \
+               mtspr   SPRN_IVOR##vector_number,r26;   \
+               sync
+
+/* As with the other PowerPC ports, it is expected that when code
+ * execution begins here, the following registers contain valid, yet
+ * optional, information:
+ *
+ *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
+ *   r4 - Starting address of the init RAM disk
+ *   r5 - Ending address of the init RAM disk
+ *   r6 - Start of kernel command line string (e.g. "mem=128")
+ *   r7 - End of kernel command line string
+ *
+ */
+       .text
+_GLOBAL(_stext)
+_GLOBAL(_start)
+       /*
+        * Reserve a word at a fixed location to store the address
+        * of abatron_pteptrs
+        */
+       nop
+/*
+ * Save parameters we are passed
+ */
+       mr      r31,r3
+       mr      r30,r4
+       mr      r29,r5
+       mr      r28,r6
+       mr      r27,r7
+       li      r24,0           /* CPU number */
+
+/* We try to not make any assumptions about how the boot loader
+ * setup or used the TLBs.  We invalidate all mappings from the
+ * boot loader and load a single entry in TLB1[0] to map the
+ * first 16M of kernel memory.  Any boot info passed from the
+ * bootloader needs to live in this first 16M.
+ *
+ * Requirement on bootloader:
+ *  - The page we're executing in needs to reside in TLB1 and
+ *    have IPROT=1.  If not an invalidate broadcast could
+ *    evict the entry we're currently executing in.
+ *
+ *  r3 = Index of TLB1 were executing in
+ *  r4 = Current MSR[IS]
+ *  r5 = Index of TLB1 temp mapping
+ *
+ * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0]
+ * if needed
+ */
+
+/* 1. Find the index of the entry we're executing in */
+       bl      invstr                          /* Find our address */
+invstr:        mflr    r6                              /* Make it accessible */
+       mfmsr   r7
+       rlwinm  r4,r7,27,31,31                  /* extract MSR[IS] */
+       mfspr   r7, SPRN_PID0
+       slwi    r7,r7,16
+       or      r7,r7,r4
+       mtspr   SPRN_MAS6,r7
+       tlbsx   0,r6                            /* search MSR[IS], SPID=PID0 */
+       mfspr   r7,SPRN_MAS1
+       andis.  r7,r7,MAS1_VALID@h
+       bne     match_TLB
+       mfspr   r7,SPRN_PID1
+       slwi    r7,r7,16
+       or      r7,r7,r4
+       mtspr   SPRN_MAS6,r7
+       tlbsx   0,r6                            /* search MSR[IS], SPID=PID1 */
+       mfspr   r7,SPRN_MAS1
+       andis.  r7,r7,MAS1_VALID@h
+       bne     match_TLB
+       mfspr   r7, SPRN_PID2
+       slwi    r7,r7,16
+       or      r7,r7,r4
+       mtspr   SPRN_MAS6,r7
+       tlbsx   0,r6                            /* Fall through, we had to match */
+match_TLB:
+       mfspr   r7,SPRN_MAS0
+       rlwinm  r3,r7,16,28,31                  /* Extract MAS0(Entry) */
+
+       mfspr   r7,SPRN_MAS1                    /* Insure IPROT set */
+       oris    r7,r7,MAS1_IPROT@h
+       mtspr   SPRN_MAS1,r7
+       tlbwe
+
+/* 2. Invalidate all entries except the entry we're executing in */
+       mfspr   r9,SPRN_TLB1CFG
+       andi.   r9,r9,0xfff
+       li      r6,0                            /* Set Entry counter to 0 */
+1:     lis     r7,0x1000                       /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r7,r6,16,12,15                  /* Setup MAS0 = TLBSEL | ESEL(r6) */
+       mtspr   SPRN_MAS0,r7
+       tlbre
+       mfspr   r7,SPRN_MAS1
+       rlwinm  r7,r7,0,2,31                    /* Clear MAS1 Valid and IPROT */
+       cmpw    r3,r6
+       beq     skpinv                          /* Dont update the current execution TLB */
+       mtspr   SPRN_MAS1,r7
+       tlbwe
+       isync
+skpinv:        addi    r6,r6,1                         /* Increment */
+       cmpw    r6,r9                           /* Are we done? */
+       bne     1b                              /* If not, repeat */
+
+       /* Invalidate TLB0 */
+       li      r6,0x04
+       tlbivax 0,r6
+#ifdef CONFIG_SMP
+       tlbsync
+#endif
+       /* Invalidate TLB1 */
+       li      r6,0x0c
+       tlbivax 0,r6
+#ifdef CONFIG_SMP
+       tlbsync
+#endif
+       msync
+
+/* 3. Setup a temp mapping and jump to it */
+       andi.   r5, r3, 0x1     /* Find an entry not used and is non-zero */
+       addi    r5, r5, 0x1
+       lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r7,r3,16,12,15  /* Setup MAS0 = TLBSEL | ESEL(r3) */
+       mtspr   SPRN_MAS0,r7
+       tlbre
+
+       /* Just modify the entry ID and EPN for the temp mapping */
+       lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r7,r5,16,12,15  /* Setup MAS0 = TLBSEL | ESEL(r5) */
+       mtspr   SPRN_MAS0,r7
+       xori    r6,r4,1         /* Setup TMP mapping in the other Address space */
+       slwi    r6,r6,12
+       oris    r6,r6,(MAS1_VALID|MAS1_IPROT)@h
+       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+       mtspr   SPRN_MAS1,r6
+       mfspr   r6,SPRN_MAS2
+       li      r7,0            /* temp EPN = 0 */
+       rlwimi  r7,r6,0,20,31
+       mtspr   SPRN_MAS2,r7
+       tlbwe
+
+       xori    r6,r4,1
+       slwi    r6,r6,5         /* setup new context with other address space */
+       bl      1f              /* Find our address */
+1:     mflr    r9
+       rlwimi  r7,r9,0,20,31
+       addi    r7,r7,24
+       mtspr   SRR0,r7
+       mtspr   SRR1,r6
+       rfi
+
+/* 4. Clear out PIDs & Search info */
+       li      r6,0
+       mtspr   SPRN_PID0,r6
+       mtspr   SPRN_PID1,r6
+       mtspr   SPRN_PID2,r6
+       mtspr   SPRN_MAS6,r6
+
+/* 5. Invalidate mapping we started in */
+       lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r7,r3,16,12,15  /* Setup MAS0 = TLBSEL | ESEL(r3) */
+       mtspr   SPRN_MAS0,r7
+       tlbre
+       li      r6,0
+       mtspr   SPRN_MAS1,r6
+       tlbwe
+       /* Invalidate TLB1 */
+       li      r9,0x0c
+       tlbivax 0,r9
+#ifdef CONFIG_SMP
+       tlbsync
+#endif
+       msync
+
+/* 6. Setup KERNELBASE mapping in TLB1[0] */
+       lis     r6,0x1000               /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
+       mtspr   SPRN_MAS0,r6
+       lis     r6,(MAS1_VALID|MAS1_IPROT)@h
+       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l
+       mtspr   SPRN_MAS1,r6
+       li      r7,0
+       lis     r6,KERNELBASE@h
+       ori     r6,r6,KERNELBASE@l
+       rlwimi  r6,r7,0,20,31
+       mtspr   SPRN_MAS2,r6
+       li      r7,(MAS3_SX|MAS3_SW|MAS3_SR)
+       mtspr   SPRN_MAS3,r7
+       tlbwe
+
+/* 7. Jump to KERNELBASE mapping */
+       li      r7,0
+       bl      1f                      /* Find our address */
+1:     mflr    r9
+       rlwimi  r6,r9,0,20,31
+       addi    r6,r6,24
+       mtspr   SRR0,r6
+       mtspr   SRR1,r7
+       rfi                             /* start execution out of TLB1[0] entry */
+
+/* 8. Clear out the temp mapping */
+       lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r7,r5,16,12,15  /* Setup MAS0 = TLBSEL | ESEL(r5) */
+       mtspr   SPRN_MAS0,r7
+       tlbre
+       mtspr   SPRN_MAS1,r8
+       tlbwe
+       /* Invalidate TLB1 */
+       li      r9,0x0c
+       tlbivax 0,r9
+#ifdef CONFIG_SMP
+       tlbsync
+#endif
+       msync
+
+       /* Establish the interrupt vector offsets */
+       SET_IVOR(0,  CriticalInput);
+       SET_IVOR(1,  MachineCheck);
+       SET_IVOR(2,  DataStorage);
+       SET_IVOR(3,  InstructionStorage);
+       SET_IVOR(4,  ExternalInput);
+       SET_IVOR(5,  Alignment);
+       SET_IVOR(6,  Program);
+       SET_IVOR(7,  FloatingPointUnavailable);
+       SET_IVOR(8,  SystemCall);
+       SET_IVOR(9,  AuxillaryProcessorUnavailable);
+       SET_IVOR(10, Decrementer);
+       SET_IVOR(11, FixedIntervalTimer);
+       SET_IVOR(12, WatchdogTimer);
+       SET_IVOR(13, DataTLBError);
+       SET_IVOR(14, InstructionTLBError);
+       SET_IVOR(15, Debug);
+       SET_IVOR(32, SPEUnavailable);
+       SET_IVOR(33, SPEFloatingPointData);
+       SET_IVOR(34, SPEFloatingPointRound);
+       SET_IVOR(35, PerformanceMonitor);
+
+       /* Establish the interrupt vector base */
+       lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
+       mtspr   SPRN_IVPR,r4
+
+       /* Setup the defaults for TLB entries */
+       li      r2,MAS4_TSIZED(BOOKE_PAGESZ_4K)
+       mtspr   SPRN_MAS4, r2
+
+#if 0
+       /* Enable DOZE */
+       mfspr   r2,SPRN_HID0
+       oris    r2,r2,HID0_DOZE@h
+       mtspr   SPRN_HID0, r2
+#endif
+
+       /*
+        * This is where the main kernel code starts.
+        */
+
+       /* ptr to current */
+       lis     r2,init_task@h
+       ori     r2,r2,init_task@l
+
+       /* ptr to current thread */
+       addi    r4,r2,THREAD    /* init task's THREAD */
+       mtspr   SPRG3,r4
+
+       /* stack */
+       lis     r1,init_thread_union@h
+       ori     r1,r1,init_thread_union@l
+       li      r0,0
+       stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+
+       bl      early_init
+
+       mfspr   r3,SPRN_TLB1CFG
+       andi.   r3,r3,0xfff
+       lis     r4,num_tlbcam_entries@ha
+       stw     r3,num_tlbcam_entries@l(r4)
+/*
+ * Decide what sort of machine this is and initialize the MMU.
+ */
+       mr      r3,r31
+       mr      r4,r30
+       mr      r5,r29
+       mr      r6,r28
+       mr      r7,r27
+       bl      machine_init
+       bl      MMU_init
+
+       /* Setup PTE pointers for the Abatron bdiGDB */
+       lis     r6, swapper_pg_dir@h
+       ori     r6, r6, swapper_pg_dir@l
+       lis     r5, abatron_pteptrs@h
+       ori     r5, r5, abatron_pteptrs@l
+       lis     r4, KERNELBASE@h
+       ori     r4, r4, KERNELBASE@l
+       stw     r5, 0(r4)       /* Save abatron_pteptrs at a fixed location */
+       stw     r6, 0(r5)
+
+       /* Let's move on */
+       lis     r4,start_kernel@h
+       ori     r4,r4,start_kernel@l
+       lis     r3,MSR_KERNEL@h
+       ori     r3,r3,MSR_KERNEL@l
+       mtspr   SRR0,r4
+       mtspr   SRR1,r3
+       rfi                     /* change context and jump to start_kernel */
+
+/*
+ * Interrupt vector entry code
+ *
+ * The Book E MMUs are always on so we don't need to handle
+ * interrupts in real mode as with previous PPC processors. In
+ * this case we handle interrupts in the kernel virtual address
+ * space.
+ *
+ * Interrupt vectors are dynamically placed relative to the
+ * interrupt prefix as determined by the address of interrupt_base.
+ * The interrupt vectors offsets are programmed using the labels
+ * for each interrupt vector entry.
+ *
+ * Interrupt vectors must be aligned on a 16 byte boundary.
+ * We align on a 32 byte cache line boundary for good measure.
+ */
+
+#define NORMAL_EXCEPTION_PROLOG                                                     \
+       mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
+       mtspr   SPRN_SPRG1,r11;                                              \
+       mtspr   SPRN_SPRG4W,r1;                                              \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_SRR1;          /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       beq     1f;                                                          \
+       mfspr   r1,SPRG3;               /* if from user, start at top of   */\
+       lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
+       addi    r1,r1,THREAD_SIZE;                                           \
+1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
+       tophys(r11,r1);                                                      \
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,GPR10(r11);                                              \
+       mfspr   r12,SPRG1;                                                   \
+       stw     r12,GPR11(r11);                                              \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r10,SPRG4R;                                                  \
+       mfspr   r12,SRR0;                                                    \
+       stw     r10,GPR1(r11);                                               \
+       mfspr   r9,SRR1;                                                     \
+       stw     r10,0(r11);                                                  \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for critical exceptions.  This is a little different
+ * from the normal exception prolog above since a critical exception
+ * can potentially occur at any point during normal exception processing.
+ * Thus we cannot use the same SPRG registers as the normal prolog above.
+ * Instead we use a couple of words of memory at low physical addresses.
+ * This is OK since we don't support SMP on these processors. For Book E
+ * processors, we also have a reserved register (SPRG2) that is only used
+ * in critical exceptions so we can free up a GPR to use as the base for
+ * indirect access to the critical exception save area.  This is necessary
+ * since the MMU is always on and the save area is offset from KERNELBASE.
+ */
+#define CRITICAL_EXCEPTION_PROLOG                                           \
+       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */   \
+       lis     r8,crit_save@ha;                                             \
+       stw     r10,crit_r10@l(r8);                                          \
+       stw     r11,crit_r11@l(r8);                                          \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,crit_sprg0@l(r8);                                        \
+       mfspr   r10,SPRG1;                                                   \
+       stw     r10,crit_sprg1@l(r8);                                        \
+       mfspr   r10,SPRG4R;                                                  \
+       stw     r10,crit_sprg4@l(r8);                                        \
+       mfspr   r10,SPRG5R;                                                  \
+       stw     r10,crit_sprg5@l(r8);                                        \
+       mfspr   r10,SPRG7R;                                                  \
+       stw     r10,crit_sprg7@l(r8);                                        \
+       mfspr   r10,SPRN_PID;                                                \
+       stw     r10,crit_pid@l(r8);                                          \
+       mfspr   r10,SRR0;                                                    \
+       stw     r10,crit_srr0@l(r8);                                         \
+       mfspr   r10,SRR1;                                                    \
+       stw     r10,crit_srr1@l(r8);                                         \
+       mfspr   r8,SPRG2;               /* SPRG2 only used in criticals */   \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_CSRR1;         /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       lis     r11,critical_stack_top@h;                                    \
+       ori     r11,r11,critical_stack_top@l;                                \
+       beq     1f;                                                          \
+       /* COMING FROM USER MODE */                                          \
+       mfspr   r11,SPRG3;              /* if from user, start at top of   */\
+       lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+       addi    r11,r11,THREAD_SIZE;                                         \
+1:     subi    r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame     */\
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r12,SPRN_DEAR;          /* save DEAR and ESR in the frame  */\
+       stw     r12,_DEAR(r11);         /* since they may have had stuff   */\
+       mfspr   r9,SPRN_ESR;            /* in them at the point where the  */\
+       stw     r9,_ESR(r11);           /* exception was taken             */\
+       mfspr   r12,CSRR0;                                                   \
+       stw     r1,GPR1(r11);                                                \
+       mfspr   r9,CSRR1;                                                    \
+       stw     r1,0(r11);                                                   \
+       tovirt(r1,r11);                                                      \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for machine check exceptions.  This is similar to
+ * the critical exception prolog, except that machine check exceptions
+ * have their own save area.  For Book E processors, we also have a
+ * reserved register (SPRG6) that is only used in machine check exceptions
+ * so we can free up a GPR to use as the base for indirect access to the
+ * machine check exception save area.  This is necessary since the MMU
+ * is always on and the save area is offset from KERNELBASE.
+ */
+#define MCHECK_EXCEPTION_PROLOG                                             \
+       mtspr   SPRG6W,r8;              /* SPRG6 used in machine checks */   \
+       lis     r8,mcheck_save@ha;                                           \
+       stw     r10,mcheck_r10@l(r8);                                        \
+       stw     r11,mcheck_r11@l(r8);                                        \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,mcheck_sprg0@l(r8);                                      \
+       mfspr   r10,SPRG1;                                                   \
+       stw     r10,mcheck_sprg1@l(r8);                                      \
+       mfspr   r10,SPRG4R;                                                  \
+       stw     r10,mcheck_sprg4@l(r8);                                      \
+       mfspr   r10,SPRG5R;                                                  \
+       stw     r10,mcheck_sprg5@l(r8);                                      \
+       mfspr   r10,SPRG7R;                                                  \
+       stw     r10,mcheck_sprg7@l(r8);                                      \
+       mfspr   r10,SPRN_PID;                                                \
+       stw     r10,mcheck_pid@l(r8);                                        \
+       mfspr   r10,SRR0;                                                    \
+       stw     r10,mcheck_srr0@l(r8);                                       \
+       mfspr   r10,SRR1;                                                    \
+       stw     r10,mcheck_srr1@l(r8);                                       \
+       mfspr   r10,CSRR0;                                                   \
+       stw     r10,mcheck_csrr0@l(r8);                                      \
+       mfspr   r10,CSRR1;                                                   \
+       stw     r10,mcheck_csrr1@l(r8);                                      \
+       mfspr   r8,SPRG6R;              /* SPRG6 used in machine checks */   \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_MCSRR1;        /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       lis     r11,mcheck_stack_top@h;                                      \
+       ori     r11,r11,mcheck_stack_top@l;                                  \
+       beq     1f;                                                          \
+       /* COMING FROM USER MODE */                                          \
+       mfspr   r11,SPRG3;              /* if from user, start at top of   */\
+       lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+       addi    r11,r11,THREAD_SIZE;                                         \
+1:     subi    r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame     */\
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r12,SPRN_DEAR;          /* save DEAR and ESR in the frame  */\
+       stw     r12,_DEAR(r11);         /* since they may have had stuff   */\
+       mfspr   r9,SPRN_ESR;            /* in them at the point where the  */\
+       stw     r9,_ESR(r11);           /* exception was taken             */\
+       mfspr   r12,MCSRR0;                                                  \
+       stw     r1,GPR1(r11);                                                \
+       mfspr   r9,MCSRR1;                                                   \
+       stw     r1,0(r11);                                                   \
+       tovirt(r1,r11);                                                      \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception vectors.
+ */
+#define        START_EXCEPTION(label)                                               \
+        .align 5;                                                                   \
+label:
+
+#define FINISH_EXCEPTION(func)                                 \
+       bl      transfer_to_handler_full;                       \
+       .long   func;                                           \
+       .long   ret_from_except_full
+
+#define EXCEPTION(n, label, hdlr, xfer)                                \
+       START_EXCEPTION(label);                                 \
+       NORMAL_EXCEPTION_PROLOG;                                \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr)                     \
+       START_EXCEPTION(label);                                 \
+       CRITICAL_EXCEPTION_PROLOG;                              \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+                         NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define MCHECK_EXCEPTION(n, label, hdlr)                       \
+       START_EXCEPTION(label);                                 \
+       MCHECK_EXCEPTION_PROLOG;                                \
+       mfspr   r5,SPRN_ESR;                                    \
+       stw     r5,_ESR(r11);                                   \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+                         NOCOPY, mcheck_transfer_to_handler,   \
+                         ret_from_mcheck_exc)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)  \
+       li      r10,trap;                                       \
+       stw     r10,TRAP(r11);                                  \
+       lis     r10,msr@h;                                      \
+       ori     r10,r10,msr@l;                                  \
+       copyee(r10, r9);                                        \
+       bl      tfer;                                           \
+       .long   hdlr;                                           \
+       .long   ret
+
+#define COPY_EE(d, s)          rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)          \
+       EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)         \
+       EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+                         ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)           \
+       EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)      \
+       EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
+                         ret_from_except)
+
+interrupt_base:
+       /* Critical Input Interrupt */
+       CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
+
+       /* Machine Check Interrupt */
+       MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+
+       /* Data Storage Interrupt */
+       START_EXCEPTION(DataStorage)
+       mtspr   SPRG0, r10              /* Save some working registers */
+       mtspr   SPRG1, r11
+       mtspr   SPRG4W, r12
+       mtspr   SPRG5W, r13
+       mfcr    r11
+       mtspr   SPRG7W, r11
+
+       /*
+        * Check if it was a store fault, if not then bail
+        * because a user tried to access a kernel or
+        * read-protected page.  Otherwise, get the
+        * offending address and handle it.
+        */
+       mfspr   r10, SPRN_ESR
+       andis.  r10, r10, ESR_ST@h
+       beq     2f
+
+       mfspr   r10, SPRN_DEAR          /* Get faulting address */
+
+       /* If we are faulting a kernel address, we have to use the
+        * kernel page tables.
+        */
+       lis     r11, TASK_SIZE@h
+       ori     r11, r11, TASK_SIZE@l
+       cmplw   0, r10, r11
+       bge     2f
+
+       /* Get the PGD for the current thread */
+3:
+       mfspr   r11,SPRG3
+       lwz     r11,PGDIR(r11)
+4:
+       rlwimi  r11, r10, 12, 20, 29    /* Create L1 (pgdir/pmd) address */
+       lwz     r11, 0(r11)             /* Get L1 entry */
+       rlwinm. r12, r11, 0, 0, 19      /* Extract L2 (pte) base address */
+       beq     2f                      /* Bail if no table */
+
+       rlwimi  r12, r10, 22, 20, 29    /* Compute PTE address */
+       lwz     r11, 0(r12)             /* Get Linux PTE */
+
+       /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */
+       andi.   r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE
+       cmpwi   0, r13, _PAGE_RW|_PAGE_USER
+       bne     2f                      /* Bail if not */
+
+       /* Update 'changed'. */
+       ori     r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+       stw     r11, 0(r12)             /* Update Linux page table */
+
+       /* MAS2 not updated as the entry does exist in the tlb, this
+          fault taken to detect state transition (eg: COW -> DIRTY)
+        */
+       lis     r12, MAS3_RPN@h
+       ori     r12, r12, _PAGE_HWEXEC | MAS3_RPN@l
+       and     r11, r11, r12
+       rlwimi  r11, r11, 31, 27, 27    /* SX <- _PAGE_HWEXEC */
+       ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
+
+       /* update search PID in MAS6, AS = 0 */
+       mfspr   r12, SPRN_PID0
+       slwi    r12, r12, 16
+       mtspr   SPRN_MAS6, r12
+
+       /* find the TLB index that caused the fault.  It has to be here. */
+       tlbsx   0, r10
+
+       mtspr   SPRN_MAS3,r11
+       tlbwe
+
+       /* Done...restore registers and get out of here.  */
+       mfspr   r11, SPRG7R
+       mtcr    r11
+       mfspr   r13, SPRG5R
+       mfspr   r12, SPRG4R
+       mfspr   r11, SPRG1
+       mfspr   r10, SPRG0
+       rfi                     /* Force context change */
+
+2:
+       /*
+        * The bailout.  Restore registers to pre-exception conditions
+        * and call the heavyweights to help us out.
+        */
+       mfspr   r11, SPRG7R
+       mtcr    r11
+       mfspr   r13, SPRG5R
+       mfspr   r12, SPRG4R
+       mfspr   r11, SPRG1
+       mfspr   r10, SPRG0
+       b       data_access
+
+       /* Instruction Storage Interrupt */
+       START_EXCEPTION(InstructionStorage)
+       NORMAL_EXCEPTION_PROLOG
+       mfspr   r5,SPRN_ESR             /* Grab the ESR and save it */
+       stw     r5,_ESR(r11)
+       mr      r4,r12                  /* Pass SRR0 as arg2 */
+       li      r5,0                    /* Pass zero as arg3 */
+       EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+
+       /* External Input Interrupt */
+       EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+
+       /* Alignment Interrupt */
+       START_EXCEPTION(Alignment)
+       NORMAL_EXCEPTION_PROLOG
+       mfspr   r4,SPRN_DEAR            /* Grab the DEAR and save it */
+       stw     r4,_DEAR(r11)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE(0x0600, AlignmentException)
+
+       /* Program Interrupt */
+       START_EXCEPTION(Program)
+       NORMAL_EXCEPTION_PROLOG
+       mfspr   r4,SPRN_ESR             /* Grab the ESR and save it */
+       stw     r4,_ESR(r11)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_STD(0x0700, ProgramCheckException)
+
+       /* Floating Point Unavailable Interrupt */
+       EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
+
+       /* System Call Interrupt */
+       START_EXCEPTION(SystemCall)
+       NORMAL_EXCEPTION_PROLOG
+       EXC_XFER_EE_LITE(0x0c00, DoSyscall)
+
+       /* Auxillary Processor Unavailable Interrupt */
+       EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE)
+
+       /* Decrementer Interrupt */
+       START_EXCEPTION(Decrementer)
+       NORMAL_EXCEPTION_PROLOG
+       lis     r0,TSR_DIS@h            /* Setup the DEC interrupt mask */
+       mtspr   SPRN_TSR,r0             /* Clear the DEC interrupt */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_LITE(0x0900, timer_interrupt)
+
+       /* Fixed Internal Timer Interrupt */
+       /* TODO: Add FIT support */
+       EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
+
+       /* Watchdog Timer Interrupt */
+       /* TODO: Add watchdog support */
+       CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
+
+       /* Data TLB Error Interrupt */
+       START_EXCEPTION(DataTLBError)
+       mtspr   SPRG0, r10              /* Save some working registers */
+       mtspr   SPRG1, r11
+       mtspr   SPRG4W, r12
+       mtspr   SPRG5W, r13
+       mfcr    r11
+       mtspr   SPRG7W, r11
+       mfspr   r10, SPRN_DEAR          /* Get faulting address */
+
+       /* If we are faulting a kernel address, we have to use the
+        * kernel page tables.
+        */
+       lis     r11, TASK_SIZE@h
+       ori     r11, r11, TASK_SIZE@l
+       cmplw   5, r10, r11
+       blt     5, 3f
+       lis     r11, swapper_pg_dir@h
+       ori     r11, r11, swapper_pg_dir@l
+
+       mfspr   r12,SPRN_MAS1           /* Set TID to 0 */
+       li      r13,MAS1_TID@l
+       andc    r12,r12,r13
+       mtspr   SPRN_MAS1,r12
+
+       b       4f
+
+       /* Get the PGD for the current thread */
+3:
+       mfspr   r11,SPRG3
+       lwz     r11,PGDIR(r11)
+
+4:
+       rlwimi  r11, r10, 12, 20, 29    /* Create L1 (pgdir/pmd) address */
+       lwz     r11, 0(r11)             /* Get L1 entry */
+       rlwinm. r12, r11, 0, 0, 19      /* Extract L2 (pte) base address */
+       beq     2f                      /* Bail if no table */
+
+       rlwimi  r12, r10, 22, 20, 29    /* Compute PTE address */
+       lwz     r11, 0(r12)             /* Get Linux PTE */
+       andi.   r13, r11, _PAGE_PRESENT
+       beq     2f
+
+       ori     r11, r11, _PAGE_ACCESSED
+       stw     r11, 0(r12)
+
+        /* Jump to common tlb load */
+       b       finish_tlb_load
+2:
+       /* The bailout.  Restore registers to pre-exception conditions
+        * and call the heavyweights to help us out.
+        */
+       mfspr   r11, SPRG7R
+       mtcr    r11
+       mfspr   r13, SPRG5R
+       mfspr   r12, SPRG4R
+       mfspr   r11, SPRG1
+       mfspr   r10, SPRG0
+       b       data_access
+
+       /* Instruction TLB Error Interrupt */
+       /*
+        * Nearly the same as above, except we get our
+        * information from different registers and bailout
+        * to a different point.
+        */
+       START_EXCEPTION(InstructionTLBError)
+       mtspr   SPRG0, r10              /* Save some working registers */
+       mtspr   SPRG1, r11
+       mtspr   SPRG4W, r12
+       mtspr   SPRG5W, r13
+       mfcr    r11
+       mtspr   SPRG7W, r11
+       mfspr   r10, SRR0               /* Get faulting address */
+
+       /* If we are faulting a kernel address, we have to use the
+        * kernel page tables.
+        */
+       lis     r11, TASK_SIZE@h
+       ori     r11, r11, TASK_SIZE@l
+       cmplw   5, r10, r11
+       blt     5, 3f
+       lis     r11, swapper_pg_dir@h
+       ori     r11, r11, swapper_pg_dir@l
+
+       mfspr   r12,SPRN_MAS1           /* Set TID to 0 */
+       li      r13,MAS1_TID@l
+       andc    r12,r12,r13
+       mtspr   SPRN_MAS1,r12
+
+       b       4f
+
+       /* Get the PGD for the current thread */
+3:
+       mfspr   r11,SPRG3
+       lwz     r11,PGDIR(r11)
+
+4:
+       rlwimi  r11, r10, 12, 20, 29    /* Create L1 (pgdir/pmd) address */
+       lwz     r11, 0(r11)             /* Get L1 entry */
+       rlwinm. r12, r11, 0, 0, 19      /* Extract L2 (pte) base address */
+       beq     2f                      /* Bail if no table */
+
+       rlwimi  r12, r10, 22, 20, 29    /* Compute PTE address */
+       lwz     r11, 0(r12)             /* Get Linux PTE */
+       andi.   r13, r11, _PAGE_PRESENT
+       beq     2f
+
+       ori     r11, r11, _PAGE_ACCESSED
+       stw     r11, 0(r12)
+
+       /* Jump to common TLB load point */
+       b       finish_tlb_load
+
+2:
+       /* The bailout.  Restore registers to pre-exception conditions
+        * and call the heavyweights to help us out.
+        */
+       mfspr   r11, SPRG7R
+       mtcr    r11
+       mfspr   r13, SPRG5R
+       mfspr   r12, SPRG4R
+       mfspr   r11, SPRG1
+       mfspr   r10, SPRG0
+       b       InstructionStorage
+
+#ifdef CONFIG_SPE
+       /* SPE Unavailable */
+       START_EXCEPTION(SPEUnavailable)
+       NORMAL_EXCEPTION_PROLOG
+       bne     load_up_spe
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE_LITE(0x2010, KernelSPE)
+#else
+       EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+       /* SPE Floating Point Data */
+#ifdef CONFIG_SPE
+       EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
+#else
+       EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+       /* SPE Floating Point Round */
+       EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE)
+
+       /* Performance Monitor */
+       EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE)
+
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_SRR1, which will still have
+ * the MSR_DE bit set.
+ */
+       /* Debug Interrupt */
+       START_EXCEPTION(Debug)
+       CRITICAL_EXCEPTION_PROLOG
+
+       /*
+        * If this is a single step or branch-taken exception in an
+        * exception entry sequence, it was probably meant to apply to
+        * the code where the exception occurred (since exception entry
+        * doesn't turn off DE automatically).  We simulate the effect
+        * of turning off DE on entry to an exception handler by turning
+        * off DE in the CSRR1 value and clearing the debug status.
+        */
+       mfspr   r10,SPRN_DBSR           /* check single-step/branch taken */
+       andis.  r10,r10,(DBSR_IC|DBSR_BT)@h
+       beq+    1f
+       andi.   r0,r9,MSR_PR            /* check supervisor */
+       beq     2f                      /* branch if we need to fix it up... */
+
+       /* continue normal handling for a critical exception... */
+1:     mfspr   r4,SPRN_DBSR
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_TEMPLATE(DebugException, 0x2002, \
+               (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+               NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+
+       /* here it looks like we got an inappropriate debug exception. */
+2:     rlwinm  r9,r9,0,~MSR_DE         /* clear DE in the CSRR1 value */
+       mtspr   SPRN_DBSR,r10           /* clear the IC/BT debug intr status */
+       /* restore state and get out */
+       lwz     r10,_CCR(r11)
+       lwz     r0,GPR0(r11)
+       lwz     r1,GPR1(r11)
+       mtcrf   0x80,r10
+       mtspr   CSRR0,r12
+       mtspr   CSRR1,r9
+       lwz     r9,GPR9(r11)
+
+       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */
+       lis     r8,crit_save@ha;
+       lwz     r10,crit_r10@l(r8)
+       lwz     r11,crit_r11@l(r8)
+       mfspr   r8,SPRG2
+
+       rfci
+       b       .
+
+/*
+ * Local functions
+ */
+       /*
+        * Data TLB exceptions will bail out to this point
+        * if they can't resolve the lightweight TLB fault.
+        */
+data_access:
+       NORMAL_EXCEPTION_PROLOG
+       mfspr   r5,SPRN_ESR             /* Grab the ESR, save it, pass arg3 */
+       stw     r5,_ESR(r11)
+       mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
+       andis.  r10,r5,(ESR_ILK|ESR_DLK)@h
+       bne     1f
+       EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+1:
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_EE_LITE(0x0300, CacheLockingException)
+
+/*
+
+ * Both the instruction and data TLB miss get to this
+ * point to load the TLB.
+ *     r10 - EA of fault
+ *     r11 - TLB (info from Linux PTE)
+ *     r12, r13 - available to use
+ *     CR5 - results of addr < TASK_SIZE
+ *     MAS0, MAS1 - loaded with proper value when we get here
+ *     MAS2, MAS3 - will need additional info from Linux PTE
+ *     Upon exit, we reload everything and RFI.
+ */
+finish_tlb_load:
+       /*
+        * We set execute, because we don't have the granularity to
+        * properly set this at the page level (Linux problem).
+        * Many of these bits are software only.  Bits we don't set
+        * here we (properly should) assume have the appropriate value.
+        */
+
+       mfspr   r12, SPRN_MAS2
+       rlwimi  r12, r11, 26, 27, 31    /* extract WIMGE from pte */
+       mtspr   SPRN_MAS2, r12
+
+       bge     5, 1f
+
+       /* addr > TASK_SIZE */
+       li      r10, (MAS3_UX | MAS3_UW | MAS3_UR)
+       andi.   r13, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC)
+       andi.   r12, r11, _PAGE_USER    /* Test for _PAGE_USER */
+       iseleq  r12, 0, r10
+       and     r10, r12, r13
+       srwi    r12, r10, 1
+       or      r12, r12, r10   /* Copy user perms into supervisor */
+       b       2f
+
+       /* addr <= TASK_SIZE */
+1:     rlwinm  r12, r11, 31, 29, 29    /* Extract _PAGE_HWWRITE into SW */
+       ori     r12, r12, (MAS3_SX | MAS3_SR)
+
+2:     rlwimi  r11, r12, 0, 20, 31     /* Extract RPN from PTE and merge with perms */
+       mtspr   SPRN_MAS3, r11
+       tlbwe
+
+       /* Done...restore registers and get out of here.  */
+       mfspr   r11, SPRG7R
+       mtcr    r11
+       mfspr   r13, SPRG5R
+       mfspr   r12, SPRG4R
+       mfspr   r11, SPRG1
+       mfspr   r10, SPRG0
+       rfi                                     /* Force context change */
+
+#ifdef CONFIG_SPE
+/* Note that the SPE support is closely modeled after the AltiVec
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_spe:
+/*
+ * Disable SPE for the task which had SPE previously,
+ * and save its SPE registers in its thread_struct.
+ * Enables SPE for use in the kernel on return.
+ * On SMP we know the SPE units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+       mfmsr   r5
+       oris    r5,r5,MSR_SPE@h
+       mtmsr   r5                      /* enable use of SPE now */
+       isync
+/*
+ * For SMP, we don't do lazy SPE switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_spe in switch_to.
+ */
+#ifndef CONFIG_SMP
+       lis     r3,last_task_used_spe@ha
+       lwz     r4,last_task_used_spe@l(r3)
+       cmpi    0,r4,0
+       beq     1f
+       addi    r4,r4,THREAD    /* want THREAD of last_task_used_spe */
+       SAVE_32EVR(0,r10,r4)
+       evxor   evr10, evr10, evr10     /* clear out evr10 */
+       evmwumiaa evr10, evr10, evr10   /* evr10 <- ACC = 0 * 0 + ACC */
+       li      r5,THREAD_ACC
+       evstddx evr10, r4, r5           /* save off accumulator */
+       lwz     r5,PT_REGS(r4)
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r10,MSR_SPE@h
+       andc    r4,r4,r10       /* disable SPE for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+       /* enable use of SPE after return */
+       oris    r9,r9,MSR_SPE@h
+       mfspr   r5,SPRG3                /* current task's THREAD (phys) */
+       li      r4,1
+       li      r10,THREAD_ACC
+       stw     r4,THREAD_USED_SPE(r5)
+       evlddx  evr4,r10,r5
+       evmra   evr4,evr4
+       REST_32EVR(0,r10,r5)
+#ifndef CONFIG_SMP
+       subi    r4,r5,THREAD
+       stw     r4,last_task_used_spe@l(r3)
+#endif /* CONFIG_SMP */
+       /* restore registers and return */
+2:     REST_4GPRS(3, r11)
+       lwz     r10,_CCR(r11)
+       REST_GPR(1, r11)
+       mtcr    r10
+       lwz     r10,_LINK(r11)
+       mtlr    r10
+       REST_GPR(10, r11)
+       mtspr   SRR1,r9
+       mtspr   SRR0,r12
+       REST_GPR(9, r11)
+       REST_GPR(12, r11)
+       lwz     r11,GPR11(r11)
+       SYNC
+       rfi
+
+
+
+/*
+ * SPE unavailable trap from kernel - print a message, but let
+ * the task use SPE in the kernel until it returns to user mode.
+ */
+KernelSPE:
+       lwz     r3,_MSR(r1)
+       oris    r3,r3,MSR_SPE@h
+       stw     r3,_MSR(r1)     /* enable use of SPE after return */
+       lis     r3,87f@h
+       ori     r3,r3,87f@l
+       mr      r4,r2           /* current */
+       lwz     r5,_NIP(r1)
+       bl      printk
+       b       ret_from_except
+87:    .string "SPE used in kernel  (task=%p, pc=%x)  \n"
+       .align  4,0
+
+#endif /* CONFIG_SPE */
+
+/*
+ * Global functions
+ */
+
+/*
+ * extern void loadcam_entry(unsigned int index)
+ *
+ * Load TLBCAM[index] entry in to the L2 CAM MMU
+ */
+_GLOBAL(loadcam_entry)
+       lis     r4,TLBCAM@ha
+       addi    r4,r4,TLBCAM@l
+       mulli   r5,r3,20
+       add     r3,r5,r4
+       lwz     r4,0(r3)
+       mtspr   SPRN_MAS0,r4
+       lwz     r4,4(r3)
+       mtspr   SPRN_MAS1,r4
+       lwz     r4,8(r3)
+       mtspr   SPRN_MAS2,r4
+       lwz     r4,12(r3)
+       mtspr   SPRN_MAS3,r4
+       tlbwe
+       isync
+       blr
+
+/*
+ * extern void giveup_altivec(struct task_struct *prev)
+ *
+ * The e500 core does not have an AltiVec unit.
+ */
+_GLOBAL(giveup_altivec)
+       blr
+
+#ifdef CONFIG_SPE
+/*
+ * extern void giveup_spe(struct task_struct *prev)
+ *
+ */
+_GLOBAL(giveup_spe)
+       mfmsr   r5
+       oris    r5,r5,MSR_SPE@h
+       SYNC
+       mtmsr   r5                      /* enable use of SPE now */
+       isync
+       cmpi    0,r3,0
+       beqlr-                          /* if no previous owner, done */
+       addi    r3,r3,THREAD            /* want THREAD of task */
+       lwz     r5,PT_REGS(r3)
+       cmpi    0,r5,0
+       SAVE_32EVR(0, r4, r3)
+       evxor   evr6, evr6, evr6        /* clear out evr6 */
+       evmwumiaa evr6, evr6, evr6      /* evr6 <- ACC = 0 * 0 + ACC */
+       li      r4,THREAD_ACC
+       evstddx evr6, r4, r3            /* save off accumulator */
+       mfspr   r6,SPRN_SPEFSCR
+       stw     r6,THREAD_SPEFSCR(r3)   /* save spefscr register value */
+       beq     1f
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r3,MSR_SPE@h
+       andc    r4,r4,r3                /* disable SPE for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+       li      r5,0
+       lis     r4,last_task_used_spe@ha
+       stw     r5,last_task_used_spe@l(r4)
+#endif /* CONFIG_SMP */
+       blr
+#endif /* CONFIG_SPE */
+
+/*
+ * extern void giveup_fpu(struct task_struct *prev)
+ *
+ * The e500 core does not have an FPU.
+ */
+_GLOBAL(giveup_fpu)
+       blr
+
+/*
+ * extern void abort(void)
+ *
+ * At present, this routine just applies a system reset.
+ */
+_GLOBAL(abort)
+       li      r13,0
+        mtspr   SPRN_DBCR0,r13         /* disable all debug events */
+       mfmsr   r13
+       ori     r13,r13,MSR_DE@l        /* Enable Debug Events */
+       mtmsr   r13
+        mfspr   r13,SPRN_DBCR0
+        lis    r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
+        mtspr   SPRN_DBCR0,r13
+
+_GLOBAL(set_context)
+
+#ifdef CONFIG_BDI_SWITCH
+       /* Context switch the PTE pointer for the Abatron BDI2000.
+        * The PGDIR is the second parameter.
+        */
+       lis     r5, abatron_pteptrs@h
+       ori     r5, r5, abatron_pteptrs@l
+       stw     r4, 0x4(r5)
+#endif
+       mtspr   SPRN_PID,r3
+       isync                   /* Force context change */
+       blr
+
+/*
+ * We put a few things here that have to be page-aligned. This stuff
+ * goes at the beginning of the data segment, which is page-aligned.
+ */
+       .data
+_GLOBAL(sdata)
+_GLOBAL(empty_zero_page)
+       .space  4096
+_GLOBAL(swapper_pg_dir)
+       .space  4096
+
+       .section .bss
+/* Stack for handling critical exceptions from kernel mode */
+critical_stack_bottom:
+       .space 4096
+critical_stack_top:
+       .previous
+
+/* Stack for handling machine check exceptions from kernel mode */
+mcheck_stack_bottom:
+       .space 4096
+mcheck_stack_top:
+       .previous
+
+/*
+ * This area is used for temporarily saving registers during the
+ * critical and machine check exception prologs. It must always
+ * follow the page aligned allocations, so it starts on a page
+ * boundary, ensuring that all crit_save areas are in a single
+ * page.
+ */
+
+/* crit_save */
+_GLOBAL(crit_save)
+       .space  4
+_GLOBAL(crit_r10)
+       .space  4
+_GLOBAL(crit_r11)
+       .space  4
+_GLOBAL(crit_sprg0)
+       .space  4
+_GLOBAL(crit_sprg1)
+       .space  4
+_GLOBAL(crit_sprg4)
+       .space  4
+_GLOBAL(crit_sprg5)
+       .space  4
+_GLOBAL(crit_sprg7)
+       .space  4
+_GLOBAL(crit_pid)
+       .space  4
+_GLOBAL(crit_srr0)
+       .space  4
+_GLOBAL(crit_srr1)
+       .space  4
+
+/* mcheck_save */
+_GLOBAL(mcheck_save)
+       .space  4
+_GLOBAL(mcheck_r10)
+       .space  4
+_GLOBAL(mcheck_r11)
+       .space  4
+_GLOBAL(mcheck_sprg0)
+       .space  4
+_GLOBAL(mcheck_sprg1)
+       .space  4
+_GLOBAL(mcheck_sprg4)
+       .space  4
+_GLOBAL(mcheck_sprg5)
+       .space  4
+_GLOBAL(mcheck_sprg7)
+       .space  4
+_GLOBAL(mcheck_pid)
+       .space  4
+_GLOBAL(mcheck_srr0)
+       .space  4
+_GLOBAL(mcheck_srr1)
+       .space  4
+_GLOBAL(mcheck_csrr0)
+       .space  4
+_GLOBAL(mcheck_csrr1)
+       .space  4
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+_GLOBAL(cmd_line)
+       .space  512
+
+/*
+ * Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+       .space  8
+
+
diff --git a/arch/ppc/kernel/vecemu.c b/arch/ppc/kernel/vecemu.c
new file mode 100644 (file)
index 0000000..604d094
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Routines to emulate some Altivec/VMX instructions, specifically
+ * those that can trap when given denormalized operands in Java mode.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+/* Functions in vector.S */
+extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b);
+extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b);
+extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c);
+extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c);
+extern void vrefp(vector128 *dst, vector128 *src);
+extern void vrsqrtefp(vector128 *dst, vector128 *src);
+extern void vexptep(vector128 *dst, vector128 *src);
+
+static unsigned int exp2s[8] = {
+       0x800000,
+       0x8b95c2,
+       0x9837f0,
+       0xa5fed7,
+       0xb504f3,
+       0xc5672a,
+       0xd744fd,
+       0xeac0c7
+};
+
+/*
+ * Computes an estimate of 2^x.  The `s' argument is the 32-bit
+ * single-precision floating-point representation of x.
+ */
+static unsigned int eexp2(unsigned int s)
+{
+       int exp, pwr;
+       unsigned int mant, frac;
+
+       /* extract exponent field from input */
+       exp = ((s >> 23) & 0xff) - 127;
+       if (exp > 7) {
+               /* check for NaN input */
+               if (exp == 128 && (s & 0x7fffff) != 0)
+                       return s | 0x400000;    /* return QNaN */
+               /* 2^-big = 0, 2^+big = +Inf */
+               return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */
+       }
+       if (exp < -23)
+               return 0x3f800000;      /* 1.0 */
+
+       /* convert to fixed point integer in 9.23 representation */
+       pwr = (s & 0x7fffff) | 0x800000;
+       if (exp > 0)
+               pwr <<= exp;
+       else
+               pwr >>= -exp;
+       if (s & 0x80000000)
+               pwr = -pwr;
+
+       /* extract integer part, which becomes exponent part of result */
+       exp = (pwr >> 23) + 126;
+       if (exp >= 254)
+               return 0x7f800000;
+       if (exp < -23)
+               return 0;
+
+       /* table lookup on top 3 bits of fraction to get mantissa */
+       mant = exp2s[(pwr >> 20) & 7];
+
+       /* linear interpolation using remaining 20 bits of fraction */
+       asm("mulhwu %0,%1,%2" : "=r" (frac)
+           : "r" (pwr << 12), "r" (0x172b83ff));
+       asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant));
+       mant += frac;
+
+       if (exp >= 0)
+               return mant + (exp << 23);
+
+       /* denormalized result */
+       exp = -exp;
+       mant += 1 << (exp - 1);
+       return mant >> exp;
+}
+
+/*
+ * Computes an estimate of log_2(x).  The `s' argument is the 32-bit
+ * single-precision floating-point representation of x.
+ */
+static unsigned int elog2(unsigned int s)
+{
+       int exp, mant, lz, frac;
+
+       exp = s & 0x7f800000;
+       mant = s & 0x7fffff;
+       if (exp == 0x7f800000) {        /* Inf or NaN */
+               if (mant != 0)
+                       s |= 0x400000;  /* turn NaN into QNaN */
+               return s;
+       }
+       if ((exp | mant) == 0)          /* +0 or -0 */
+               return 0xff800000;      /* return -Inf */
+
+       if (exp == 0) {
+               /* denormalized */
+               asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant));
+               mant <<= lz - 8;
+               exp = (-118 - lz) << 23;
+       } else {
+               mant |= 0x800000;
+               exp -= 127 << 23;
+       }
+
+       if (mant >= 0xb504f3) {                         /* 2^0.5 * 2^23 */
+               exp |= 0x400000;                        /* 0.5 * 2^23 */
+               asm("mulhwu %0,%1,%2" : "=r" (mant)
+                   : "r" (mant), "r" (0xb504f334));    /* 2^-0.5 * 2^32 */
+       }
+       if (mant >= 0x9837f0) {                         /* 2^0.25 * 2^23 */
+               exp |= 0x200000;                        /* 0.25 * 2^23 */
+               asm("mulhwu %0,%1,%2" : "=r" (mant)
+                   : "r" (mant), "r" (0xd744fccb));    /* 2^-0.25 * 2^32 */
+       }
+       if (mant >= 0x8b95c2) {                         /* 2^0.125 * 2^23 */
+               exp |= 0x100000;                        /* 0.125 * 2^23 */
+               asm("mulhwu %0,%1,%2" : "=r" (mant)
+                   : "r" (mant), "r" (0xeac0c6e8));    /* 2^-0.125 * 2^32 */
+       }
+       if (mant > 0x800000) {                          /* 1.0 * 2^23 */
+               /* calculate (mant - 1) * 1.381097463 */
+               /* 1.381097463 == 0.125 / (2^0.125 - 1) */
+               asm("mulhwu %0,%1,%2" : "=r" (frac)
+                   : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a));
+               exp += frac;
+       }
+       s = exp & 0x80000000;
+       if (exp != 0) {
+               if (s)
+                       exp = -exp;
+               asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp));
+               lz = 8 - lz;
+               if (lz > 0)
+                       exp >>= lz;
+               else if (lz < 0)
+                       exp <<= -lz;
+               s += ((lz + 126) << 23) + exp;
+       }
+       return s;
+}
+
+#define VSCR_SAT       1
+
+static int ctsxs(unsigned int x, int scale, unsigned int *vscrp)
+{
+       int exp, mant;
+
+       exp = (x >> 23) & 0xff;
+       mant = x & 0x7fffff;
+       if (exp == 255 && mant != 0)
+               return 0;               /* NaN -> 0 */
+       exp = exp - 127 + scale;
+       if (exp < 0)
+               return 0;               /* round towards zero */
+       if (exp >= 31) {
+               /* saturate, unless the result would be -2^31 */
+               if (x + (scale << 23) != 0xcf000000)
+                       *vscrp |= VSCR_SAT;
+               return (x & 0x80000000)? 0x80000000: 0x7fffffff;
+       }
+       mant |= 0x800000;
+       mant = (mant << 7) >> (30 - exp);
+       return (x & 0x80000000)? -mant: mant;
+}
+
+static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp)
+{
+       int exp;
+       unsigned int mant;
+
+       exp = (x >> 23) & 0xff;
+       mant = x & 0x7fffff;
+       if (exp == 255 && mant != 0)
+               return 0;               /* NaN -> 0 */
+       exp = exp - 127 + scale;
+       if (exp < 0)
+               return 0;               /* round towards zero */
+       if (x & 0x80000000) {
+               /* negative => saturate to 0 */
+               *vscrp |= VSCR_SAT;
+               return 0;
+       }
+       if (exp >= 32) {
+               /* saturate */
+               *vscrp |= VSCR_SAT;
+               return 0xffffffff;
+       }
+       mant |= 0x800000;
+       mant = (mant << 8) >> (31 - exp);
+       return mant;
+}
+
+/* Round to floating integer, towards 0 */
+static unsigned int rfiz(unsigned int x)
+{
+       int exp;
+
+       exp = ((x >> 23) & 0xff) - 127;
+       if (exp == 128 && (x & 0x7fffff) != 0)
+               return x | 0x400000;    /* NaN -> make it a QNaN */
+       if (exp >= 23)
+               return x;               /* it's an integer already (or Inf) */
+       if (exp < 0)
+               return x & 0x80000000;  /* |x| < 1.0 rounds to 0 */
+       return x & ~(0x7fffff >> exp);
+}
+
+/* Round to floating integer, towards +/- Inf */
+static unsigned int rfii(unsigned int x)
+{
+       int exp, mask;
+
+       exp = ((x >> 23) & 0xff) - 127;
+       if (exp == 128 && (x & 0x7fffff) != 0)
+               return x | 0x400000;    /* NaN -> make it a QNaN */
+       if (exp >= 23)
+               return x;               /* it's an integer already (or Inf) */
+       if ((x & 0x7fffffff) == 0)
+               return x;               /* +/-0 -> +/-0 */
+       if (exp < 0)
+               /* 0 < |x| < 1.0 rounds to +/- 1.0 */
+               return (x & 0x80000000) | 0x3f800000;
+       mask = 0x7fffff >> exp;
+       /* mantissa overflows into exponent - that's OK,
+          it can't overflow into the sign bit */
+       return (x + mask) & ~mask;
+}
+
+/* Round to floating integer, to nearest */
+static unsigned int rfin(unsigned int x)
+{
+       int exp, half;
+
+       exp = ((x >> 23) & 0xff) - 127;
+       if (exp == 128 && (x & 0x7fffff) != 0)
+               return x | 0x400000;    /* NaN -> make it a QNaN */
+       if (exp >= 23)
+               return x;               /* it's an integer already (or Inf) */
+       if (exp < -1)
+               return x & 0x80000000;  /* |x| < 0.5 -> +/-0 */
+       if (exp == -1)
+               /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */
+               return (x & 0x80000000) | 0x3f800000;
+       half = 0x400000 >> exp;
+       /* add 0.5 to the magnitude and chop off the fraction bits */
+       return (x + half) & ~(0x7fffff >> exp);
+}
+
+int emulate_altivec(struct pt_regs *regs)
+{
+       unsigned int instr, i;
+       unsigned int va, vb, vc, vd;
+       vector128 *vrs;
+
+       if (get_user(instr, (unsigned int __user *) regs->nip))
+               return -EFAULT;
+       if ((instr >> 26) != 4)
+               return -EINVAL;         /* not an altivec instruction */
+       vd = (instr >> 21) & 0x1f;
+       va = (instr >> 16) & 0x1f;
+       vb = (instr >> 11) & 0x1f;
+       vc = (instr >> 6) & 0x1f;
+
+       vrs = current->thread.vr;
+       switch (instr & 0x3f) {
+       case 10:
+               switch (vc) {
+               case 0: /* vaddfp */
+                       vaddfp(&vrs[vd], &vrs[va], &vrs[vb]);
+                       break;
+               case 1: /* vsubfp */
+                       vsubfp(&vrs[vd], &vrs[va], &vrs[vb]);
+                       break;
+               case 4: /* vrefp */
+                       vrefp(&vrs[vd], &vrs[vb]);
+                       break;
+               case 5: /* vrsqrtefp */
+                       vrsqrtefp(&vrs[vd], &vrs[vb]);
+                       break;
+               case 6: /* vexptefp */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = eexp2(vrs[vb].u[i]);
+                       break;
+               case 7: /* vlogefp */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = elog2(vrs[vb].u[i]);
+                       break;
+               case 8:         /* vrfin */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = rfin(vrs[vb].u[i]);
+                       break;
+               case 9:         /* vrfiz */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = rfiz(vrs[vb].u[i]);
+                       break;
+               case 10:        /* vrfip */
+                       for (i = 0; i < 4; ++i) {
+                               u32 x = vrs[vb].u[i];
+                               x = (x & 0x80000000)? rfiz(x): rfii(x);
+                               vrs[vd].u[i] = x;
+                       }
+                       break;
+               case 11:        /* vrfim */
+                       for (i = 0; i < 4; ++i) {
+                               u32 x = vrs[vb].u[i];
+                               x = (x & 0x80000000)? rfii(x): rfiz(x);
+                               vrs[vd].u[i] = x;
+                       }
+                       break;
+               case 14:        /* vctuxs */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va,
+                                               &current->thread.vscr.u[3]);
+                       break;
+               case 15:        /* vctsxs */
+                       for (i = 0; i < 4; ++i)
+                               vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va,
+                                               &current->thread.vscr.u[3]);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case 46:        /* vmaddfp */
+               vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]);
+               break;
+       case 47:        /* vnmsubfp */
+               vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c
new file mode 100644 (file)
index 0000000..1037656
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+ * arch/ppc/syslib/rheap.c
+ *
+ * A Remote Heap.  Remote means that we don't touch the memory that the
+ * heap points to. Normal heap implementations use the memory they manage
+ * to place their list. We cannot do that because the memory we manage may
+ * have special properties, for example it is uncachable or of different
+ * endianess.
+ *
+ * Author: Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2004 (c) INTRACOM S.A. Greece. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm/rheap.h>
+
+/*
+ * Fixup a list_head, needed when copying lists.  If the pointers fall
+ * between s and e, apply the delta.  This assumes that
+ * sizeof(struct list_head *) == sizeof(unsigned long *).
+ */
+static inline void fixup(unsigned long s, unsigned long e, int d,
+                        struct list_head *l)
+{
+       unsigned long *pp;
+
+       pp = (unsigned long *)&l->next;
+       if (*pp >= s && *pp < e)
+               *pp += d;
+
+       pp = (unsigned long *)&l->prev;
+       if (*pp >= s && *pp < e)
+               *pp += d;
+}
+
+/* Grow the allocated blocks */
+static int grow(rh_info_t * info, int max_blocks)
+{
+       rh_block_t *block, *blk;
+       int i, new_blocks;
+       int delta;
+       unsigned long blks, blke;
+
+       if (max_blocks <= info->max_blocks)
+               return -EINVAL;
+
+       new_blocks = max_blocks - info->max_blocks;
+
+       block = kmalloc(sizeof(rh_block_t) * max_blocks, GFP_KERNEL);
+       if (block == NULL)
+               return -ENOMEM;
+
+       if (info->max_blocks > 0) {
+
+               /* copy old block area */
+               memcpy(block, info->block,
+                      sizeof(rh_block_t) * info->max_blocks);
+
+               delta = (char *)block - (char *)info->block;
+
+               /* and fixup list pointers */
+               blks = (unsigned long)info->block;
+               blke = (unsigned long)(info->block + info->max_blocks);
+
+               for (i = 0, blk = block; i < info->max_blocks; i++, blk++)
+                       fixup(blks, blke, delta, &blk->list);
+
+               fixup(blks, blke, delta, &info->empty_list);
+               fixup(blks, blke, delta, &info->free_list);
+               fixup(blks, blke, delta, &info->taken_list);
+
+               /* free the old allocated memory */
+               if ((info->flags & RHIF_STATIC_BLOCK) == 0)
+                       kfree(info->block);
+       }
+
+       info->block = block;
+       info->empty_slots += new_blocks;
+       info->max_blocks = max_blocks;
+       info->flags &= ~RHIF_STATIC_BLOCK;
+
+       /* add all new blocks to the free list */
+       for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++)
+               list_add(&blk->list, &info->empty_list);
+
+       return 0;
+}
+
+/*
+ * Assure at least the required amount of empty slots.  If this function
+ * causes a grow in the block area then all pointers kept to the block
+ * area are invalid!
+ */
+static int assure_empty(rh_info_t * info, int slots)
+{
+       int max_blocks;
+
+       /* This function is not meant to be used to grow uncontrollably */
+       if (slots >= 4)
+               return -EINVAL;
+
+       /* Enough space */
+       if (info->empty_slots >= slots)
+               return 0;
+
+       /* Next 16 sized block */
+       max_blocks = ((info->max_blocks + slots) + 15) & ~15;
+
+       return grow(info, max_blocks);
+}
+
+static rh_block_t *get_slot(rh_info_t * info)
+{
+       rh_block_t *blk;
+
+       /* If no more free slots, and failure to extend. */
+       /* XXX: You should have called assure_empty before */
+       if (info->empty_slots == 0) {
+               printk(KERN_ERR "rh: out of slots; crash is imminent.\n");
+               return NULL;
+       }
+
+       /* Get empty slot to use */
+       blk = list_entry(info->empty_list.next, rh_block_t, list);
+       list_del_init(&blk->list);
+       info->empty_slots--;
+
+       /* Initialize */
+       blk->start = NULL;
+       blk->size = 0;
+       blk->owner = NULL;
+
+       return blk;
+}
+
+static inline void release_slot(rh_info_t * info, rh_block_t * blk)
+{
+       list_add(&blk->list, &info->empty_list);
+       info->empty_slots++;
+}
+
+static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
+{
+       rh_block_t *blk;
+       rh_block_t *before;
+       rh_block_t *after;
+       rh_block_t *next;
+       int size;
+       unsigned long s, e, bs, be;
+       struct list_head *l;
+
+       /* We assume that they are aligned properly */
+       size = blkn->size;
+       s = (unsigned long)blkn->start;
+       e = s + size;
+
+       /* Find the blocks immediately before and after the given one
+        * (if any) */
+       before = NULL;
+       after = NULL;
+       next = NULL;
+
+       list_for_each(l, &info->free_list) {
+               blk = list_entry(l, rh_block_t, list);
+
+               bs = (unsigned long)blk->start;
+               be = bs + blk->size;
+
+               if (next == NULL && s >= bs)
+                       next = blk;
+
+               if (be == s)
+                       before = blk;
+
+               if (e == bs)
+                       after = blk;
+
+               /* If both are not null, break now */
+               if (before != NULL && after != NULL)
+                       break;
+       }
+
+       /* Now check if they are really adjacent */
+       if (before != NULL && s != (unsigned long)before->start + before->size)
+               before = NULL;
+
+       if (after != NULL && e != (unsigned long)after->start)
+               after = NULL;
+
+       /* No coalescing; list insert and return */
+       if (before == NULL && after == NULL) {
+
+               if (next != NULL)
+                       list_add(&blkn->list, &next->list);
+               else
+                       list_add(&blkn->list, &info->free_list);
+
+               return;
+       }
+
+       /* We don't need it anymore */
+       release_slot(info, blkn);
+
+       /* Grow the before block */
+       if (before != NULL && after == NULL) {
+               before->size += size;
+               return;
+       }
+
+       /* Grow the after block backwards */
+       if (before == NULL && after != NULL) {
+               (int8_t *) after->start -= size;
+               after->size += size;
+               return;
+       }
+
+       /* Grow the before block, and release the after block */
+       before->size += size + after->size;
+       list_del(&after->list);
+       release_slot(info, after);
+}
+
+static void attach_taken_block(rh_info_t * info, rh_block_t * blkn)
+{
+       rh_block_t *blk;
+       struct list_head *l;
+
+       /* Find the block immediately before the given one (if any) */
+       list_for_each(l, &info->taken_list) {
+               blk = list_entry(l, rh_block_t, list);
+               if (blk->start > blkn->start) {
+                       list_add_tail(&blkn->list, &blk->list);
+                       return;
+               }
+       }
+
+       list_add_tail(&blkn->list, &info->taken_list);
+}
+
+/*
+ * Create a remote heap dynamically.  Note that no memory for the blocks
+ * are allocated.  It will upon the first allocation
+ */
+rh_info_t *rh_create(unsigned int alignment)
+{
+       rh_info_t *info;
+
+       /* Alignment must be a power of two */
+       if ((alignment & (alignment - 1)) != 0)
+               return ERR_PTR(-EINVAL);
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       info->alignment = alignment;
+
+       /* Initially everything as empty */
+       info->block = NULL;
+       info->max_blocks = 0;
+       info->empty_slots = 0;
+       info->flags = 0;
+
+       INIT_LIST_HEAD(&info->empty_list);
+       INIT_LIST_HEAD(&info->free_list);
+       INIT_LIST_HEAD(&info->taken_list);
+
+       return info;
+}
+
+/*
+ * Destroy a dynamically created remote heap.  Deallocate only if the areas
+ * are not static
+ */
+void rh_destroy(rh_info_t * info)
+{
+       if ((info->flags & RHIF_STATIC_BLOCK) == 0 && info->block != NULL)
+               kfree(info->block);
+
+       if ((info->flags & RHIF_STATIC_INFO) == 0)
+               kfree(info);
+}
+
+/*
+ * Initialize in place a remote heap info block.  This is needed to support
+ * operation very early in the startup of the kernel, when it is not yet safe
+ * to call kmalloc.
+ */
+void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
+            rh_block_t * block)
+{
+       int i;
+       rh_block_t *blk;
+
+       /* Alignment must be a power of two */
+       if ((alignment & (alignment - 1)) != 0)
+               return;
+
+       info->alignment = alignment;
+
+       /* Initially everything as empty */
+       info->block = block;
+       info->max_blocks = max_blocks;
+       info->empty_slots = max_blocks;
+       info->flags = RHIF_STATIC_INFO | RHIF_STATIC_BLOCK;
+
+       INIT_LIST_HEAD(&info->empty_list);
+       INIT_LIST_HEAD(&info->free_list);
+       INIT_LIST_HEAD(&info->taken_list);
+
+       /* Add all new blocks to the free list */
+       for (i = 0, blk = block; i < max_blocks; i++, blk++)
+               list_add(&blk->list, &info->empty_list);
+}
+
+/* Attach a free memory region, coalesces regions if adjuscent */
+int rh_attach_region(rh_info_t * info, void *start, int size)
+{
+       rh_block_t *blk;
+       unsigned long s, e, m;
+       int r;
+
+       /* The region must be aligned */
+       s = (unsigned long)start;
+       e = s + size;
+       m = info->alignment - 1;
+
+       /* Round start up */
+       s = (s + m) & ~m;
+
+       /* Round end down */
+       e = e & ~m;
+
+       /* Take final values */
+       start = (void *)s;
+       size = (int)(e - s);
+
+       /* Grow the blocks, if needed */
+       r = assure_empty(info, 1);
+       if (r < 0)
+               return r;
+
+       blk = get_slot(info);
+       blk->start = start;
+       blk->size = size;
+       blk->owner = NULL;
+
+       attach_free_block(info, blk);
+
+       return 0;
+}
+
+/* Detatch given address range, splits free block if needed. */
+void *rh_detach_region(rh_info_t * info, void *start, int size)
+{
+       struct list_head *l;
+       rh_block_t *blk, *newblk;
+       unsigned long s, e, m, bs, be;
+
+       /* Validate size */
+       if (size <= 0)
+               return ERR_PTR(-EINVAL);
+
+       /* The region must be aligned */
+       s = (unsigned long)start;
+       e = s + size;
+       m = info->alignment - 1;
+
+       /* Round start up */
+       s = (s + m) & ~m;
+
+       /* Round end down */
+       e = e & ~m;
+
+       if (assure_empty(info, 1) < 0)
+               return ERR_PTR(-ENOMEM);
+
+       blk = NULL;
+       list_for_each(l, &info->free_list) {
+               blk = list_entry(l, rh_block_t, list);
+               /* The range must lie entirely inside one free block */
+               bs = (unsigned long)blk->start;
+               be = (unsigned long)blk->start + blk->size;
+               if (s >= bs && e <= be)
+                       break;
+               blk = NULL;
+       }
+
+       if (blk == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       /* Perfect fit */
+       if (bs == s && be == e) {
+               /* Delete from free list, release slot */
+               list_del(&blk->list);
+               release_slot(info, blk);
+               return (void *)s;
+       }
+
+       /* blk still in free list, with updated start and/or size */
+       if (bs == s || be == e) {
+               if (bs == s)
+                       (int8_t *) blk->start += size;
+               blk->size -= size;
+
+       } else {
+               /* The front free fragment */
+               blk->size = s - bs;
+
+               /* the back free fragment */
+               newblk = get_slot(info);
+               newblk->start = (void *)e;
+               newblk->size = be - e;
+
+               list_add(&newblk->list, &blk->list);
+       }
+
+       return (void *)s;
+}
+
+void *rh_alloc(rh_info_t * info, int size, const char *owner)
+{
+       struct list_head *l;
+       rh_block_t *blk;
+       rh_block_t *newblk;
+       void *start;
+
+       /* Validate size */
+       if (size <= 0)
+               return ERR_PTR(-EINVAL);
+
+       /* Align to configured alignment */
+       size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
+
+       if (assure_empty(info, 1) < 0)
+               return ERR_PTR(-ENOMEM);
+
+       blk = NULL;
+       list_for_each(l, &info->free_list) {
+               blk = list_entry(l, rh_block_t, list);
+               if (size <= blk->size)
+                       break;
+               blk = NULL;
+       }
+
+       if (blk == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       /* Just fits */
+       if (blk->size == size) {
+               /* Move from free list to taken list */
+               list_del(&blk->list);
+               blk->owner = owner;
+               start = blk->start;
+
+               attach_taken_block(info, blk);
+
+               return start;
+       }
+
+       newblk = get_slot(info);
+       newblk->start = blk->start;
+       newblk->size = size;
+       newblk->owner = owner;
+
+       /* blk still in free list, with updated start, size */
+       (int8_t *) blk->start += size;
+       blk->size -= size;
+
+       start = newblk->start;
+
+       attach_taken_block(info, newblk);
+
+       return start;
+}
+
+/* allocate at precisely the given address */
+void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
+{
+       struct list_head *l;
+       rh_block_t *blk, *newblk1, *newblk2;
+       unsigned long s, e, m, bs, be;
+
+       /* Validate size */
+       if (size <= 0)
+               return ERR_PTR(-EINVAL);
+
+       /* The region must be aligned */
+       s = (unsigned long)start;
+       e = s + size;
+       m = info->alignment - 1;
+
+       /* Round start up */
+       s = (s + m) & ~m;
+
+       /* Round end down */
+       e = e & ~m;
+
+       if (assure_empty(info, 2) < 0)
+               return ERR_PTR(-ENOMEM);
+
+       blk = NULL;
+       list_for_each(l, &info->free_list) {
+               blk = list_entry(l, rh_block_t, list);
+               /* The range must lie entirely inside one free block */
+               bs = (unsigned long)blk->start;
+               be = (unsigned long)blk->start + blk->size;
+               if (s >= bs && e <= be)
+                       break;
+       }
+
+       if (blk == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       /* Perfect fit */
+       if (bs == s && be == e) {
+               /* Move from free list to taken list */
+               list_del(&blk->list);
+               blk->owner = owner;
+
+               start = blk->start;
+               attach_taken_block(info, blk);
+
+               return start;
+
+       }
+
+       /* blk still in free list, with updated start and/or size */
+       if (bs == s || be == e) {
+               if (bs == s)
+                       (int8_t *) blk->start += size;
+               blk->size -= size;
+
+       } else {
+               /* The front free fragment */
+               blk->size = s - bs;
+
+               /* The back free fragment */
+               newblk2 = get_slot(info);
+               newblk2->start = (void *)e;
+               newblk2->size = be - e;
+
+               list_add(&newblk2->list, &blk->list);
+       }
+
+       newblk1 = get_slot(info);
+       newblk1->start = (void *)s;
+       newblk1->size = e - s;
+       newblk1->owner = owner;
+
+       start = newblk1->start;
+       attach_taken_block(info, newblk1);
+
+       return start;
+}
+
+int rh_free(rh_info_t * info, void *start)
+{
+       rh_block_t *blk, *blk2;
+       struct list_head *l;
+       int size;
+
+       /* Linear search for block */
+       blk = NULL;
+       list_for_each(l, &info->taken_list) {
+               blk2 = list_entry(l, rh_block_t, list);
+               if (start < blk2->start)
+                       break;
+               blk = blk2;
+       }
+
+       if (blk == NULL || start > (blk->start + blk->size))
+               return -EINVAL;
+
+       /* Remove from taken list */
+       list_del(&blk->list);
+
+       /* Get size of freed block */
+       size = blk->size;
+       attach_free_block(info, blk);
+
+       return size;
+}
+
+int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
+{
+       rh_block_t *blk;
+       struct list_head *l;
+       struct list_head *h;
+       int nr;
+
+       switch (what) {
+
+       case RHGS_FREE:
+               h = &info->free_list;
+               break;
+
+       case RHGS_TAKEN:
+               h = &info->taken_list;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Linear search for block */
+       nr = 0;
+       list_for_each(l, h) {
+               blk = list_entry(l, rh_block_t, list);
+               if (stats != NULL && nr < max_stats) {
+                       stats->start = blk->start;
+                       stats->size = blk->size;
+                       stats->owner = blk->owner;
+                       stats++;
+               }
+               nr++;
+       }
+
+       return nr;
+}
+
+int rh_set_owner(rh_info_t * info, void *start, const char *owner)
+{
+       rh_block_t *blk, *blk2;
+       struct list_head *l;
+       int size;
+
+       /* Linear search for block */
+       blk = NULL;
+       list_for_each(l, &info->taken_list) {
+               blk2 = list_entry(l, rh_block_t, list);
+               if (start < blk2->start)
+                       break;
+               blk = blk2;
+       }
+
+       if (blk == NULL || start > (blk->start + blk->size))
+               return -EINVAL;
+
+       blk->owner = owner;
+
+       return size;
+}
+
+void rh_dump(rh_info_t * info)
+{
+       static rh_stats_t st[32];       /* XXX maximum 32 blocks */
+       int maxnr;
+       int i, nr;
+
+       maxnr = sizeof(st) / sizeof(st[0]);
+
+       printk(KERN_INFO
+              "info @0x%p (%d slots empty / %d max)\n",
+              info, info->empty_slots, info->max_blocks);
+
+       printk(KERN_INFO "  Free:\n");
+       nr = rh_get_stats(info, RHGS_FREE, maxnr, st);
+       if (nr > maxnr)
+               nr = maxnr;
+       for (i = 0; i < nr; i++)
+               printk(KERN_INFO
+                      "    0x%p-0x%p (%u)\n",
+                      st[i].start, (int8_t *) st[i].start + st[i].size,
+                      st[i].size);
+       printk(KERN_INFO "\n");
+
+       printk(KERN_INFO "  Taken:\n");
+       nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st);
+       if (nr > maxnr)
+               nr = maxnr;
+       for (i = 0; i < nr; i++)
+               printk(KERN_INFO
+                      "    0x%p-0x%p (%u) %s\n",
+                      st[i].start, (int8_t *) st[i].start + st[i].size,
+                      st[i].size, st[i].owner != NULL ? st[i].owner : "");
+       printk(KERN_INFO "\n");
+}
+
+void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
+{
+       printk(KERN_INFO
+              "blk @0x%p: 0x%p-0x%p (%u)\n",
+              blk, blk->start, (int8_t *) blk->start + blk->size, blk->size);
+}
diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
new file mode 100644 (file)
index 0000000..e4666df
--- /dev/null
@@ -0,0 +1,75 @@
+config 85xx
+       bool
+       depends on E500
+       default y
+
+config PPC_INDIRECT_PCI_BE
+       bool
+       depends on 85xx
+       default y
+
+menu "Freescale 85xx options"
+       depends on E500
+
+choice
+       prompt "Machine Type"
+       depends on 85xx
+       default MPC8540_ADS
+
+config MPC8540_ADS
+       bool "Freescale MPC8540 ADS"
+       help
+         This option enables support for the MPC 8540 ADS evaluation board.
+
+config MPC8555_CDS
+       bool "Freescale MPC8555 CDS"
+       help
+         This option enablese support for the MPC8555 CDS evaluation board.
+
+config MPC8560_ADS
+       bool "Freescale MPC8560 ADS"
+       help
+         This option enables support for the MPC 8560 ADS evaluation board.
+
+config SBC8560
+       bool "WindRiver PowerQUICC III SBC8560"
+       help
+         This option enables support for the WindRiver PowerQUICC III 
+         SBC8560 board.
+
+endchoice
+
+# It's often necessary to know the specific 85xx processor type.
+# Fortunately, it is implied (so far) from the board type, so we
+# don't need to ask more redundant questions.
+config MPC8540
+       bool
+       depends on MPC8540_ADS
+       default y
+
+config MPC8555
+       bool
+       depends on MPC8555_CDS
+       default y
+
+config MPC8560
+       bool
+       depends on SBC8560 || MPC8560_ADS
+       default y
+
+config 85xx_PCI2
+       bool "Supprt for 2nd PCI host controller"
+       depends on MPC8555_CDS
+       default y
+
+config FSL_OCP
+       bool
+       depends on 85xx
+       default y
+
+config PPC_GEN550
+       bool
+       depends on MPC8540 || SBC8560 || MPC8555
+       default y
+
+endmenu
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
new file mode 100644 (file)
index 0000000..673b970
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the PowerPC 85xx linux kernel.
+#
+
+obj-$(CONFIG_MPC8540_ADS)      += mpc85xx_ads_common.o mpc8540_ads.o
+obj-$(CONFIG_MPC8555_CDS)      += mpc85xx_cds_common.o
+obj-$(CONFIG_MPC8560_ADS)      += mpc85xx_ads_common.o mpc8560_ads.o
+obj-$(CONFIG_SBC8560)          += sbc85xx.o sbc8560.o
+
+obj-$(CONFIG_MPC8540)          += mpc8540.o
+obj-$(CONFIG_MPC8555)          += mpc8555.o
+obj-$(CONFIG_MPC8560)          += mpc8560.o
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
new file mode 100644 (file)
index 0000000..aada7e4
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.c
+ *
+ * MPC8540ADS board specific routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+struct ocp_gfar_data mpc85xx_tsec1_def = {
+       .interruptTransmit = MPC85xx_IRQ_TSEC1_TX,
+       .interruptError = MPC85xx_IRQ_TSEC1_ERROR,
+       .interruptReceive = MPC85xx_IRQ_TSEC1_RX,
+       .interruptPHY = MPC85xx_IRQ_EXT5,
+       .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+                       | GFAR_HAS_RMON
+                       | GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE),
+       .phyid = 0,
+       .phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_tsec2_def = {
+       .interruptTransmit = MPC85xx_IRQ_TSEC2_TX,
+       .interruptError = MPC85xx_IRQ_TSEC2_ERROR,
+       .interruptReceive = MPC85xx_IRQ_TSEC2_RX,
+       .interruptPHY = MPC85xx_IRQ_EXT5,
+       .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+                       | GFAR_HAS_RMON
+                       | GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE),
+       .phyid = 1,
+       .phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_fec_def = {
+       .interruptTransmit = MPC85xx_IRQ_FEC,
+       .interruptError = MPC85xx_IRQ_FEC,
+       .interruptReceive = MPC85xx_IRQ_FEC,
+       .interruptPHY = MPC85xx_IRQ_EXT5,
+       .flags = 0,
+       .phyid = 3,
+       .phyregidx = 0,
+};
+
+struct ocp_fs_i2c_data mpc85xx_i2c1_def = {
+       .flags = FS_I2C_SEPARATE_DFSRR,
+};
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc8540ads_setup_arch(void)
+{
+       struct ocp_def *def;
+       struct ocp_gfar_data *einfo;
+       bd_t *binfo = (bd_t *) __res;
+       unsigned int freq;
+
+       /* get the core frequency */
+       freq = binfo->bi_intfreq;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc8540ads_setup_arch()", 0);
+
+       /* Set loops_per_jiffy to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+       /* setup PCI host bridges */
+       mpc85xx_setup_hose();
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+       mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       /* Invalidate the entry we stole earlier the serial ports
+        * should be properly mapped */
+       invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6);
+       }
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6);
+       }
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 2);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enet2addr, 6);
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_HDA1;
+#endif
+
+       ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base));
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       /* parse_bootinfo must always be called first */
+       parse_bootinfo(find_bootinfo());
+
+       /*
+        * If we were passed in a board information, copy it into the
+        * residual data area.
+        */
+       if (r3) {
+               memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+                      sizeof (bd_t));
+       }
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       {
+               bd_t *binfo = (bd_t *) __res;
+
+               /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+               settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+                         binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+       }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+       /*
+        * If the init RAM disk has been configured in, and there's a valid
+        * starting address for it, set it up.
+        */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif                         /* CONFIG_BLK_DEV_INITRD */
+
+       /* Copy the kernel command line arguments to a safe place. */
+
+       if (r6) {
+               *(char *) (r7 + KERNELBASE) = 0;
+               strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+       }
+
+       /* setup the PowerPC module struct */
+       ppc_md.setup_arch = mpc8540ads_setup_arch;
+       ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+       ppc_md.init_IRQ = mpc85xx_ads_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+
+       ppc_md.restart = mpc85xx_restart;
+       ppc_md.power_off = mpc85xx_power_off;
+       ppc_md.halt = mpc85xx_halt;
+
+       ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+       ppc_md.time_init = NULL;
+       ppc_md.set_rtc_time = NULL;
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+       ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc8540ads_init(): exit", 0);
+
+       return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h
new file mode 100644 (file)
index 0000000..0d602fc
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ *
+ */
+
+#ifndef __MACH_MPC8540ADS_H__
+#define __MACH_MPC8540ADS_H__
+
+#include <linux/config.h>
+#include <linux/initrd.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#define SERIAL_PORT_DFNS       \
+       STD_UART_OP(0)          \
+       STD_UART_OP(1)
+
+#endif /* __MACH_MPC8540ADS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc8555.c b/arch/ppc/platforms/85xx/mpc8555.c
new file mode 100644 (file)
index 0000000..9427584
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * arch/ppc/platform/85xx/mpc8555.c
+ *
+ * MPC8555 I/O descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/mpc85xx.h>
+#include <asm/ocp.h>
+
+/* These should be defined in platform code */
+extern struct ocp_gfar_data mpc85xx_tsec1_def;
+extern struct ocp_gfar_data mpc85xx_tsec2_def;
+extern struct ocp_mpc_i2c_data mpc85xx_i2c1_def;
+
+/* We use offsets for paddr since we do not know at compile time
+ * what CCSRBAR is, platform code should fix this up in
+ * setup_arch
+ *
+ * Only the first IRQ is given even if a device has
+ * multiple lines associated with ita
+ */
+struct ocp_def core_ocp[] = {
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_IIC,
+          .index        = 0,
+          .paddr        = MPC85xx_IIC1_OFFSET,
+          .irq          = MPC85xx_IRQ_IIC1,
+          .pm           = OCP_CPM_NA,
+         .additions    = &mpc85xx_i2c1_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_16550,
+          .index        = 0,
+          .paddr        = MPC85xx_UART0_OFFSET,
+          .irq          = MPC85xx_IRQ_DUART,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_16550,
+          .index        = 1,
+          .paddr        = MPC85xx_UART1_OFFSET,
+          .irq          = MPC85xx_IRQ_DUART,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_GFAR,
+          .index        = 0,
+          .paddr        = MPC85xx_ENET1_OFFSET,
+          .irq          = MPC85xx_IRQ_TSEC1_TX,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_tsec1_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_GFAR,
+          .index        = 1,
+          .paddr        = MPC85xx_ENET2_OFFSET,
+          .irq          = MPC85xx_IRQ_TSEC2_TX,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_tsec2_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_DMA,
+          .index        = 0,
+          .paddr        = MPC85xx_DMA_OFFSET,
+          .irq          = MPC85xx_IRQ_DMA0,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_PERFMON,
+          .index        = 0,
+          .paddr        = MPC85xx_PERFMON_OFFSET,
+          .irq          = MPC85xx_IRQ_PERFMON,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_INVALID
+        }
+};
diff --git a/arch/ppc/platforms/85xx/mpc8555_cds.h b/arch/ppc/platforms/85xx/mpc8555_cds.h
new file mode 100644 (file)
index 0000000..566e0e1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/platforms/mpc8555_cds.h
+ *
+ * MPC8555CDS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ *
+ */
+
+#ifndef __MACH_MPC8555CDS_H__
+#define __MACH_MPC8555CDS_H__
+
+#include <linux/config.h>
+#include <linux/serial.h>
+#include <platforms/85xx/mpc85xx_cds_common.h>
+
+#define CPM_MAP_ADDR   (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif /* __MACH_MPC8555CDS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
new file mode 100644 (file)
index 0000000..0cb2c34
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8560_ads.c
+ *
+ * MPC8560ADS board specific routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <asm/cpm2.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+extern void cpm2_reset(void);
+
+struct ocp_gfar_data mpc85xx_tsec1_def = {
+        .interruptTransmit = MPC85xx_IRQ_TSEC1_TX,
+        .interruptError = MPC85xx_IRQ_TSEC1_ERROR,
+        .interruptReceive = MPC85xx_IRQ_TSEC1_RX,
+        .interruptPHY = MPC85xx_IRQ_EXT5,
+        .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+                       | GFAR_HAS_RMON | GFAR_HAS_COALESCE
+                        | GFAR_HAS_PHY_INTR),
+        .phyid = 0,
+        .phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_tsec2_def = {
+        .interruptTransmit = MPC85xx_IRQ_TSEC2_TX,
+        .interruptError = MPC85xx_IRQ_TSEC2_ERROR,
+        .interruptReceive = MPC85xx_IRQ_TSEC2_RX,
+        .interruptPHY = MPC85xx_IRQ_EXT5,
+        .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+                       | GFAR_HAS_RMON | GFAR_HAS_COALESCE
+                        | GFAR_HAS_PHY_INTR),
+        .phyid = 1,
+        .phyregidx = 0,
+};
+
+struct ocp_fs_i2c_data mpc85xx_i2c1_def = {
+       .flags = FS_I2C_SEPARATE_DFSRR,
+};
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+
+static void __init
+mpc8560ads_setup_arch(void)
+{
+       struct ocp_def *def;
+       struct ocp_gfar_data *einfo;
+       bd_t *binfo = (bd_t *) __res;
+       unsigned int freq;
+
+       cpm2_reset();
+
+       /* get the core frequency */
+       freq = binfo->bi_intfreq;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc8560ads_setup_arch()", 0);
+
+       /* Set loops_per_jiffy to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+       /* setup PCI host bridges */
+       mpc85xx_setup_hose();
+#endif
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6);
+       }
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6);
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_HDA1;
+#endif
+
+       ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base));
+}
+
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+       while ((irq = cpm2_get_irq(regs)) >= 0) {
+               ppc_irq_dispatch_handler(regs, irq);
+       }
+       return IRQ_HANDLED;
+}
+
+static void __init
+mpc8560_ads_init_IRQ(void)
+{
+       int i;
+       volatile cpm2_map_t *immap = cpm2_immr;
+
+       /* Setup OpenPIC */
+       mpc85xx_ads_init_IRQ();
+
+       /* disable all CPM interupts */
+       immap->im_intctl.ic_simrh = 0x0;
+       immap->im_intctl.ic_simrl = 0x0;
+
+       for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
+               irq_desc[i].handler = &cpm2_pic;
+
+       /* Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       immap->im_intctl.ic_sicr = 0;
+       immap->im_intctl.ic_scprrh = 0x05309770;
+       immap->im_intctl.ic_scprrl = 0x05309770;
+
+       request_irq(MPC85xx_IRQ_CPM, cpm2_cascade, SA_INTERRUPT, "cpm2_cascade", NULL);
+
+       return;
+}
+
+
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       /* parse_bootinfo must always be called first */
+       parse_bootinfo(find_bootinfo());
+
+       /*
+        * If we were passed in a board information, copy it into the
+        * residual data area.
+        */
+       if (r3) {
+               memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+                      sizeof (bd_t));
+
+       }
+#if defined(CONFIG_BLK_DEV_INITRD)
+       /*
+        * If the init RAM disk has been configured in, and there's a valid
+        * starting address for it, set it up.
+        */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif                         /* CONFIG_BLK_DEV_INITRD */
+
+       /* Copy the kernel command line arguments to a safe place. */
+
+       if (r6) {
+               *(char *) (r7 + KERNELBASE) = 0;
+               strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+       }
+
+       /* setup the PowerPC module struct */
+       ppc_md.setup_arch = mpc8560ads_setup_arch;
+       ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+       ppc_md.init_IRQ = mpc8560_ads_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+
+       ppc_md.restart = mpc85xx_restart;
+       ppc_md.power_off = mpc85xx_power_off;
+       ppc_md.halt = mpc85xx_halt;
+
+       ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+       ppc_md.time_init = NULL;
+       ppc_md.set_rtc_time = NULL;
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc8560ads_init(): exit", 0);
+
+       return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.h b/arch/ppc/platforms/85xx/mpc8560_ads.h
new file mode 100644 (file)
index 0000000..7df885d
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * arch/ppc/platforms/mpc8560_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ *
+ */
+
+#ifndef __MACH_MPC8560ADS_H
+#define __MACH_MPC8560ADS_H
+
+#include <linux/config.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#define CPM_MAP_ADDR   (CCSRBAR + MPC85xx_CPM_OFFSET)
+#define PHY_INTERRUPT  MPC85xx_IRQ_EXT7
+
+#endif                         /* __MACH_MPC8560ADS_H */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
new file mode 100644 (file)
index 0000000..c7e53e3
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * arch/ppc/platform/85xx/mpc85xx_cds_common.c
+ *
+ * MPC85xx CDS board specific routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor, 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/immap_cpm2.h>
+#include <asm/ocp.h>
+#include <asm/kgdb.h>
+
+#include <mm/mmu_decl.h>
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory;      /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+static int cds_pci_slot = 2;
+static volatile u8 * cadmus;
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+
+static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  0: L2 Cache */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  1: ECM */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  2: DDR DRAM */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  3: LBIU */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  4: DMA 0 */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  5: DMA 1 */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  6: DMA 2 */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  7: DMA 3 */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  8: PCI/PCI-X */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal  9: RIO Inbound Port Write Error */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 10: RIO Doorbell Inbound */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 11: RIO Outbound Message */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 12: RIO Inbound Message */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 13: TSEC 0 Transmit */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 14: TSEC 0 Receive */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 15: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 16: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 17: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 18: TSEC 0 Receive/Transmit Error */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 19: TSEC 1 Transmit */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 20: TSEC 1 Receive */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 21: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 22: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 23: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 24: TSEC 1 Receive/Transmit Error */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 25: Fast Ethernet */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 26: DUART */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 27: I2C */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 28: Performance Monitor */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 29: Unused */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 30: CPM */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),        /* Internal 31: Unused */
+#if defined(CONFIG_PCI)
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 0: PCI1 slot */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 1: PCI1 slot */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 2: PCI1 slot */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 3: PCI1 slot */
+#else
+        0x0,                            /* External  0: */
+        0x0,                            /* External  1: */
+        0x0,                            /* External  2: */
+        0x0,                            /* External  3: */
+#endif
+        0x0,                            /* External  4: */
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 5: PHY */
+        0x0,                            /* External  6: */
+        0x0,                            /* External  7: */
+        0x0,                            /* External  8: */
+        0x0,                            /* External  9: */
+        0x0,                            /* External 10: */
+#if defined(CONFIG_85xx_PCI2) && defined(CONFIG_PCI)
+        (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* External 11: PCI2 slot 0 */
+#else
+        0x0,                            /* External 11: */
+#endif
+};
+
+struct ocp_gfar_data mpc85xx_tsec1_def = {
+        .interruptTransmit = MPC85xx_IRQ_TSEC1_TX,
+        .interruptError = MPC85xx_IRQ_TSEC1_ERROR,
+        .interruptReceive = MPC85xx_IRQ_TSEC1_RX,
+        .interruptPHY = MPC85xx_IRQ_EXT5,
+        .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR |
+                        GFAR_HAS_PHY_INTR),
+        .phyid = 0,
+        .phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_tsec2_def = {
+        .interruptTransmit = MPC85xx_IRQ_TSEC2_TX,
+        .interruptError = MPC85xx_IRQ_TSEC2_ERROR,
+        .interruptReceive = MPC85xx_IRQ_TSEC2_RX,
+        .interruptPHY = MPC85xx_IRQ_EXT5,
+        .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR |
+                        GFAR_HAS_PHY_INTR),
+        .phyid = 1,
+        .phyregidx = 0,
+};
+
+struct ocp_fs_i2c_data mpc85xx_i2c1_def = {
+       .flags = FS_I2C_SEPARATE_DFSRR,
+};
+
+/* ************************************************************************ */
+int
+mpc85xx_cds_show_cpuinfo(struct seq_file *m)
+{
+        uint pvid, svid, phid1;
+        uint memsize = total_memory;
+        bd_t *binfo = (bd_t *) __res;
+        unsigned int freq;
+
+        /* get the core frequency */
+        freq = binfo->bi_intfreq;
+
+        pvid = mfspr(PVR);
+        svid = mfspr(SVR);
+
+        seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+       seq_printf(m, "Machine\t\t: CDS (%x)\n", cadmus[CM_VER]);
+        seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
+                   freq % 1000000);
+        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+        /* Display cpu Pll setting */
+        phid1 = mfspr(HID1);
+        seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+        /* Display the amount of memory */
+        seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+
+        return 0;
+}
+
+#ifdef CONFIG_CPM2
+static void cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+       while((irq = cpm2_get_irq(regs)) >= 0)
+       {
+               ppc_irq_dispatch_handler(regs,irq);
+       }
+}
+#endif /* CONFIG_CPM2 */
+
+void __init
+mpc85xx_cds_init_IRQ(void)
+{
+       bd_t *binfo = (bd_t *) __res;
+#ifdef CONFIG_CPM2
+       volatile cpm2_map_t *immap = cpm2_immr;
+       int i;
+#endif
+
+        /* Determine the Physical Address of the OpenPIC regs */
+        phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+        OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+        OpenPIC_InitSenses = mpc85xx_cds_openpic_initsenses;
+        OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses);
+
+        /* Skip reserved space and internal sources */
+        openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+        /* Map PIC IRQs 0-11 */
+        openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+        /* we let openpic interrupts starting from an offset, to
+         * leave space for cascading interrupts underneath.
+         */
+        openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+#ifdef CONFIG_CPM2
+       /* disable all CPM interupts */
+       immap->im_intctl.ic_simrh = 0x0;
+       immap->im_intctl.ic_simrl = 0x0;
+
+       for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
+               irq_desc[i].handler = &cpm2_pic;
+
+       /* Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       immap->im_intctl.ic_sicr = 0;
+       immap->im_intctl.ic_scprrh = 0x05309770;
+       immap->im_intctl.ic_scprrl = 0x05309770;
+
+       request_irq(MPC85xx_IRQ_CPM, cpm2_cascade, SA_INTERRUPT, "cpm2_cascade", NULL);
+#endif
+
+        return;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int
+mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+       if (!hose->index)
+       {
+               /* Handle PCI1 interrupts */
+               char pci_irq_table[][4] =
+                       /*
+                        *      PCI IDSEL/INTPIN->INTLINE
+                        *        A      B      C      D
+                        */
+
+                       /* Note IRQ assignment for slots is based on which slot the elysium is
+                        * in -- in this setup elysium is in slot #2 (this PIRQA as first
+                        * interrupt on slot */
+               {
+                       { 0, 1, 2, 3 }, /* 16 - PMC */
+                       { 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */
+                       { 0, 1, 2, 3 }, /* 18 - Slot 1 */
+                       { 1, 2, 3, 0 }, /* 19 - Slot 2 */
+                       { 2, 3, 0, 1 }, /* 20 - Slot 3 */
+                       { 3, 0, 1, 2 }, /* 21 - Slot 4 */
+               };
+
+               const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4;
+               int i, j;
+
+               for (i = 0; i < 6; i++)
+                       for (j = 0; j < 4; j++)
+                               pci_irq_table[i][j] =
+                                       ((pci_irq_table[i][j] + 5 -
+                                         cds_pci_slot) & 0x3) + PIRQ0A;
+
+               return PCI_IRQ_TABLE_LOOKUP;
+       } else {
+               /* Handle PCI2 interrupts (if we have one) */
+               char pci_irq_table[][4] =
+               {
+                       /*
+                        * We only have one slot and one interrupt
+                        * going to PIRQA - PIRQD */
+                       { PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */
+               };
+
+               const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4;
+
+               return PCI_IRQ_TABLE_LOOKUP;
+       }
+}
+
+#define ARCADIA_HOST_BRIDGE_IDSEL     17
+#define ARCADIA_2ND_BRIDGE_IDSEL     3
+
+int
+mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+       if (bus == 0 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#if CONFIG_85xx_PCI2
+       /* With the current code we know PCI2 will be bus 2, however this may
+        * not be guarnteed */
+       if (bus == 2 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+       /* We explicitly do not go past the Tundra 320 Bridge */
+       if (bus == 1)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       else
+               return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc85xx_cds_setup_arch(void)
+{
+        struct ocp_def *def;
+        struct ocp_gfar_data *einfo;
+        bd_t *binfo = (bd_t *) __res;
+        unsigned int freq;
+
+        /* get the core frequency */
+        freq = binfo->bi_intfreq;
+
+        printk("mpc85xx_cds_setup_arch\n");
+
+#ifdef CONFIG_CPM2
+       cpm2_reset();
+#endif
+
+       cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
+       cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
+       printk("CDS Version = %x in PCI slot %d\n", cadmus[CM_VER], cds_pci_slot);
+
+        /* Set loops_per_jiffy to a half-way reasonable value,
+           for use until calibrate_delay gets called. */
+        loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+        /* setup PCI host bridges */
+        mpc85xx_setup_hose();
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+        conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+        mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       /* Invalidate the entry we stole earlier the serial ports
+        * should be properly mapped */
+       invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+        def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0);
+        if (def) {
+                einfo = (struct ocp_gfar_data *) def->additions;
+                memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6);
+        }
+
+        def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1);
+        if (def) {
+                einfo = (struct ocp_gfar_data *) def->additions;
+                memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6);
+        }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+        if (initrd_start)
+                ROOT_DEV = Root_RAM0;
+        else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+                ROOT_DEV = Root_NFS;
+#else
+                ROOT_DEV = Root_HDA1;
+#endif
+
+       ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base));
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+              unsigned long r6, unsigned long r7)
+{
+        /* parse_bootinfo must always be called first */
+        parse_bootinfo(find_bootinfo());
+
+        /*
+         * If we were passed in a board information, copy it into the
+         * residual data area.
+         */
+        if (r3) {
+                memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+                       sizeof (bd_t));
+
+        }
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       {
+               bd_t *binfo = (bd_t *) __res;
+
+               /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+               settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+                       binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+       }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+        /*
+         * If the init RAM disk has been configured in, and there's a valid
+         * starting address for it, set it up.
+         */
+        if (r4) {
+                initrd_start = r4 + KERNELBASE;
+                initrd_end = r5 + KERNELBASE;
+        }
+#endif                          /* CONFIG_BLK_DEV_INITRD */
+
+        /* Copy the kernel command line arguments to a safe place. */
+
+        if (r6) {
+                *(char *) (r7 + KERNELBASE) = 0;
+                strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+        }
+
+        /* setup the PowerPC module struct */
+        ppc_md.setup_arch = mpc85xx_cds_setup_arch;
+        ppc_md.show_cpuinfo = mpc85xx_cds_show_cpuinfo;
+
+        ppc_md.init_IRQ = mpc85xx_cds_init_IRQ;
+        ppc_md.get_irq = openpic_get_irq;
+
+        ppc_md.restart = mpc85xx_restart;
+        ppc_md.power_off = mpc85xx_power_off;
+        ppc_md.halt = mpc85xx_halt;
+
+        ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+        ppc_md.time_init = NULL;
+        ppc_md.set_rtc_time = NULL;
+        ppc_md.get_rtc_time = NULL;
+        ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+        ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+        if (ppc_md.progress)
+                ppc_md.progress("mpc85xx_cds_init(): exit", 0);
+
+        return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
new file mode 100644 (file)
index 0000000..a7290ed
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+ *
+ * MPC85xx CDS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor, 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.
+ *
+ */
+
+#ifndef __MACH_MPC85XX_CDS_H__
+#define __MACH_MPC85XX_CDS_H__
+
+#include <linux/config.h>
+#include <linux/serial.h>
+#include <asm/ppcboot.h>
+#include <linux/initrd.h>
+#include <syslib/ppc85xx_setup.h>
+
+#define BOARD_CCSRBAR           ((uint)0xe0000000)
+#define CCSRBAR_SIZE            ((uint)1024*1024)
+
+/* CADMUS info */
+#define CADMUS_BASE (0xf8004000)
+#define CADMUS_SIZE (256)
+#define CM_VER (0)
+#define CM_CSR (1)
+#define CM_RST (2)
+
+/* PCI config */
+#define PCI1_CFG_ADDR_OFFSET   (0x8000)
+#define PCI1_CFG_DATA_OFFSET   (0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET   (0x9000)
+#define PCI2_CFG_DATA_OFFSET   (0x9004)
+
+/* PCI interrupt controller */
+#define PIRQ0A                   MPC85xx_IRQ_EXT0
+#define PIRQ0B                   MPC85xx_IRQ_EXT1
+#define PIRQ0C                   MPC85xx_IRQ_EXT2
+#define PIRQ0D                   MPC85xx_IRQ_EXT3
+#define PIRQ1A                   MPC85xx_IRQ_EXT11
+
+/* PCI 1 memory map */
+#define MPC85XX_PCI1_LOWER_IO        0x00000000
+#define MPC85XX_PCI1_UPPER_IO        0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM       0x80000000
+#define MPC85XX_PCI1_UPPER_MEM       0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE         0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET      0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE         0x01000000
+
+/* PCI 2 memory map */
+#define MPC85XX_PCI2_LOWER_IO        0x01000000
+#define MPC85XX_PCI2_UPPER_IO        0x01ffffff
+
+#define MPC85XX_PCI2_LOWER_MEM       0xa0000000
+#define MPC85XX_PCI2_UPPER_MEM       0xbfffffff
+
+#define MPC85XX_PCI2_IO_BASE         0xe3000000
+#define MPC85XX_PCI2_MEM_OFFSET      0x00000000
+
+#define MPC85XX_PCI2_IO_SIZE         0x01000000
+
+#define SERIAL_PORT_DFNS               \
+              STD_UART_OP(0)           \
+              STD_UART_OP(1)
+
+#endif /* __MACH_MPC85XX_CDS_H__ */
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
new file mode 100644 (file)
index 0000000..d97c009
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * arch/ppc/platforms/85xx/sbc8560.c
+ * 
+ * Wind River SBC8560 board specific routines
+ * 
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/initrd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+struct ocp_gfar_data mpc85xx_tsec1_def = {
+       .interruptTransmit = MPC85xx_IRQ_TSEC1_TX,
+       .interruptError = MPC85xx_IRQ_TSEC1_ERROR,
+       .interruptReceive = MPC85xx_IRQ_TSEC1_RX,
+       .interruptPHY = MPC85xx_IRQ_EXT6,
+       .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR | GFAR_HAS_PHY_INTR),
+       .phyid = 25,
+       .phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_tsec2_def = {
+       .interruptTransmit = MPC85xx_IRQ_TSEC2_TX,
+       .interruptError = MPC85xx_IRQ_TSEC2_ERROR,
+       .interruptReceive = MPC85xx_IRQ_TSEC2_RX,
+       .interruptPHY = MPC85xx_IRQ_EXT7,
+       .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR | GFAR_HAS_PHY_INTR),
+       .phyid = 26,
+       .phyregidx = 0,
+};
+
+struct ocp_fs_i2c_data mpc85xx_i2c1_def = {
+       .flags = FS_I2C_SEPARATE_DFSRR,
+};
+
+
+#ifdef CONFIG_SERIAL_8250
+static void __init
+sbc8560_early_serial_map(void)
+{
+        struct uart_port uart_req;
+        /* Setup serial port access */
+        memset(&uart_req, 0, sizeof (uart_req));
+       uart_req.irq = MPC85xx_IRQ_EXT9;
+       uart_req.flags = STD_COM_FLAGS;
+       uart_req.uartclk = BASE_BAUD * 16;
+        uart_req.iotype = SERIAL_IO_MEM;
+        uart_req.mapbase = UARTA_ADDR;
+        uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE);
+       uart_req.type = PORT_16650;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+        gen550_init(0, &uart_req);
+#endif
+        if (early_serial_setup(&uart_req) != 0)
+                printk("Early serial init of port 0 failed\n");
+        /* Assume early_serial_setup() doesn't modify uart_req */
+       uart_req.line = 1;
+        uart_req.mapbase = UARTB_ADDR;
+        uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE);
+       uart_req.irq = MPC85xx_IRQ_EXT10;
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+        gen550_init(1, &uart_req);
+#endif
+        if (early_serial_setup(&uart_req) != 0)
+                printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+sbc8560_setup_arch(void)
+{
+       struct ocp_def *def;
+       struct ocp_gfar_data *einfo;
+       bd_t *binfo = (bd_t *) __res;
+       unsigned int freq;
+
+       /* get the core frequency */
+       freq = binfo->bi_intfreq;
+
+       if (ppc_md.progress)
+               ppc_md.progress("sbc8560_setup_arch()", 0);
+
+       /* Set loops_per_jiffy to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+       /* setup PCI host bridges */
+       mpc85xx_setup_hose();
+#endif
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+#ifdef CONFIG_SERIAL_8250
+       sbc8560_early_serial_map();
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       /* Invalidate the entry we stole earlier the serial ports
+        * should be properly mapped */ 
+       invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+       /* Set up MAC addresses for the Ethernet devices */
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6);
+       }
+
+       def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1);
+       if (def) {
+               einfo = (struct ocp_gfar_data *) def->additions;
+               memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6);
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_HDA1;
+#endif
+
+       ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base));
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       /* parse_bootinfo must always be called first */
+       parse_bootinfo(find_bootinfo());
+
+       /*
+        * If we were passed in a board information, copy it into the
+        * residual data area.
+        */
+       if (r3) {
+               memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+                      sizeof (bd_t));
+       }
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+       settlbcam(NUM_TLBCAMS - 1, UARTA_ADDR,
+                 UARTA_ADDR, 0x1000, _PAGE_IO, 0);
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+       /*
+        * If the init RAM disk has been configured in, and there's a valid
+        * starting address for it, set it up.
+        */
+       if (r4) {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif                         /* CONFIG_BLK_DEV_INITRD */
+
+       /* Copy the kernel command line arguments to a safe place. */
+
+       if (r6) {
+               *(char *) (r7 + KERNELBASE) = 0;
+               strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+       }
+
+       /* setup the PowerPC module struct */
+       ppc_md.setup_arch = sbc8560_setup_arch;
+       ppc_md.show_cpuinfo = sbc8560_show_cpuinfo;
+
+       ppc_md.init_IRQ = sbc8560_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+
+       ppc_md.restart = mpc85xx_restart;
+       ppc_md.power_off = mpc85xx_power_off;
+       ppc_md.halt = mpc85xx_halt;
+
+       ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+       ppc_md.time_init = NULL;
+       ppc_md.set_rtc_time = NULL;
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+       ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+       if (ppc_md.progress)
+               ppc_md.progress("sbc8560_init(): exit", 0);
+}
diff --git a/arch/ppc/platforms/85xx/sbc8560.h b/arch/ppc/platforms/85xx/sbc8560.h
new file mode 100644 (file)
index 0000000..5e1b00c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/platforms/85xx/sbc8560.h
+ *
+ * Wind River SBC8560 board definitions
+ *
+ * Copyright 2003 Motorola 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.
+ *
+ */
+#ifndef __MACH_SBC8560_H__
+#define __MACH_SBC8560_H__
+#include <linux/config.h>
+#include <platforms/85xx/sbc85xx.h>
+
+#define CPM_MAP_ADDR    (CCSRBAR + MPC85xx_CPM_OFFSET)
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  2
+#endif
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD ( 1843200 / 16 )
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
+#endif
+
+#define STD_SERIAL_PORT_DFNS \
+        { 0, BASE_BAUD, UARTA_ADDR, MPC85xx_IRQ_EXT9, STD_COM_FLAGS, /* ttyS0 */ \
+                iomem_base: (u8 *)UARTA_ADDR,                       \
+                io_type: SERIAL_IO_MEM },                                 \
+        { 0, BASE_BAUD, UARTB_ADDR, MPC85xx_IRQ_EXT10, STD_COM_FLAGS, /* ttyS1 */ \
+                iomem_base: (u8 *)UARTB_ADDR,                       \
+                io_type: SERIAL_IO_MEM },
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DFNS
+#endif /* __MACH_SBC8560_H__ */
diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c
new file mode 100644 (file)
index 0000000..043040d
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * arch/ppc/platforms/lite5200.c
+ *
+ * Platform support file for the Freescale LITE5200 based on MPC52xx.
+ * A maximum of this file should be moved to syslib/mpc52xx_?????
+ * so that new platform based on MPC52xx need a minimal platform file
+ * ( avoid code duplication )
+ *
+ * 
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Based on the 2.4 code written by Kent Borg,
+ * Dale Farnsworth <dale.farnsworth@mvista.com> and
+ * Wolfgang Denk <wd@denx.de>
+ * 
+ * Copyright 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright 2003 Motorola Inc.
+ * Copyright 2003 MontaVista Software Inc.
+ * Copyright 2003 DENX Software Engineering (wd@denx.de)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/initrd.h>
+#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+#include <asm/mpc52xx.h>
+
+
+/* Board data given by U-Boot */
+bd_t __res;
+EXPORT_SYMBOL(__res);  /* For modules */
+
+
+/* ======================================================================== */
+/* OCP device definition                                                    */
+/* For board/shared resources like PSCs                                     */
+/* ======================================================================== */
+/* Be sure not to load conficting devices : e.g. loading the UART drivers for
+ * PSC1 and then also loading a AC97 for this same PSC.
+ * For details about how to create an entry, look in the doc of the concerned
+ * driver ( eg drivers/serial/mpc52xx_uart.c for the PSC in uart mode )
+ */
+
+struct ocp_def board_ocp[] = {
+       {
+               .vendor         = OCP_VENDOR_FREESCALE,
+               .function       = OCP_FUNC_PSC_UART,
+               .index          = 0,
+               .paddr          = MPC52xx_PSC1,
+               .irq            = MPC52xx_PSC1_IRQ,
+               .pm             = OCP_CPM_NA,
+       },
+       {       /* Terminating entry */
+               .vendor         = OCP_VENDOR_INVALID
+       }
+};
+       
+
+/* ======================================================================== */
+/* Platform specific code                                                   */
+/* ======================================================================== */
+
+static int
+icecube_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "machine\t\t: Freescale LITE5200\n");
+       return 0;
+}
+
+static void __init
+icecube_setup_arch(void)
+{
+
+       /* Add board OCP definitions */
+       mpc52xx_add_board_devices(board_ocp);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+              unsigned long r6, unsigned long r7)
+{
+       /* Generic MPC52xx platform initialization */
+       /* TODO Create one and move a max of stuff in it.
+          Put this init in the syslib */
+
+       struct bi_record *bootinfo = find_bootinfo();
+
+       if (bootinfo)
+               parse_bootinfo(bootinfo);
+       else {
+               /* Load the bd_t board info structure */
+               if (r3)
+                       memcpy((void*)&__res,(void*)(r3+KERNELBASE),
+                                       sizeof(bd_t));
+
+#ifdef CONFIG_BLK_DEV_INITRD
+               /* Load the initrd */
+               if (r4) {
+                       initrd_start = r4 + KERNELBASE;
+                       initrd_end = r5 + KERNELBASE;
+               }
+#endif
+       
+               /* Load the command line */
+               if (r6) {
+                       *(char *)(r7+KERNELBASE) = 0;
+                       strcpy(cmd_line, (char *)(r6+KERNELBASE));
+               }
+       }
+
+       /* BAT setup */
+       mpc52xx_set_bat();
+       
+       /* No ISA bus AFAIK */
+       isa_io_base             = 0;
+       isa_mem_base            = 0;
+
+       /* Setup the ppc_md struct */
+       ppc_md.setup_arch       = icecube_setup_arch;
+       ppc_md.show_cpuinfo     = icecube_show_cpuinfo;
+       ppc_md.show_percpuinfo  = NULL;
+       ppc_md.init_IRQ         = mpc52xx_init_irq;
+       ppc_md.get_irq          = mpc52xx_get_irq;
+
+       ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory;
+       ppc_md.setup_io_mappings  = mpc52xx_map_io;
+
+       ppc_md.restart          = mpc52xx_restart;
+       ppc_md.power_off        = mpc52xx_power_off;
+       ppc_md.halt             = mpc52xx_halt;
+       
+               /* No time keeper on the IceCube */
+       ppc_md.time_init        = NULL;
+       ppc_md.get_rtc_time     = NULL;
+       ppc_md.set_rtc_time     = NULL;
+       
+       ppc_md.calibrate_decr   = mpc52xx_calibrate_decr;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       ppc_md.progress         = mpc52xx_progress;
+#endif
+}
+
diff --git a/arch/ppc/platforms/lite5200.h b/arch/ppc/platforms/lite5200.h
new file mode 100644 (file)
index 0000000..833134b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/ppc/platforms/lite5200.h
+ * 
+ * Definitions for Freescale LITE5200 : MPC52xx Standard Development
+ * Platform board support
+ * 
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ * 
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __PLATFORMS_LITE5200_H__
+#define __PLATFORMS_LITE5200_H__
+
+/* Serial port used for low-level debug */
+#define MPC52xx_PF_CONSOLE_PORT 0      /* PSC1 */
+
+
+#endif /* __PLATFORMS_LITE5200_H__ */
diff --git a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c
new file mode 100644 (file)
index 0000000..30b6936
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/ppc/platforms/mpc5200.c
+ *
+ * OCP Definitions for the boards based on MPC5200 processor. Contains
+ * definitions for every common peripherals. (Mostly all but PSCs)
+ * 
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/ocp.h>
+#include <asm/mpc52xx.h>
+
+/* Here is the core_ocp struct.
+ * With all the devices common to all board. Even if port multiplexing is
+ * not setup for them (if the user don't want them, just don't select the
+ * config option). The potentially conflicting devices (like PSCs) goes in
+ * board specific file.
+ */
+struct ocp_def core_ocp[] = {
+       {       /* Terminating entry */
+               .vendor         = OCP_VENDOR_INVALID
+       }
+};
diff --git a/arch/ppc/platforms/rpx8260.c b/arch/ppc/platforms/rpx8260.c
new file mode 100644 (file)
index 0000000..07d78d4
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * arch/ppc/platforms/rpx8260.c
+ *
+ * RPC EP8260 platform support
+ *
+ * Author: Dan Malek <dan@embeddededge.com>
+ * Derived from: pq2ads_setup.c by Kumar
+ *
+ * Copyright 2004 Embedded Edge, LLC
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+
+#include <asm/mpc8260.h>
+#include <asm/machdep.h>
+
+static void (*callback_setup_arch)(void);
+
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void m8260_init(unsigned long r3, unsigned long r4,
+       unsigned long r5, unsigned long r6, unsigned long r7);
+
+static int
+ep8260_show_cpuinfo(struct seq_file *m)
+{
+       bd_t    *binfo = (bd_t *)__res;
+
+       seq_printf(m, "vendor\t\t: RPC\n"
+                     "machine\t\t: EP8260 PPC\n"
+                     "\n"
+                     "mem size\t\t: 0x%08x\n"
+                     "console baud\t\t: %d\n"
+                     "\n",
+                     binfo->bi_memsize,
+                     binfo->bi_baudrate);
+       return 0;
+}
+
+static void __init
+ep8260_setup_arch(void)
+{
+       printk("RPC EP8260 Port\n");
+       callback_setup_arch();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       /* Generic 8260 platform initialization */
+       m8260_init(r3, r4, r5, r6, r7);
+
+       /* Anything special for this platform */
+       ppc_md.show_cpuinfo     = ep8260_show_cpuinfo;
+
+       callback_setup_arch     = ppc_md.setup_arch;
+       ppc_md.setup_arch       = ep8260_setup_arch;
+}
diff --git a/arch/ppc/platforms/rpx8260.h b/arch/ppc/platforms/rpx8260.h
new file mode 100644 (file)
index 0000000..7d5cd88
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Embedded Planet RPX6 (or RPX Super) MPC8260 board.
+ * Copied from the RPX-Classic and SBS8260 stuff.
+ *
+ * Copyright (c) 2001 Dan Malek <dan@embeddededge.com>
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_PLATFORMS_RPX8260_H__
+#define __ASM_PLATFORMS_RPX8260_H__
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+       unsigned int    bi_memstart;    /* Memory start address */
+       unsigned int    bi_memsize;     /* Memory (end) size in bytes */
+       unsigned int    bi_nvsize;      /* NVRAM size in bytes (can be 0) */
+       unsigned int    bi_intfreq;     /* Internal Freq, in Hz */
+       unsigned int    bi_busfreq;     /* Bus Freq, in MHz */
+       unsigned int    bi_cpmfreq;     /* CPM Freq, in MHz */
+       unsigned int    bi_brgfreq;     /* BRG Freq, in MHz */
+       unsigned int    bi_vco;         /* VCO Out from PLL */
+       unsigned int    bi_baudrate;    /* Default console baud rate */
+       unsigned int    bi_immr;        /* IMMR when called from boot rom */
+       unsigned char   bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define CPM_MAP_ADDR           ((uint)0xf0000000)
+#define RPX_CSR_ADDR           ((uint)0xfa000000)
+#define RPX_CSR_SIZE           ((uint)(512 * 1024))
+#define RPX_NVRTC_ADDR         ((uint)0xfa080000)
+#define RPX_NVRTC_SIZE         ((uint)(512 * 1024))
+
+/* The RPX6 has 16, byte wide control/status registers.
+ * Not all are used (yet).
+ */
+extern volatile u_char *rpx6_csr_addr;
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ID_MASK          ((u_char)0xf0)          /* Read only */
+#define BCSR0_SWITCH_MASK      ((u_char)0x0f)          /* Read only */
+#define BCSR1_XCVR_SMC1                ((u_char)0x80)
+#define BCSR1_XCVR_SMC2                ((u_char)0x40)
+#define BCSR2_FLASH_WENABLE    ((u_char)0x20)
+#define BCSR2_NVRAM_ENABLE     ((u_char)0x10)
+#define BCSR2_ALT_IRQ2         ((u_char)0x08)
+#define BCSR2_ALT_IRQ3         ((u_char)0x04)
+#define BCSR2_PRST             ((u_char)0x02)          /* Force reset */
+#define BCSR2_ENPRST           ((u_char)0x01)          /* Enable POR */
+#define BCSR3_MODCLK_MASK      ((u_char)0xe0)
+#define BCSR3_ENCLKHDR         ((u_char)0x10)
+#define BCSR3_LED5             ((u_char)0x04)          /* 0 == on */
+#define BCSR3_LED6             ((u_char)0x02)          /* 0 == on */
+#define BCSR3_LED7             ((u_char)0x01)          /* 0 == on */
+#define BCSR4_EN_PHY           ((u_char)0x80)          /* Enable PHY */
+#define BCSR4_EN_MII           ((u_char)0x40)          /* Enable PHY */
+#define BCSR4_MII_READ         ((u_char)0x04)
+#define BCSR4_MII_MDC          ((u_char)0x02)
+#define BCSR4_MII_MDIO         ((u_char)0x01)
+#define BCSR13_FETH_IRQMASK    ((u_char)0xf0)
+#define BCSR15_FETH_IRQ                ((u_char)0x20)
+
+#define PHY_INTERRUPT  SIU_INT_IRQ7
+
+#endif /* __ASM_PLATFORMS_RPX8260_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/syslib/cpm2_common.c b/arch/ppc/syslib/cpm2_common.c
new file mode 100644 (file)
index 0000000..ea5e770
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ *     2.3.99 Updates
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+#include <asm/mpc8260.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/immap_cpm2.h>
+#include <asm/cpm2.h>
+#include <asm/rheap.h>
+
+static void cpm2_dpinit(void);
+cpm_cpm2_t     *cpmp;          /* Pointer to comm processor space */
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+cpm2_map_t *cpm2_immr;
+
+#define CPM_MAP_SIZE   (0x40000)       /* 256k - the PQ3 reserve this amount
+                                          of space for CPM as it is larger
+                                          than on PQ2 */
+
+void
+cpm2_reset(void)
+{
+       cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
+
+       /* Reclaim the DP memory for our use.
+        */
+       cpm2_dpinit();
+
+       /* Tell everyone where the comm processor resides.
+        */
+       cpmp = &cpm2_immr->im_cpm;
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks.  The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers).  Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK    (((bd_t *)__res)->bi_brgfreq)
+#define BRG_UART_CLK   (BRG_INT_CLK/16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+cpm_setbrg(uint brg, uint rate)
+{
+       volatile uint   *bp;
+
+       /* This is good enough to get SMCs running.....
+       */
+       if (brg < 4) {
+               bp = (uint *)&cpm2_immr->im_brgc1;
+       }
+       else {
+               bp = (uint *)&cpm2_immr->im_brgc5;
+               brg -= 4;
+       }
+       bp += brg;
+       *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+cpm2_fastbrg(uint brg, uint rate, int div16)
+{
+       volatile uint   *bp;
+
+       if (brg < 4) {
+               bp = (uint *)&cpm2_immr->im_brgc1;
+       }
+       else {
+               bp = (uint *)&cpm2_immr->im_brgc5;
+               brg -= 4;
+       }
+       bp += brg;
+       *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+       if (div16)
+               *bp |= CPM_BRG_DIV16;
+}
+
+/*
+ * dpalloc / dpfree bits.
+ */
+static spinlock_t cpm_dpmem_lock;
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t cpm_boot_dpmem_rh_block[16];
+static rh_info_t cpm_dpmem_info;
+
+static void cpm2_dpinit(void)
+{
+       spin_lock_init(&cpm_dpmem_lock);
+
+       /* initialize the info header */
+       rh_init(&cpm_dpmem_info, 1,
+                       sizeof(cpm_boot_dpmem_rh_block) /
+                       sizeof(cpm_boot_dpmem_rh_block[0]),
+                       cpm_boot_dpmem_rh_block);
+
+       /* Attach the usable dpmem area */
+       /* XXX: This is actually crap. CPM_DATAONLY_BASE and
+        * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
+        * varies with the processor and the microcode patches activated.
+        * But the following should be at least safe.
+        */
+       rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
+                       CPM_DATAONLY_SIZE);
+}
+
+/* This function returns an index into the DPRAM area.
+ */
+uint cpm_dpalloc(uint size, uint align)
+{
+       void *start;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cpm_dpmem_lock, flags);
+       cpm_dpmem_info.alignment = align;
+       start = rh_alloc(&cpm_dpmem_info, size, "commproc");
+       spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+       return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc);
+
+int cpm_dpfree(uint offset)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cpm_dpmem_lock, flags);
+       ret = rh_free(&cpm_dpmem_info, (void *)offset);
+       spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(cpm_dpfree);
+
+/* not sure if this is ever needed */
+uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+{
+       void *start;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cpm_dpmem_lock, flags);
+       cpm_dpmem_info.alignment = align;
+       start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+       spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+       return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc_fixed);
+
+void cpm_dpdump(void)
+{
+       rh_dump(&cpm_dpmem_info);
+}
+EXPORT_SYMBOL(cpm_dpdump);
+
+void *cpm_dpram_addr(uint offset)
+{
+       return (void *)&cpm2_immr->im_dprambase[offset];
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
new file mode 100644 (file)
index 0000000..9c0582d
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * arch/ppc/platforms/mpc8260_pci9.c
+ *
+ * Workaround for device erratum PCI 9.
+ * See Motorola's "XPC826xA Family Device Errata Reference."
+ * The erratum applies to all 8260 family Hip4 processors.  It is scheduled 
+ * to be fixed in HiP4 Rev C.  Erratum PCI 9 states that a simultaneous PCI 
+ * inbound write transaction and PCI outbound read transaction can result in a 
+ * bus deadlock.  The suggested workaround is to use the IDMA controller to 
+ * perform all reads from PCI configuration, memory, and I/O space.
+ *
+ * Author:  andy_lowe@mvista.com
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/byteorder.h>
+#include <asm/mpc8260.h>
+#include <asm/immap_cpm2.h>
+#include <asm/cpm2.h>
+
+#include "m8260_pci.h"
+
+#ifdef CONFIG_8260_PCI9
+/*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
+
+#define IDMA_XFER_BUF_SIZE 64  /* size of the IDMA transfer buffer */
+
+/* define a structure for the IDMA dpram usage */
+typedef struct idma_dpram_s {
+       idma_t pram;                            /* IDMA parameter RAM */
+       u_char xfer_buf[IDMA_XFER_BUF_SIZE];    /* IDMA transfer buffer */
+       idma_bd_t bd;                           /* buffer descriptor */
+} idma_dpram_t;
+
+/* define offsets relative to start of IDMA dpram */
+#define IDMA_XFER_BUF_OFFSET (sizeof(idma_t))
+#define IDMA_BD_OFFSET (sizeof(idma_t) + IDMA_XFER_BUF_SIZE)
+
+/* define globals */
+static volatile idma_dpram_t *idma_dpram;
+
+/* Exactly one of CONFIG_8260_PCI9_IDMAn must be defined, 
+ * where n is 1, 2, 3, or 4.  This selects the IDMA channel used for 
+ * the PCI9 workaround.
+ */
+#ifdef CONFIG_8260_PCI9_IDMA1
+#define IDMA_CHAN 0
+#define PROFF_IDMA PROFF_IDMA1_BASE
+#define IDMA_PAGE CPM_CR_IDMA1_PAGE
+#define IDMA_SBLOCK CPM_CR_IDMA1_SBLOCK
+#endif
+#ifdef CONFIG_8260_PCI9_IDMA2
+#define IDMA_CHAN 1
+#define PROFF_IDMA PROFF_IDMA2_BASE
+#define IDMA_PAGE CPM_CR_IDMA2_PAGE
+#define IDMA_SBLOCK CPM_CR_IDMA2_SBLOCK
+#endif
+#ifdef CONFIG_8260_PCI9_IDMA3
+#define IDMA_CHAN 2
+#define PROFF_IDMA PROFF_IDMA3_BASE
+#define IDMA_PAGE CPM_CR_IDMA3_PAGE
+#define IDMA_SBLOCK CPM_CR_IDMA3_SBLOCK
+#endif
+#ifdef CONFIG_8260_PCI9_IDMA4
+#define IDMA_CHAN 3
+#define PROFF_IDMA PROFF_IDMA4_BASE
+#define IDMA_PAGE CPM_CR_IDMA4_PAGE
+#define IDMA_SBLOCK CPM_CR_IDMA4_SBLOCK
+#endif
+
+void idma_pci9_init(void)
+{
+       uint dpram_offset;
+       volatile idma_t *pram;
+       volatile im_idma_t *idma_reg;
+       volatile cpm2_map_t *immap = cpm2_immr;
+
+       /* allocate IDMA dpram */
+       dpram_offset = cpm_dpalloc(sizeof(idma_dpram_t), 64);
+       idma_dpram = cpm_dpram_addr(dpram_offset); 
+
+       /* initialize the IDMA parameter RAM */
+       memset((void *)idma_dpram, 0, sizeof(idma_dpram_t));
+       pram = &idma_dpram->pram;
+       pram->ibase = dpram_offset + IDMA_BD_OFFSET;
+       pram->dpr_buf = dpram_offset + IDMA_XFER_BUF_OFFSET;
+       pram->ss_max = 32;
+       pram->dts = 32;
+
+       /* initialize the IDMA_BASE pointer to the IDMA parameter RAM */
+       *((ushort *) &immap->im_dprambase[PROFF_IDMA]) = dpram_offset;
+
+       /* initialize the IDMA registers */
+       idma_reg = (volatile im_idma_t *) &immap->im_sdma.sdma_idsr1;
+       idma_reg[IDMA_CHAN].idmr = 0;           /* mask all IDMA interrupts */
+       idma_reg[IDMA_CHAN].idsr = 0xff;        /* clear all event flags */
+
+       printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
+               IDMA_CHAN + 1);
+
+       return;
+}
+
+/* Use the IDMA controller to transfer data from I/O memory to local RAM.
+ * The src address must be a physical address suitable for use by the DMA 
+ * controller with no translation.  The dst address must be a kernel virtual 
+ * address.  The dst address is translated to a physical address via 
+ * virt_to_phys().
+ * The sinc argument specifies whether or not the source address is incremented
+ * by the DMA controller.  The source address is incremented if and only if sinc
+ * is non-zero.  The destination address is always incremented since the 
+ * destination is always host RAM.
+ */
+static void 
+idma_pci9_read(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
+{
+       unsigned long flags;
+       volatile idma_t *pram = &idma_dpram->pram;
+       volatile idma_bd_t *bd = &idma_dpram->bd;
+       volatile cpm2_map_t *immap = cpm2_immr;
+
+       local_irq_save(flags);
+
+       /* initialize IDMA parameter RAM for this transfer */
+       if (sinc)
+               pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
+                         | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
+       else
+               pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_DINC 
+                         | IDMA_DCM_SD_MEM2MEM;
+       pram->ibdptr = pram->ibase;
+       pram->sts = unit_size;
+       pram->istate = 0;
+
+       /* initialize the buffer descriptor */
+       bd->dst = virt_to_phys(dst);
+       bd->src = (uint) src;
+       bd->len = bytes;
+       bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
+                 | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
+
+       /* issue the START_IDMA command to the CP */
+       while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
+       immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
+                                        CPM_CR_START_IDMA) | CPM_CR_FLG;
+       while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+       /* wait for transfer to complete */
+       while(bd->flags & IDMA_BD_V);
+
+       local_irq_restore(flags);
+
+       return;
+}
+
+/* Use the IDMA controller to transfer data from I/O memory to local RAM.
+ * The dst address must be a physical address suitable for use by the DMA 
+ * controller with no translation.  The src address must be a kernel virtual 
+ * address.  The src address is translated to a physical address via 
+ * virt_to_phys().
+ * The dinc argument specifies whether or not the dest address is incremented
+ * by the DMA controller.  The source address is incremented if and only if sinc
+ * is non-zero.  The source address is always incremented since the 
+ * source is always host RAM.
+ */
+static void 
+idma_pci9_write(u8 *dst, u8 *src, int bytes, int unit_size, int dinc)
+{
+       unsigned long flags;
+       volatile idma_t *pram = &idma_dpram->pram;
+       volatile idma_bd_t *bd = &idma_dpram->bd;
+       volatile cpm2_map_t *immap = cpm2_immr;
+
+       local_irq_save(flags);
+
+       /* initialize IDMA parameter RAM for this transfer */
+       if (dinc)
+               pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
+                         | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
+       else
+               pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC 
+                         | IDMA_DCM_SD_MEM2MEM;
+       pram->ibdptr = pram->ibase;
+       pram->sts = unit_size;
+       pram->istate = 0;
+
+       /* initialize the buffer descriptor */
+       bd->dst = (uint) dst;
+       bd->src = virt_to_phys(src);
+       bd->len = bytes;
+       bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
+                 | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
+
+       /* issue the START_IDMA command to the CP */
+       while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
+       immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
+                                        CPM_CR_START_IDMA) | CPM_CR_FLG;
+       while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+       /* wait for transfer to complete */
+       while(bd->flags & IDMA_BD_V);
+
+       local_irq_restore(flags);
+
+       return;
+}
+
+/* Same as idma_pci9_read, but 16-bit little-endian byte swapping is performed
+ * if the unit_size is 2, and 32-bit little-endian byte swapping is performed if
+ * the unit_size is 4.
+ */
+static void 
+idma_pci9_read_le(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
+{
+       int i;
+       u8 *p;
+
+       idma_pci9_read(dst, src, bytes, unit_size, sinc);
+       switch(unit_size) {
+               case 2:
+                       for (i = 0, p = dst; i < bytes; i += 2, p += 2)
+                               swab16s((u16 *) p);
+                       break;
+               case 4:
+                       for (i = 0, p = dst; i < bytes; i += 4, p += 4)
+                               swab32s((u32 *) p);
+                       break;
+               default:
+                       break;
+       }
+}
+EXPORT_SYMBOL(idma_pci9_init);
+EXPORT_SYMBOL(idma_pci9_read);
+EXPORT_SYMBOL(idma_pci9_read_le);
+
+static inline int is_pci_mem(unsigned long addr)
+{
+       if (addr >= MPC826x_PCI_LOWER_MMIO &&
+           addr <= MPC826x_PCI_UPPER_MMIO)
+               return 1;
+       if (addr >= MPC826x_PCI_LOWER_MEM &&
+           addr <= MPC826x_PCI_UPPER_MEM)
+               return 1;
+       return 0;
+}
+
+#define is_pci_mem(pa) ( (pa > 0x80000000) && (pa < 0xc0000000))
+int readb(volatile unsigned char *addr)
+{
+       u8 val;
+       unsigned long pa = iopa((unsigned long) addr);
+
+       if (!is_pci_mem(pa))
+               return in_8(addr);
+
+       idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
+       return val;
+}
+
+int readw(volatile unsigned short *addr)
+{
+       u16 val;
+       unsigned long pa = iopa((unsigned long) addr);
+
+       if (!is_pci_mem(pa))
+               return in_le16(addr);
+
+       idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
+       return swab16(val);
+}
+
+unsigned readl(volatile unsigned *addr)
+{
+       u32 val;
+       unsigned long pa = iopa((unsigned long) addr);
+
+       if (!is_pci_mem(pa))
+               return in_le32(addr);
+
+       idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
+       return swab32(val);
+}
+
+int inb(unsigned port)
+{
+       u8 val;
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
+       return val;
+}
+
+int inw(unsigned port)
+{
+       u16 val;
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
+       return swab16(val);
+}
+
+unsigned inl(unsigned port)
+{
+       u32 val;
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
+       return swab32(val);
+}
+
+void insb(unsigned port, void *buf, int ns)
+{
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u8), sizeof(u8), 0);
+}
+
+void insw(unsigned port, void *buf, int ns)
+{
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
+}
+
+void insl(unsigned port, void *buf, int nl)
+{
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
+}
+
+void insw_ns(unsigned port, void *buf, int ns)
+{
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
+}
+
+void insl_ns(unsigned port, void *buf, int nl)
+{
+       u8 *addr = (u8 *)(port + _IO_BASE);
+
+       idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
+}
+
+void *memcpy_fromio(void *dest, unsigned long src, size_t count)
+{
+       unsigned long pa = iopa((unsigned long) src);
+
+       if (is_pci_mem(pa))
+               idma_pci9_read((u8 *)dest, (u8 *)pa, count, 32, 1);
+       else
+               memcpy(dest, (void *)src, count);
+       return dest;
+}
+
+EXPORT_SYMBOL(readb);
+EXPORT_SYMBOL(readw);
+EXPORT_SYMBOL(readl);
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(insw_ns);
+EXPORT_SYMBOL(insl_ns);
+EXPORT_SYMBOL(memcpy_fromio);
+
+#endif /* ifdef CONFIG_8260_PCI9 */
+
+/* Indirect PCI routines adapted from arch/ppc/kernel/indirect_pci.c.
+ * Copyright (C) 1998 Gabriel Paubert.
+ */
+#ifndef CONFIG_8260_PCI9
+#define cfg_read(val, addr, type, op)  *val = op((type)(addr))
+#else
+#define cfg_read(val, addr, type, op) \
+       idma_pci9_read_le((u8*)(val),(u8*)(addr),sizeof(*(val)),sizeof(*(val)),0)
+#endif
+
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+static int indirect_write_config(struct pci_bus *pbus, unsigned int devfn, int where,
+                        int size, u32 value)
+{
+       struct pci_controller *hose = pbus->sysdata;
+       u8 cfg_type = 0;
+       if (ppc_md.pci_exclude_device)
+               if (ppc_md.pci_exclude_device(pbus->number, devfn))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (hose->set_cfg_type)
+               if (pbus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       out_be32(hose->cfg_addr,
+                (((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
+                | ((pbus->number - hose->bus_offset) << 8) | 0x80);
+
+       switch (size)
+       {
+               case 1:
+                       cfg_write(value, hose->cfg_data + (where & 3), u8, out_8);
+                       break;
+               case 2:
+                       cfg_write(value, hose->cfg_data + (where & 2), u16, out_le16);
+                       break;
+               case 4:
+                       cfg_write(value, hose->cfg_data + (where & 0), u32, out_le32);
+                       break;
+       }               
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int indirect_read_config(struct pci_bus *pbus, unsigned int devfn, int where,
+                        int size, u32 *value)
+{
+       struct pci_controller *hose = pbus->sysdata;
+       u8 cfg_type = 0;
+       if (ppc_md.pci_exclude_device)
+               if (ppc_md.pci_exclude_device(pbus->number, devfn))
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (hose->set_cfg_type)
+               if (pbus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       out_be32(hose->cfg_addr,
+                (((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
+                | ((pbus->number - hose->bus_offset) << 8) | 0x80);
+
+       switch (size)
+       {
+               case 1:
+                       cfg_read(value, hose->cfg_data + (where & 3), u8 *, in_8);
+                       break;
+               case 2:
+                       cfg_read(value, hose->cfg_data + (where & 2), u16 *, in_le16);
+                       break;
+               case 4:
+                       cfg_read(value, hose->cfg_data + (where & 0), u32 *, in_le32);
+                       break;
+       }               
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops =
+{
+       .read = indirect_read_config,
+       .write = indirect_write_config,
+};
+
+void
+setup_m8260_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+       hose->ops = &indirect_pci_ops;
+       hose->cfg_addr = (unsigned int *) ioremap(cfg_addr, 4);
+       hose->cfg_data = (unsigned char *) ioremap(cfg_data, 4);
+}
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
new file mode 100644 (file)
index 0000000..0f88e63
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * arch/ppc/syslib/mpc52xx_pic.c
+ *
+ * Programmable Interrupt Controller functions for the Freescale MPC52xx 
+ * embedded CPU.
+ *
+ * 
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Based on (well, mostly copied from) the code from the 2.4 kernel by
+ * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
+ * 
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
+ * 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/mpc52xx.h>
+
+
+static struct mpc52xx_intr *intr;
+static struct mpc52xx_sdma *sdma;
+
+static void
+mpc52xx_ic_disable(unsigned int irq)
+{
+       u32 val;
+
+       if (irq == MPC52xx_IRQ0) {
+               val = in_be32(&intr->ctrl);
+               val &= ~(1 << 11);
+               out_be32(&intr->ctrl, val);
+       }
+       else if (irq < MPC52xx_IRQ1) {
+               BUG();
+       }
+       else if (irq <= MPC52xx_IRQ3) {
+               val = in_be32(&intr->ctrl);
+               val &= ~(1 << (10 - (irq - MPC52xx_IRQ1)));
+               out_be32(&intr->ctrl, val);
+       }
+       else if (irq < MPC52xx_SDMA_IRQ_BASE) {
+               val = in_be32(&intr->main_mask);
+               val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE));
+               out_be32(&intr->main_mask, val);
+       }
+       else if (irq < MPC52xx_PERP_IRQ_BASE) {
+               val = in_be32(&sdma->IntMask);
+               val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE);
+               out_be32(&sdma->IntMask, val);
+       }
+       else {
+               val = in_be32(&intr->per_mask);
+               val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
+               out_be32(&intr->per_mask, val);
+       }
+}
+
+static void
+mpc52xx_ic_enable(unsigned int irq)
+{
+       u32 val;
+
+       if (irq == MPC52xx_IRQ0) {
+               val = in_be32(&intr->ctrl);
+               val |= 1 << 11;
+               out_be32(&intr->ctrl, val);
+       }
+       else if (irq < MPC52xx_IRQ1) {
+               BUG();
+       }
+       else if (irq <= MPC52xx_IRQ3) {
+               val = in_be32(&intr->ctrl);
+               val |= 1 << (10 - (irq - MPC52xx_IRQ1));
+               out_be32(&intr->ctrl, val);
+       }
+       else if (irq < MPC52xx_SDMA_IRQ_BASE) {
+               val = in_be32(&intr->main_mask);
+               val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)));
+               out_be32(&intr->main_mask, val);
+       }
+       else if (irq < MPC52xx_PERP_IRQ_BASE) {
+               val = in_be32(&sdma->IntMask);
+               val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE));
+               out_be32(&sdma->IntMask, val);
+       }
+       else {
+               val = in_be32(&intr->per_mask);
+               val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
+               out_be32(&intr->per_mask, val);
+       }
+}
+
+static void
+mpc52xx_ic_ack(unsigned int irq)
+{
+       u32 val;
+
+       /*
+        * Only some irqs are reset here, others in interrupting hardware.
+        */
+                       
+       switch (irq) {
+       case MPC52xx_IRQ0:
+               val = in_be32(&intr->ctrl);
+               val |= 0x08000000;
+               out_be32(&intr->ctrl, val);
+               break;
+       case MPC52xx_CCS_IRQ:
+               val = in_be32(&intr->enc_status);
+               val |= 0x00000400;
+               out_be32(&intr->enc_status, val);
+               break;
+       case MPC52xx_IRQ1:
+               val = in_be32(&intr->ctrl);
+               val |= 0x04000000;
+               out_be32(&intr->ctrl, val);
+               break;
+       case MPC52xx_IRQ2:
+               val = in_be32(&intr->ctrl);
+               val |= 0x02000000;
+               out_be32(&intr->ctrl, val);
+               break;
+       case MPC52xx_IRQ3:
+               val = in_be32(&intr->ctrl);
+               val |= 0x01000000;
+               out_be32(&intr->ctrl, val);
+               break;
+       default:
+               if (irq >= MPC52xx_SDMA_IRQ_BASE
+                   && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) {
+                       out_be32(&sdma->IntPend,
+                                1 << (irq - MPC52xx_SDMA_IRQ_BASE));
+               }
+               break;
+       }
+}
+
+static void
+mpc52xx_ic_disable_and_ack(unsigned int irq)
+{
+       mpc52xx_ic_disable(irq);
+       mpc52xx_ic_ack(irq);
+}
+
+static void
+mpc52xx_ic_end(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               mpc52xx_ic_enable(irq);
+}
+
+static struct hw_interrupt_type mpc52xx_ic = {
+       "MPC52xx",
+       NULL,                           /* startup(irq) */
+       NULL,                           /* shutdown(irq) */
+       mpc52xx_ic_enable,              /* enable(irq) */
+       mpc52xx_ic_disable,             /* disable(irq) */
+       mpc52xx_ic_disable_and_ack,     /* disable_and_ack(irq) */
+       mpc52xx_ic_end,                 /* end(irq) */
+       0                               /* set_affinity(irq, cpumask) SMP. */
+};
+
+void __init
+mpc52xx_init_irq(void)
+{
+       int i;
+
+       /* Remap the necessary zones */
+       intr = (struct mpc52xx_intr *)
+               ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr));
+       sdma = (struct mpc52xx_sdma *)
+               ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma));
+       
+       if ((intr==NULL) || (sdma==NULL))
+               panic("Can't ioremap PIC/SDMA register for init_irq !");
+
+       /* Disable all interrupt sources. */
+       out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
+       out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
+       out_be32(&intr->per_mask, 0x7ffffc00);  /* 1 means disabled */
+       out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
+       out_be32(&intr->ctrl,
+                       0x0f000000 |    /* clear IRQ 0-3 */
+                       0x00c00000 |    /* IRQ0: level-sensitive, active low */
+                       0x00001000 |    /* MEE master external enable */
+                       0x00000000 |    /* 0 means disable IRQ 0-3 */
+                       0x00000001);    /* CEb route critical normally */
+
+       /* Zero a bunch of the priority settings.  */
+       out_be32(&intr->per_pri1, 0);
+       out_be32(&intr->per_pri2, 0);
+       out_be32(&intr->per_pri3, 0);
+       out_be32(&intr->main_pri1, 0);
+       out_be32(&intr->main_pri2, 0);
+
+       /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc[i].handler = &mpc52xx_ic;
+               irq_desc[i].status = IRQ_LEVEL;
+       }
+}
+
+int
+mpc52xx_get_irq(struct pt_regs *regs)
+{
+       u32 status;
+       int irq = -1;
+
+       status = in_be32(&intr->enc_status);
+
+       if (status & 0x00000400) {              /* critical */
+               irq = (status >> 8) & 0x3;
+               if (irq == 2)                   /* high priority peripheral */
+                       goto peripheral;
+               irq += MPC52xx_CRIT_IRQ_BASE;
+       }
+       else if (status & 0x00200000) {         /* main */
+               irq = (status >> 16) & 0x1f;
+               if (irq == 4)                   /* low priority peripheral */
+                       goto peripheral;
+               irq += MPC52xx_MAIN_IRQ_BASE;
+       }
+       else if (status & 0x20000000) {         /* peripheral */
+peripheral:
+               irq = (status >> 24) & 0x1f;
+               if (irq == 0) {                 /* bestcomm */
+                       status = in_be32(&sdma->IntPend);
+                       irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
+               }
+               else
+                       irq += MPC52xx_PERP_IRQ_BASE;
+       }
+
+       return irq;
+}
+
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
new file mode 100644 (file)
index 0000000..631cea3
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * arch/ppc/syslib/mpc52xx_common.c
+ *
+ * Common code for the boards based on Freescale MPC52xx embedded CPU.
+ *
+ * 
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Support for other bootloaders than UBoot by Dale Farnsworth 
+ * <dfarnsworth@mvista.com>
+ * 
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
+ * 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+
+#include <asm/time.h>
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+#include <asm/ocp.h>
+#include <asm/ppcboot.h>
+
+extern bd_t __res;
+
+static int core_mult[] = {             /* CPU Frequency multiplier, taken    */
+       0,  0,  0,  10, 20, 20, 25, 45, /* from the datasheet used to compute */
+       30, 55, 40, 50, 0,  60, 35, 0,  /* CPU frequency from XLB freq and    */
+       30, 25, 65, 10, 70, 20, 75, 45, /* external jumper config             */
+       0,  55, 40, 50, 80, 60, 35, 0
+};
+
+void
+mpc52xx_restart(char *cmd)
+{
+       struct mpc52xx_gpt* gpt0 = (struct mpc52xx_gpt*) MPC52xx_GPTx(0);
+       
+       local_irq_disable();
+       
+       /* Turn on the watchdog and wait for it to expire. It effectively
+         does a reset */
+       if (gpt0 != NULL) {
+               out_be32(&gpt0->count, 0x000000ff);
+               out_be32(&gpt0->mode, 0x00009004);
+       } else
+               printk(KERN_ERR "mpc52xx_restart: Unable to ioremap GPT0 registers, -> looping ...");
+
+       while (1);
+}
+
+void
+mpc52xx_halt(void)
+{
+       local_irq_disable();
+
+       while (1);
+}
+
+void
+mpc52xx_power_off(void)
+{
+       /* By default we don't have any way of shut down.
+          If a specific board wants to, it can set the power down
+          code to any hardware implementation dependent code */
+       mpc52xx_halt();
+}
+
+
+void __init
+mpc52xx_set_bat(void)
+{
+       /* Set BAT 2 to map the 0xf0000000 area */
+       /* This mapping is used during mpc52xx_progress,
+        * mpc52xx_find_end_of_memory, and UARTs/GPIO access for debug
+        */
+       mb();
+       mtspr(DBAT2U, 0xf0001ffe);
+       mtspr(DBAT2L, 0xf000002a);
+       mb();
+}
+
+void __init
+mpc52xx_map_io(void)
+{
+       /* Here we only map the MBAR */
+       io_block_mapping(
+               MPC52xx_MBAR_VIRT, MPC52xx_MBAR, MPC52xx_MBAR_SIZE, _PAGE_IO);
+}
+
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+#ifdef MPC52xx_PF_CONSOLE_PORT
+#define MPC52xx_CONSOLE MPC52xx_PSCx(MPC52xx_PF_CONSOLE_PORT)
+#else
+#error "mpc52xx PSC for console not selected"
+#endif
+
+void
+mpc52xx_progress(char *s, unsigned short hex)
+{
+       struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE;
+       char c;
+
+               /* Don't we need to disable serial interrupts ? */
+       
+       while ((c = *s++) != 0) {
+               if (c == '\n') {
+                       while (!(in_be16(&psc->mpc52xx_psc_status) &
+                                MPC52xx_PSC_SR_TXRDY)) ;
+                       out_8(&psc->mpc52xx_psc_buffer_8, '\r');
+               }
+               while (!(in_be16(&psc->mpc52xx_psc_status) &
+                        MPC52xx_PSC_SR_TXRDY)) ;
+               out_8(&psc->mpc52xx_psc_buffer_8, c);
+       }
+}
+
+#endif  /* CONFIG_SERIAL_TEXT_DEBUG */
+
+
+unsigned long __init
+mpc52xx_find_end_of_memory(void)
+{
+       u32 ramsize = __res.bi_memsize;
+
+       /*
+        * if bootloader passed a memsize, just use it
+        * else get size from sdram config registers
+        */
+       if (ramsize == 0) {
+               struct mpc52xx_mmap_ctl *mmap_ctl;
+               u32 sdram_config_0, sdram_config_1;
+
+               /* Temp BAT2 mapping active when this is called ! */
+               mmap_ctl = (struct mpc52xx_mmap_ctl*) MPC52xx_MMAP_CTL;
+                       
+               sdram_config_0 = in_be32(&mmap_ctl->sdram0);
+               sdram_config_1 = in_be32(&mmap_ctl->sdram1);
+
+               if ((sdram_config_0 & 0x1f) >= 0x13)
+                       ramsize = 1 << ((sdram_config_0 & 0xf) + 17);
+
+               if (((sdram_config_1 & 0x1f) >= 0x13) &&
+                               ((sdram_config_1 & 0xfff00000) == ramsize))
+                       ramsize += 1 << ((sdram_config_1 & 0xf) + 17);
+
+               iounmap(mmap_ctl);
+       }
+       
+       return ramsize;
+}
+
+void __init
+mpc52xx_calibrate_decr(void)
+{
+       int current_time, previous_time;
+       int tbl_start, tbl_end;
+       unsigned int xlbfreq, cpufreq, ipbfreq, pcifreq, divisor;
+
+       xlbfreq = __res.bi_busfreq;
+       /* if bootloader didn't pass bus frequencies, calculate them */
+       if (xlbfreq == 0) {
+               /* Get RTC & Clock manager modules */
+               struct mpc52xx_rtc *rtc;
+               struct mpc52xx_cdm *cdm;
+               
+               rtc = (struct mpc52xx_rtc*)
+                       ioremap(MPC52xx_RTC, sizeof(struct mpc52xx_rtc));
+               cdm = (struct mpc52xx_cdm*)
+                       ioremap(MPC52xx_CDM, sizeof(struct mpc52xx_cdm));
+
+               if ((rtc==NULL) || (cdm==NULL))
+                       panic("Can't ioremap RTC/CDM while computing bus freq");
+
+               /* Count bus clock during 1/64 sec */
+               out_be32(&rtc->dividers, 0x8f1f0000);   /* Set RTC 64x faster */
+               previous_time = in_be32(&rtc->time);
+               while ((current_time = in_be32(&rtc->time)) == previous_time) ;
+               tbl_start = get_tbl();
+               previous_time = current_time;
+               while ((current_time = in_be32(&rtc->time)) == previous_time) ;
+               tbl_end = get_tbl();
+               out_be32(&rtc->dividers, 0xffff0000);   /* Restore RTC */
+
+               /* Compute all frequency from that & CDM settings */
+               xlbfreq = (tbl_end - tbl_start) << 8;
+               cpufreq = (xlbfreq * core_mult[in_be32(&cdm->rstcfg)&0x1f])/10;
+               ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ?
+                                       xlbfreq / 2 : xlbfreq;
+               switch (in_8(&cdm->pci_clk_sel) & 3) {
+               case 0:
+                       pcifreq = ipbfreq;
+                       break;
+               case 1:
+                       pcifreq = ipbfreq / 2;
+                       break;
+               default:
+                       pcifreq = xlbfreq / 4;
+                       break;
+               }
+               __res.bi_busfreq = xlbfreq;
+               __res.bi_intfreq = cpufreq;
+               __res.bi_ipbfreq = ipbfreq;
+               __res.bi_pcifreq = pcifreq;
+       
+               /* Release mapping */
+               iounmap((void*)rtc);
+               iounmap((void*)cdm);
+       }
+
+       divisor = 4;
+
+       tb_ticks_per_jiffy = xlbfreq / HZ / divisor;
+       tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
+}
+
+
+void __init
+mpc52xx_add_board_devices(struct ocp_def board_ocp[]) {
+       while (board_ocp->vendor != OCP_VENDOR_INVALID)
+               if(ocp_add_one_device(board_ocp++))
+                       printk("mpc5200-ocp: Failed to add board device !\n");
+}
+
diff --git a/arch/ppc/syslib/ppc4xx_sgdma.c b/arch/ppc/syslib/ppc4xx_sgdma.c
new file mode 100644 (file)
index 0000000..49c6e9c
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * arch/ppc/kernel/ppc4xx_sgdma.c
+ *
+ * IBM PPC4xx DMA engine scatter/gather library
+ *
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * Cleaned up and converted to new DCR access
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Original code by Armin Kuster <akuster@mvista.com>
+ * and Pete Popov <ppopov@mvista.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.
+ *
+ * You 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ppc4xx_dma.h>
+
+void
+ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
+{
+       if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+               printk("ppc4xx_set_sg_addr: bad channel: %d\n", dmanr);
+               return;
+       }
+
+#ifdef PPC4xx_DMA_64BIT
+       mtdcr(DCRN_ASGH0 + (dmanr * 0x8), (u32)(sg_addr >> 32));
+#endif
+       mtdcr(DCRN_ASG0 + (dmanr * 0x8), (u32)sg_addr);
+}
+
+/*
+ *   Add a new sgl descriptor to the end of a scatter/gather list
+ *   which was created by alloc_dma_handle().
+ *
+ *   For a memory to memory transfer, both dma addresses must be
+ *   valid. For a peripheral to memory transfer, one of the addresses
+ *   must be set to NULL, depending on the direction of the transfer:
+ *   memory to peripheral: set dst_addr to NULL,
+ *   peripheral to memory: set src_addr to NULL.
+ */
+int
+ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
+                  unsigned int count)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+       ppc_dma_ch_t *p_dma_ch;
+
+       if (!handle) {
+               printk("ppc4xx_add_dma_sgl: null handle\n");
+               return DMA_STATUS_BAD_HANDLE;
+       }
+
+       if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+               printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
+               return DMA_STATUS_BAD_CHANNEL;
+       }
+
+       p_dma_ch = &dma_channels[psgl->dmanr];
+
+#ifdef DEBUG_4xxDMA
+       {
+               int error = 0;
+               unsigned int aligned =
+                   (unsigned) src_addr | (unsigned) dst_addr | count;
+               switch (p_dma_ch->pwidth) {
+               case PW_8:
+                       break;
+               case PW_16:
+                       if (aligned & 0x1)
+                               error = 1;
+                       break;
+               case PW_32:
+                       if (aligned & 0x3)
+                               error = 1;
+                       break;
+               case PW_64:
+                       if (aligned & 0x7)
+                               error = 1;
+                       break;
+               default:
+                       printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
+                              p_dma_ch->pwidth);
+                       return DMA_STATUS_GENERAL_ERROR;
+               }
+               if (error)
+                       printk
+                           ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
+                            src_addr, dst_addr, count, p_dma_ch->pwidth);
+
+       }
+#endif
+
+       if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
+               printk("sgl handle out of memory \n");
+               return DMA_STATUS_OUT_OF_MEMORY;
+       }
+
+       if (!psgl->ptail) {
+               psgl->phead = (ppc_sgl_t *)
+                   ((unsigned) psgl + sizeof (sgl_list_info_t));
+               psgl->phead_dma = psgl->dma_addr + sizeof(sgl_list_info_t);
+               psgl->ptail = psgl->phead;
+               psgl->ptail_dma = psgl->phead_dma;
+       } else {
+               psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t);
+               psgl->ptail++;
+               psgl->ptail_dma += sizeof(ppc_sgl_t);
+       }
+
+       psgl->ptail->control = psgl->control;
+       psgl->ptail->src_addr = src_addr;
+       psgl->ptail->dst_addr = dst_addr;
+       psgl->ptail->control_count = (count >> p_dma_ch->shift) |
+           psgl->sgl_control;
+       psgl->ptail->next = (uint32_t) NULL;
+
+       return DMA_STATUS_GOOD;
+}
+
+/*
+ * Enable (start) the DMA described by the sgl handle.
+ */
+void
+ppc4xx_enable_dma_sgl(sgl_handle_t handle)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+       ppc_dma_ch_t *p_dma_ch;
+       uint32_t sg_command;
+
+       if (!handle) {
+               printk("ppc4xx_enable_dma_sgl: null handle\n");
+               return;
+       } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+               printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
+                      psgl->dmanr);
+               return;
+       } else if (!psgl->phead) {
+               printk("ppc4xx_enable_dma_sgl: sg list empty\n");
+               return;
+       }
+
+       p_dma_ch = &dma_channels[psgl->dmanr];
+       psgl->ptail->control_count &= ~SG_LINK; /* make this the last dscrptr */
+       sg_command = mfdcr(DCRN_ASGC);
+
+       ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma);
+
+       sg_command |= SSG_ENABLE(psgl->dmanr);
+
+       mtdcr(DCRN_ASGC, sg_command);   /* start transfer */
+}
+
+/*
+ * Halt an active scatter/gather DMA operation.
+ */
+void
+ppc4xx_disable_dma_sgl(sgl_handle_t handle)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+       uint32_t sg_command;
+
+       if (!handle) {
+               printk("ppc4xx_enable_dma_sgl: null handle\n");
+               return;
+       } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+               printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
+                      psgl->dmanr);
+               return;
+       }
+
+       sg_command = mfdcr(DCRN_ASGC);
+       sg_command &= ~SSG_ENABLE(psgl->dmanr);
+       mtdcr(DCRN_ASGC, sg_command);   /* stop transfer */
+}
+
+/*
+ *  Returns number of bytes left to be transferred from the entire sgl list.
+ *  *src_addr and *dst_addr get set to the source/destination address of
+ *  the sgl descriptor where the DMA stopped.
+ *
+ *  An sgl transfer must NOT be active when this function is called.
+ */
+int
+ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
+                          phys_addr_t * dst_addr)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+       ppc_dma_ch_t *p_dma_ch;
+       ppc_sgl_t *pnext, *sgl_addr;
+       uint32_t count_left;
+
+       if (!handle) {
+               printk("ppc4xx_get_dma_sgl_residue: null handle\n");
+               return DMA_STATUS_BAD_HANDLE;
+       } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+               printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
+                      psgl->dmanr);
+               return DMA_STATUS_BAD_CHANNEL;
+       }
+
+       sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8)));
+       count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8));
+
+       if (!sgl_addr) {
+               printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
+               goto error;
+       }
+
+       pnext = psgl->phead;
+       while (pnext &&
+              ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
+               (pnext != sgl_addr))
+           ) {
+               pnext++;
+       }
+
+       if (pnext == sgl_addr) {        /* found the sgl descriptor */
+
+               *src_addr = pnext->src_addr;
+               *dst_addr = pnext->dst_addr;
+
+               /*
+                * Now search the remaining descriptors and add their count.
+                * We already have the remaining count from this descriptor in
+                * count_left.
+                */
+               pnext++;
+
+               while ((pnext != psgl->ptail) &&
+                      ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
+                   ) {
+                       count_left += pnext->control_count & SG_COUNT_MASK;
+               }
+
+               if (pnext != psgl->ptail) {     /* should never happen */
+                       printk
+                           ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
+                            (unsigned int) psgl->ptail, (unsigned int) handle);
+                       goto error;
+               }
+
+               /* success */
+               p_dma_ch = &dma_channels[psgl->dmanr];
+               return (count_left << p_dma_ch->shift); /* count in bytes */
+
+       } else {
+               /* this shouldn't happen */
+               printk
+                   ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
+                    (unsigned int) sgl_addr, (unsigned int) handle);
+
+       }
+
+      error:
+       *src_addr = (phys_addr_t) NULL;
+       *dst_addr = (phys_addr_t) NULL;
+       return 0;
+}
+
+/*
+ * Returns the address(es) of the buffer(s) contained in the head element of
+ * the scatter/gather list.  The element is removed from the scatter/gather
+ * list and the next element becomes the head.
+ *
+ * This function should only be called when the DMA is not active.
+ */
+int
+ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
+                             phys_addr_t * dst_dma_addr)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+
+       if (!handle) {
+               printk("ppc4xx_delete_sgl_element: null handle\n");
+               return DMA_STATUS_BAD_HANDLE;
+       } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+               printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
+                      psgl->dmanr);
+               return DMA_STATUS_BAD_CHANNEL;
+       }
+
+       if (!psgl->phead) {
+               printk("ppc4xx_delete_sgl_element: sgl list empty\n");
+               *src_dma_addr = (phys_addr_t) NULL;
+               *dst_dma_addr = (phys_addr_t) NULL;
+               return DMA_STATUS_SGL_LIST_EMPTY;
+       }
+
+       *src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
+       *dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;
+
+       if (psgl->phead == psgl->ptail) {
+               /* last descriptor on the list */
+               psgl->phead = NULL;
+               psgl->ptail = NULL;
+       } else {
+               psgl->phead++;
+               psgl->phead_dma += sizeof(ppc_sgl_t);
+       }
+
+       return DMA_STATUS_GOOD;
+}
+
+
+/*
+ *   Create a scatter/gather list handle.  This is simply a structure which
+ *   describes a scatter/gather list.
+ *
+ *   A handle is returned in "handle" which the driver should save in order to
+ *   be able to access this list later.  A chunk of memory will be allocated
+ *   to be used by the API for internal management purposes, including managing
+ *   the sg list and allocating memory for the sgl descriptors.  One page should
+ *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use
+ *   a whole page for a single sg list, but most likely there will be only one
+ *   sg list per channel.
+ *
+ *   Interrupt notes:
+ *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
+ *   loads in the control register.  The control word has a "global" interrupt
+ *   enable bit for that channel. Interrupts are further qualified by a few bits
+ *   in the sgl descriptor count register.  In order to setup an sgl, we have to
+ *   know ahead of time whether or not interrupts will be enabled at the completion
+ *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
+ *   be called before calling alloc_dma_handle().  If the interrupt mode will never
+ *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt()
+ *   do not have to be called -- interrupts will be enabled or disabled based
+ *   on how the channel was configured after powerup by the hw_init_dma_channel()
+ *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
+ *   however, only the last descriptor will be setup to interrupt. Thus, an
+ *   interrupt will occur (if interrupts are enabled) only after the complete
+ *   sgl transfer is done.
+ */
+int
+ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
+{
+       sgl_list_info_t *psgl;
+       dma_addr_t dma_addr;
+       ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+       uint32_t sg_command;
+       void *ret;
+
+       if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+               printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
+               return DMA_STATUS_BAD_CHANNEL;
+       }
+
+       if (!phandle) {
+               printk("ppc4xx_alloc_dma_handle: null handle pointer\n");
+               return DMA_STATUS_NULL_POINTER;
+       }
+
+       /* Get a page of memory, which is zeroed out by consistent_alloc() */
+       ret = dma_alloc_coherent(NULL, DMA_PPC4xx_SIZE, &dma_addr, GFP_KERNEL);
+       if (ret != NULL) {
+               memset(ret, 0, DMA_PPC4xx_SIZE);
+               psgl = (sgl_list_info_t *) ret;
+       }
+
+       if (psgl == NULL) {
+               *phandle = (sgl_handle_t) NULL;
+               return DMA_STATUS_OUT_OF_MEMORY;
+       }
+
+       psgl->dma_addr = dma_addr;
+       psgl->dmanr = dmanr;
+
+       /*
+        * Modify and save the control word. These words will be
+        * written to each sgl descriptor.  The DMA engine then
+        * loads this control word into the control register
+        * every time it reads a new descriptor.
+        */
+       psgl->control = p_dma_ch->control;
+       /* Clear all mode bits */
+       psgl->control &= ~(DMA_TM_MASK | DMA_TD);
+       /* Save control word and mode */
+       psgl->control |= (mode | DMA_CE_ENABLE);
+
+       /* In MM mode, we must set ETD/TCE */
+       if (mode == DMA_MODE_MM)
+               psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
+
+       if (p_dma_ch->int_enable) {
+               /* Enable channel interrupt */
+               psgl->control |= DMA_CIE_ENABLE;
+       } else {
+               psgl->control &= ~DMA_CIE_ENABLE;
+       }
+
+       sg_command = mfdcr(DCRN_ASGC);
+       sg_command |= SSG_MASK_ENABLE(dmanr);
+
+       /* Enable SGL control access */
+       mtdcr(DCRN_ASGC, sg_command);
+       psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;
+
+       if (p_dma_ch->int_enable) {
+               if (p_dma_ch->tce_enable)
+                       psgl->sgl_control |= SG_TCI_ENABLE;
+               else
+                       psgl->sgl_control |= SG_ETI_ENABLE;
+       }
+
+       *phandle = (sgl_handle_t) psgl;
+       return DMA_STATUS_GOOD;
+}
+
+/*
+ * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
+ * The list must be empty (contain no elements).
+ */
+void
+ppc4xx_free_dma_handle(sgl_handle_t handle)
+{
+       sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+
+       if (!handle) {
+               printk("ppc4xx_free_dma_handle: got NULL\n");
+               return;
+       } else if (psgl->phead) {
+               printk("ppc4xx_free_dma_handle: list not empty\n");
+               return;
+       } else if (!psgl->dma_addr) {   /* should never happen */
+               printk("ppc4xx_free_dma_handle: no dma address\n");
+               return;
+       }
+
+       dma_free_coherent(NULL, DMA_PPC4xx_SIZE, (void *) psgl, 0);
+}
+
+EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
+EXPORT_SYMBOL(ppc4xx_free_dma_handle);
+EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
+EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);
diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c
new file mode 100644 (file)
index 0000000..6ceea97
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * arch/ppc/syslib/ppc85xx_setup.c
+ *
+ * MPC85XX common board code
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/mpc85xx.h>
+#include <asm/immap_85xx.h>
+#include <asm/mmu.h>
+#include <asm/ocp.h>
+#include <asm/kgdb.h>
+
+#include <syslib/ppc85xx_setup.h>
+
+/* Return the amount of memory */
+unsigned long __init
+mpc85xx_find_end_of_memory(void)
+{
+        bd_t *binfo;
+
+        binfo = (bd_t *) __res;
+
+        return binfo->bi_memsize;
+}
+
+/* The decrementer counts at the system (internal) clock freq divided by 8 */
+void __init
+mpc85xx_calibrate_decr(void)
+{
+        bd_t *binfo = (bd_t *) __res;
+        unsigned int freq, divisor;
+
+        /* get the core frequency */
+        freq = binfo->bi_busfreq;
+
+        /* The timebase is updated every 8 bus clocks, HID0[SEL_TBCLK] = 0 */
+        divisor = 8;
+        tb_ticks_per_jiffy = freq / divisor / HZ;
+        tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+
+       /* Set the time base to zero */
+       mtspr(SPRN_TBWL, 0);
+       mtspr(SPRN_TBWU, 0);
+
+       /* Clear any pending timer interrupts */
+       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+       /* Enable decrementer interrupt */
+       mtspr(SPRN_TCR, TCR_DIE);
+}
+
+#ifdef CONFIG_SERIAL_8250
+void __init
+mpc85xx_early_serial_map(void)
+{
+       struct uart_port serial_req;
+       bd_t *binfo = (bd_t *) __res;
+       phys_addr_t duart_paddr = binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+
+       /* Setup serial port access */
+       memset(&serial_req, 0, sizeof (serial_req));
+       serial_req.uartclk = binfo->bi_busfreq;
+       serial_req.line = 0;
+       serial_req.irq = MPC85xx_IRQ_DUART;
+       serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+       serial_req.iotype = SERIAL_IO_MEM;
+       serial_req.membase = ioremap(duart_paddr, MPC85xx_UART0_SIZE);
+       serial_req.mapbase = duart_paddr;
+       serial_req.regshift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+       gen550_init(0, &serial_req);
+#endif
+
+       if (early_serial_setup(&serial_req) != 0)
+               printk("Early serial init of port 0 failed\n");
+
+       /* Assume early_serial_setup() doesn't modify serial_req */
+       duart_paddr = binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+       serial_req.line = 1;
+       serial_req.mapbase = duart_paddr;
+       serial_req.membase = ioremap(duart_paddr, MPC85xx_UART1_SIZE);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+       gen550_init(1, &serial_req);
+#endif
+
+       if (early_serial_setup(&serial_req) != 0)
+               printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+void
+mpc85xx_restart(char *cmd)
+{
+       local_irq_disable();
+       abort();
+}
+
+void
+mpc85xx_power_off(void)
+{
+       local_irq_disable();
+       for(;;);
+}
+
+void
+mpc85xx_halt(void)
+{
+       local_irq_disable();
+       for(;;);
+}
+
+#ifdef CONFIG_PCI
+static void __init
+mpc85xx_setup_pci1(struct pci_controller *hose)
+{
+       volatile struct ccsr_pci *pci;
+       volatile struct ccsr_guts *guts;
+       unsigned short temps;
+       bd_t *binfo = (bd_t *) __res;
+
+       pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI1_OFFSET,
+                   MPC85xx_PCI1_SIZE);
+
+       guts = ioremap(binfo->bi_immr_base + MPC85xx_GUTS_OFFSET,
+                   MPC85xx_GUTS_SIZE);
+
+       early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps);
+       temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       early_write_config_word(hose, 0, 0, PCI_COMMAND, temps);
+
+#define PORDEVSR_PCI   (0x00800000)    /* PCI Mode */
+       if (guts->pordevsr & PORDEVSR_PCI) {
+               early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
+       } else {
+               /* PCI-X init */
+               temps = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
+                       | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
+               early_write_config_word(hose, 0, 0, PCIX_COMMAND, temps);
+       }
+
+       /* Disable all windows (except powar0 since its ignored) */
+       pci->powar1 = 0;
+       pci->powar2 = 0;
+       pci->powar3 = 0;
+       pci->powar4 = 0;
+       pci->piwar1 = 0;
+       pci->piwar2 = 0;
+       pci->piwar3 = 0;
+
+       /* Setup Phys:PCI 1:1 outbound mem window @ MPC85XX_PCI1_LOWER_MEM */
+       pci->potar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
+       pci->potear1 = 0x00000000;
+       pci->powbar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
+       /* Enable, Mem R/W */
+       pci->powar1 = 0x80044000 |
+          (__ilog2(MPC85XX_PCI1_UPPER_MEM - MPC85XX_PCI1_LOWER_MEM + 1) - 1);
+
+       /* Setup outboud IO windows @ MPC85XX_PCI1_IO_BASE */
+       pci->potar2 = 0x00000000;
+       pci->potear2 = 0x00000000;
+       pci->powbar2 = (MPC85XX_PCI1_IO_BASE >> 12) & 0x000fffff;
+       /* Enable, IO R/W */
+       pci->powar2 = 0x80088000 | (__ilog2(MPC85XX_PCI1_IO_SIZE) - 1);
+
+       /* Setup 2G inbound Memory Window @ 0 */
+       pci->pitar1 = 0x00000000;
+       pci->piwbar1 = 0x00000000;
+       pci->piwar1 = 0xa0f5501e;       /* Enable, Prefetch, Local
+                                          Mem, Snoop R/W, 2G */
+}
+
+
+extern int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin);
+extern int mpc85xx_exclude_device(u_char bus, u_char devfn);
+
+#ifdef CONFIG_85xx_PCI2
+static void __init
+mpc85xx_setup_pci2(struct pci_controller *hose)
+{
+       volatile struct ccsr_pci *pci;
+       unsigned short temps;
+       bd_t *binfo = (bd_t *) __res;
+
+       pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI2_OFFSET,
+                   MPC85xx_PCI2_SIZE);
+
+       early_read_config_word(hose, hose->bus_offset, 0, PCI_COMMAND, &temps);
+       temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       early_write_config_word(hose, hose->bus_offset, 0, PCI_COMMAND, temps);
+       early_write_config_byte(hose, hose->bus_offset, 0, PCI_LATENCY_TIMER, 0x80);
+
+       /* Disable all windows (except powar0 since its ignored) */
+       pci->powar1 = 0;
+       pci->powar2 = 0;
+       pci->powar3 = 0;
+       pci->powar4 = 0;
+       pci->piwar1 = 0;
+       pci->piwar2 = 0;
+       pci->piwar3 = 0;
+
+       /* Setup Phys:PCI 1:1 outbound mem window @ MPC85XX_PCI2_LOWER_MEM */
+       pci->potar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
+       pci->potear1 = 0x00000000;
+       pci->powbar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
+       /* Enable, Mem R/W */
+       pci->powar1 = 0x80044000 |
+          (__ilog2(MPC85XX_PCI1_UPPER_MEM - MPC85XX_PCI1_LOWER_MEM + 1) - 1);
+
+       /* Setup outboud IO windows @ MPC85XX_PCI2_IO_BASE */
+       pci->potar2 = 0x00000000;
+       pci->potear2 = 0x00000000;
+       pci->powbar2 = (MPC85XX_PCI2_IO_BASE >> 12) & 0x000fffff;
+       /* Enable, IO R/W */
+       pci->powar2 = 0x80088000 | (__ilog2(MPC85XX_PCI1_IO_SIZE) - 1);
+
+       /* Setup 2G inbound Memory Window @ 0 */
+       pci->pitar1 = 0x00000000;
+       pci->piwbar1 = 0x00000000;
+       pci->piwar1 = 0xa0f5501e;       /* Enable, Prefetch, Local
+                                          Mem, Snoop R/W, 2G */
+}
+#endif /* CONFIG_85xx_PCI2 */
+
+void __init
+mpc85xx_setup_hose(void)
+{
+       struct pci_controller *hose_a;
+#ifdef CONFIG_85xx_PCI2
+       struct pci_controller *hose_b;
+#endif
+       bd_t *binfo = (bd_t *) __res;
+
+       hose_a = pcibios_alloc_controller();
+
+       if (!hose_a)
+               return;
+
+       ppc_md.pci_swizzle = common_swizzle;
+       ppc_md.pci_map_irq = mpc85xx_map_irq;
+
+       hose_a->first_busno = 0;
+       hose_a->bus_offset = 0;
+       hose_a->last_busno = 0xff;
+
+       setup_indirect_pci(hose_a, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET,
+                          binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET);
+       hose_a->set_cfg_type = 1;
+
+       mpc85xx_setup_pci1(hose_a);
+
+       hose_a->pci_mem_offset = MPC85XX_PCI1_MEM_OFFSET;
+       hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;
+       hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;
+
+       hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;
+       hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;
+       hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE;
+#if CONFIG_85xx_PCI2
+       isa_io_base =
+               (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+                                       MPC85XX_PCI1_IO_SIZE +
+                                       MPC85XX_PCI2_IO_SIZE);
+#else
+       isa_io_base =
+               (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+                                       MPC85XX_PCI1_IO_SIZE);
+#endif
+       hose_a->io_base_virt = (void *) isa_io_base;
+
+       /* setup resources */
+       pci_init_resource(&hose_a->mem_resources[0],
+                       MPC85XX_PCI1_LOWER_MEM,
+                       MPC85XX_PCI1_UPPER_MEM,
+                       IORESOURCE_MEM, "PCI1 host bridge");
+
+       pci_init_resource(&hose_a->io_resource,
+                       MPC85XX_PCI1_LOWER_IO,
+                       MPC85XX_PCI1_UPPER_IO,
+                       IORESOURCE_IO, "PCI1 host bridge");
+
+       ppc_md.pci_exclude_device = mpc85xx_exclude_device;
+
+       hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+
+#if CONFIG_85xx_PCI2
+       hose_b = pcibios_alloc_controller();
+
+       if (!hose_b)
+               return;
+
+       hose_b->bus_offset = hose_a->last_busno + 1;
+       hose_b->first_busno = hose_a->last_busno + 1;
+       hose_b->last_busno = 0xff;
+
+       setup_indirect_pci(hose_b, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET,
+                          binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET);
+       hose_b->set_cfg_type = 1;
+
+       mpc85xx_setup_pci2(hose_b);
+
+       hose_b->pci_mem_offset = MPC85XX_PCI2_MEM_OFFSET;
+       hose_b->mem_space.start = MPC85XX_PCI2_LOWER_MEM;
+       hose_b->mem_space.end = MPC85XX_PCI2_UPPER_MEM;
+
+       hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO;
+       hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO;
+       hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE;
+       hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE;
+
+       /* setup resources */
+       pci_init_resource(&hose_b->mem_resources[0],
+                       MPC85XX_PCI2_LOWER_MEM,
+                       MPC85XX_PCI2_UPPER_MEM,
+                       IORESOURCE_MEM, "PCI2 host bridge");
+
+       pci_init_resource(&hose_b->io_resource,
+                       MPC85XX_PCI2_LOWER_IO,
+                       MPC85XX_PCI2_UPPER_IO,
+                       IORESOURCE_IO, "PCI2 host bridge");
+
+       hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);
+#endif
+       return;
+}
+#endif /* CONFIG_PCI */
+
+
diff --git a/arch/ppc/syslib/ppc85xx_setup.h b/arch/ppc/syslib/ppc85xx_setup.h
new file mode 100644 (file)
index 0000000..6783259
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * arch/ppc/syslib/ppc85xx_setup.h
+ *
+ * MPC85XX common board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor 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.
+ *
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_SETUP_H
+#define __PPC_SYSLIB_PPC85XX_SETUP_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+extern void mpc85xx_early_serial_map(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern void mpc85xx_setup_hose(void) __init;
+
+/* PCI config */
+#define PCI1_CFG_ADDR_OFFSET   (0x8000)
+#define PCI1_CFG_DATA_OFFSET   (0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET   (0x9000)
+#define PCI2_CFG_DATA_OFFSET   (0x9004)
+
+/* Additional register for PCI-X configuration */
+#define PCIX_NEXT_CAP  0x60
+#define PCIX_CAP_ID    0x61
+#define PCIX_COMMAND   0x62
+#define PCIX_STATUS    0x64
+
+/* Serial Config */
+#define MPC85XX_0_SERIAL                (CCSRBAR + 0x4500)
+#define MPC85XX_1_SERIAL                (CCSRBAR + 0x4600)
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  2
+#endif
+
+#ifndef BASE_BAUD
+#define BASE_BAUD 115200
+#endif
+
+#define STD_UART_OP(num)                                       \
+       { 0, BASE_BAUD, num, MPC85xx_IRQ_DUART,                 \
+               (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),        \
+               iomem_base: (u8 *)MPC85XX_##num##_SERIAL,       \
+               io_type: SERIAL_IO_MEM},
+
+/* Offset of CPM register space */
+#define CPM_MAP_ADDR   (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif /* __PPC_SYSLIB_PPC85XX_SETUP_H */
diff --git a/arch/ppc64/kernel/hvcserver.c b/arch/ppc64/kernel/hvcserver.c
new file mode 100644 (file)
index 0000000..fbe445e
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * hvcserver.c
+ * Copyright (C) 2004 Ryan S Arnold, IBM Corporation
+ *
+ * PPC64 virtual I/O console server support.
+ *
+ * This program is free software; 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 <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <asm/hvcall.h>
+#include <asm/hvcserver.h>
+#include <asm/io.h>
+
+#define HVCS_ARCH_VERSION "1.0.0"
+
+MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
+MODULE_DESCRIPTION("IBM hvcs ppc64 API");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HVCS_ARCH_VERSION);
+
+/*
+ * Convert arch specific return codes into relevant errnos.  The hvcs
+ * functions aren't performance sensitive, so this conversion isn't an
+ * issue.
+ */
+int hvcs_convert(long to_convert)
+{
+       switch (to_convert) {
+               case H_Success:
+                       return 0;
+               case H_Parameter:
+                       return -EINVAL;
+               case H_Hardware:
+                       return -EIO;
+               case H_Busy:
+               case H_LongBusyOrder1msec:
+               case H_LongBusyOrder10msec:
+               case H_LongBusyOrder100msec:
+               case H_LongBusyOrder1sec:
+               case H_LongBusyOrder10sec:
+               case H_LongBusyOrder100sec:
+                       return -EBUSY;
+               case H_Function: /* fall through */
+               default:
+                       return -EPERM;
+       }
+}
+
+int hvcs_free_partner_info(struct list_head *head)
+{
+       struct hvcs_partner_info *pi;
+       struct list_head *element;
+
+       if (!head) {
+               return -EINVAL;
+       }
+
+       while (!list_empty(head)) {
+               element = head->next;
+               pi = list_entry(element, struct hvcs_partner_info, node);
+               list_del(element);
+               kfree(pi);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(hvcs_free_partner_info);
+
+/* Helper function for hvcs_get_partner_info */
+int hvcs_next_partner(unsigned int unit_address,
+               unsigned long last_p_partition_ID,
+               unsigned long last_p_unit_address, unsigned long *pi_buff)
+
+{
+       long retval;
+       retval = plpar_hcall_norets(H_VTERM_PARTNER_INFO, unit_address,
+                       last_p_partition_ID,
+                               last_p_unit_address, virt_to_phys(pi_buff));
+       return hvcs_convert(retval);
+}
+
+/*
+ * The unit_address parameter is the unit address of the vty-server vdevice
+ * in whose partner information the caller is interested.  This function
+ * uses a pointer to a list_head instance in which to store the partner info.
+ * This function returns non-zero on success, or if there is no partner info.
+ *
+ * Invocation of this function should always be followed by an invocation of
+ * hvcs_free_partner_info() using a pointer to the SAME list head instance
+ * that was used to store the partner_info list.
+ */
+int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head,
+               unsigned long *pi_buff)
+{
+       /*
+        * This is a page sized buffer to be passed to hvcall per invocation.
+        * NOTE: the first long returned is unit_address.  The second long
+        * returned is the partition ID and starting with pi_buff[2] are
+        * HVCS_CLC_LENGTH characters, which are diff size than the unsigned
+        * long, hence the casting mumbojumbo you see later.
+        */
+       unsigned long   last_p_partition_ID;
+       unsigned long   last_p_unit_address;
+       struct hvcs_partner_info *next_partner_info = NULL;
+       int more = 1;
+       int retval;
+
+       memset(pi_buff, 0x00, PAGE_SIZE);
+       /* invalid parameters */
+       if (!head)
+               return -EINVAL;
+
+       last_p_partition_ID = last_p_unit_address = ~0UL;
+       INIT_LIST_HEAD(head);
+
+       if (!pi_buff)
+               return -ENOMEM;
+
+       do {
+               retval = hvcs_next_partner(unit_address, last_p_partition_ID,
+                               last_p_unit_address, pi_buff);
+               if (retval) {
+                       /*
+                        * Don't indicate that we've failed if we have
+                        * any list elements.
+                        */
+                       if (!list_empty(head))
+                               return 0;
+                       return retval;
+               }
+
+               last_p_partition_ID = pi_buff[0];
+               last_p_unit_address = pi_buff[1];
+
+               /* This indicates that there are no further partners */
+               if (last_p_partition_ID == ~0UL
+                               && last_p_unit_address == ~0UL)
+                       break;
+
+               /* This is a very small struct and will be freed soon in
+                * hvcs_free_partner_info(). */
+               next_partner_info = kmalloc(sizeof(struct hvcs_partner_info),
+                               GFP_ATOMIC);
+
+               if (!next_partner_info) {
+                       printk(KERN_WARNING "HVCONSOLE: kmalloc() failed to"
+                               " allocate partner info struct.\n");
+                       hvcs_free_partner_info(head);
+                       return -ENOMEM;
+               }
+
+               next_partner_info->unit_address
+                       = (unsigned int)last_p_unit_address;
+               next_partner_info->partition_ID
+                       = (unsigned int)last_p_partition_ID;
+
+               /* copy the Null-term char too */
+               strncpy(&next_partner_info->location_code[0],
+                       (char *)&pi_buff[2],
+                       strlen((char *)&pi_buff[2]) + 1);
+
+               list_add_tail(&(next_partner_info->node), head);
+               next_partner_info = NULL;
+
+       } while (more);
+
+       return 0;
+}
+EXPORT_SYMBOL(hvcs_get_partner_info);
+
+/*
+ * If this function is called once and -EINVAL is returned it may
+ * indicate that the partner info needs to be refreshed for the
+ * target unit address at which point the caller must invoke
+ * hvcs_get_partner_info() and then call this function again.  If,
+ * for a second time, -EINVAL is returned then it indicates that
+ * there is probably already a partner connection registered to a
+ * different vty-server@ vdevice.  It is also possible that a second
+ * -EINVAL may indicate that one of the parms is not valid, for
+ * instance if the link was removed between the vty-server@ vdevice
+ * and the vty@ vdevice that you are trying to open.  Don't shoot the
+ * messenger.  Firmware implemented it this way.
+ */
+int hvcs_register_connection( unsigned int unit_address,
+               unsigned int p_partition_ID, unsigned int p_unit_address)
+{
+       long retval;
+       retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address,
+                               p_partition_ID, p_unit_address);
+       return hvcs_convert(retval);
+}
+EXPORT_SYMBOL(hvcs_register_connection);
+
+/*
+ * If -EBUSY is returned continue to call this function
+ * until 0 is returned.
+ */
+int hvcs_free_connection(unsigned int unit_address)
+{
+       long retval;
+       retval = plpar_hcall_norets(H_FREE_VTERM, unit_address);
+       return hvcs_convert(retval);
+}
+EXPORT_SYMBOL(hvcs_free_connection);
diff --git a/arch/ppc64/mm/mmap.c b/arch/ppc64/mm/mmap.c
new file mode 100644 (file)
index 0000000..5ebf686
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  linux/arch/ppc64/mm/mmap.c
+ *
+ *  flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; 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
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+       if (gap < MIN_GAP)
+               gap = MIN_GAP;
+       else if (gap > MAX_GAP)
+               gap = MAX_GAP;
+
+       return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+       /*
+        * Force standard allocation for 64 bit programs.
+        */
+       if (!test_thread_flag(TIF_32BIT))
+               return 1;
+               
+       if (current->personality & ADDR_COMPAT_LAYOUT) 
+               return 1;
+       
+       if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+               return 1;
+               
+       return sysctl_legacy_va_layout;
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+       /*
+        * Fall back to the standard layout if the personality
+        * bit is set, or if the expected stack growth is unlimited:
+        */
+       if (mmap_is_legacy()) {
+               mm->mmap_base = TASK_UNMAPPED_BASE;
+               mm->get_unmapped_area = arch_get_unmapped_area;
+               mm->unmap_area = arch_unmap_area;
+       } else {
+               mm->mmap_base = mmap_base();
+               mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+               mm->get_unmapped_exec_area = arch_get_unmapped_exec_area;
+               mm->unmap_area = arch_unmap_area_topdown;
+       }
+}
diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c
new file mode 100644 (file)
index 0000000..bc61258
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * PowerPC64 SLB support.
+ *
+ * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM
+ * Based on earlier code writteh by:
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *    Copyright (c) 2001 Dave Engebretsen
+ * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ *
+ *      This program is free software; 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.
+ */
+
+#include <linux/config.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/paca.h>
+#include <asm/naca.h>
+#include <asm/cputable.h>
+
+extern void slb_allocate(unsigned long ea);
+
+static inline void create_slbe(unsigned long ea, unsigned long vsid,
+                              unsigned long flags, unsigned long entry)
+{
+       ea = (ea & ESID_MASK) | SLB_ESID_V | entry;
+       vsid = (vsid << SLB_VSID_SHIFT) | flags;
+       asm volatile("slbmte  %0,%1" :
+                    : "r" (vsid), "r" (ea)
+                    : "memory" );
+}
+
+static void slb_add_bolted(void)
+{
+#ifndef CONFIG_PPC_ISERIES
+       WARN_ON(!irqs_disabled());
+
+       /* If you change this make sure you change SLB_NUM_BOLTED
+        * appropriately too */
+
+       /* Slot 1 - first VMALLOC segment
+         *     Since modules end up there it gets hit very heavily.
+         */
+       create_slbe(VMALLOCBASE, get_kernel_vsid(VMALLOCBASE),
+                   SLB_VSID_KERNEL, 1);
+
+       asm volatile("isync":::"memory");
+#endif
+}
+
+/* Flush all user entries from the segment table of the current processor. */
+void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
+{
+       unsigned long offset = get_paca()->slb_cache_ptr;
+       unsigned long esid_data;
+       unsigned long pc = KSTK_EIP(tsk);
+       unsigned long stack = KSTK_ESP(tsk);
+       unsigned long unmapped_base;
+
+       if (offset <= SLB_CACHE_ENTRIES) {
+               int i;
+               asm volatile("isync" : : : "memory");
+               for (i = 0; i < offset; i++) {
+                       esid_data = (unsigned long)get_paca()->slb_cache[i]
+                               << SID_SHIFT;
+                       asm volatile("slbie %0" : : "r" (esid_data));
+               }
+               asm volatile("isync" : : : "memory");
+       } else {
+               asm volatile("isync; slbia; isync" : : : "memory");
+               slb_add_bolted();
+       }
+
+       /* Workaround POWER5 < DD2.1 issue */
+       if (offset == 1 || offset > SLB_CACHE_ENTRIES) {
+               /* flush segment in EEH region, we shouldn't ever
+                * access addresses in this region. */
+               asm volatile("slbie %0" : : "r"(EEHREGIONBASE));
+       }
+
+       get_paca()->slb_cache_ptr = 0;
+       get_paca()->context = mm->context;
+
+       /*
+        * preload some userspace segments into the SLB.
+        */
+       if (test_tsk_thread_flag(tsk, TIF_32BIT))
+               unmapped_base = TASK_UNMAPPED_BASE_USER32;
+       else
+               unmapped_base = TASK_UNMAPPED_BASE_USER64;
+
+       if (pc >= KERNELBASE)
+               return;
+       slb_allocate(pc);
+
+       if (GET_ESID(pc) == GET_ESID(stack))
+               return;
+
+       if (stack >= KERNELBASE)
+               return;
+       slb_allocate(stack);
+
+       if ((GET_ESID(pc) == GET_ESID(unmapped_base))
+           || (GET_ESID(stack) == GET_ESID(unmapped_base)))
+               return;
+
+       if (unmapped_base >= KERNELBASE)
+               return;
+       slb_allocate(unmapped_base);
+}
+
+void slb_initialize(void)
+{
+#ifdef CONFIG_PPC_ISERIES
+       asm volatile("isync; slbia; isync":::"memory");
+#else
+       unsigned long flags = SLB_VSID_KERNEL;
+
+       /* Invalidate the entire SLB (even slot 0) & all the ERATS */
+       if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+               flags |= SLB_VSID_L;
+
+       asm volatile("isync":::"memory");
+       asm volatile("slbmte  %0,%0"::"r" (0) : "memory");
+       asm volatile("isync; slbia; isync":::"memory");
+       create_slbe(KERNELBASE, get_kernel_vsid(KERNELBASE),
+                   flags, 0);
+
+#endif
+       slb_add_bolted();
+       get_paca()->stab_rr = SLB_NUM_BOLTED;
+}
diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S
new file mode 100644 (file)
index 0000000..4b3dfe0
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * arch/ppc64/mm/slb_low.S
+ *
+ * Low-level SLB routines
+ *
+ * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM
+ *
+ * Based on earlier C version:
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *    Copyright (c) 2001 Dave Engebretsen
+ * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ *  This program is free software; 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.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include <asm/cputable.h>
+
+/* void slb_allocate(unsigned long ea);
+ *
+ * Create an SLB entry for the given EA (user or kernel).
+ *     r3 = faulting address, r13 = PACA
+ *     r9, r10, r11 are clobbered by this function
+ * No other registers are examined or changed.
+ */
+_GLOBAL(slb_allocate)
+       /*
+        * First find a slot, round robin. Previously we tried to find
+        * a free slot first but that took too long. Unfortunately we
+        * dont have any LRU information to help us choose a slot.
+        */
+       ld      r10,PACASTABRR(r13)
+3:
+       addi    r10,r10,1
+       /* use a cpu feature mask if we ever change our slb size */
+       cmpldi  r10,SLB_NUM_ENTRIES
+
+       blt+    4f
+       li      r10,SLB_NUM_BOLTED
+
+       /*
+        * Never cast out the segment for our kernel stack. Since we
+        * dont invalidate the ERAT we could have a valid translation
+        * for the kernel stack during the first part of exception exit
+        * which gets invalidated due to a tlbie from another cpu at a
+        * non recoverable point (after setting srr0/1) - Anton
+        */
+4:     slbmfee r11,r10
+       srdi    r11,r11,27
+       /*
+        * Use paca->ksave as the value of the kernel stack pointer,
+        * because this is valid at all times.
+        * The >> 27 (rather than >> 28) is so that the LSB is the
+        * valid bit - this way we check valid and ESID in one compare.
+        * In order to completely close the tiny race in the context
+        * switch (between updating r1 and updating paca->ksave),
+        * we check against both r1 and paca->ksave.
+        */
+       srdi    r9,r1,27
+       ori     r9,r9,1                 /* mangle SP for later compare */
+       cmpd    r11,r9
+       beq-    3b
+       ld      r9,PACAKSAVE(r13)
+       srdi    r9,r9,27
+       ori     r9,r9,1
+       cmpd    r11,r9
+       beq-    3b
+
+       std     r10,PACASTABRR(r13)
+
+       /* r3 = faulting address, r10 = entry */
+
+       srdi    r9,r3,60                /* get region */
+       srdi    r3,r3,28                /* get esid */
+       cmpldi  cr7,r9,0xc              /* cmp KERNELBASE for later use */
+
+       /* r9 = region, r3 = esid, cr7 = <>KERNELBASE */
+
+       rldicr. r11,r3,32,16
+       bne-    8f                      /* invalid ea bits set */
+       addi    r11,r9,-1
+       cmpldi  r11,0xb
+       blt-    8f                      /* invalid region */
+
+       /* r9 = region, r3 = esid, r10 = entry, cr7 = <>KERNELBASE */
+
+       blt     cr7,0f                  /* user or kernel? */
+
+       /* kernel address */
+       li      r11,SLB_VSID_KERNEL
+BEGIN_FTR_SECTION
+       bne     cr7,9f
+       li      r11,(SLB_VSID_KERNEL|SLB_VSID_L)
+END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
+       b       9f
+
+0:     /* user address */
+       li      r11,SLB_VSID_USER
+#ifdef CONFIG_HUGETLB_PAGE
+BEGIN_FTR_SECTION
+       /* check against the hugepage ranges */
+       cmpldi  r3,(TASK_HPAGE_END>>SID_SHIFT)
+       bge     6f                      /* >= TASK_HPAGE_END */
+       cmpldi  r3,(TASK_HPAGE_BASE>>SID_SHIFT)
+       bge     5f                      /* TASK_HPAGE_BASE..TASK_HPAGE_END */
+       cmpldi  r3,16
+       bge     6f                      /* 4GB..TASK_HPAGE_BASE */
+
+       lhz     r9,PACAHTLBSEGS(r13)
+       srd     r9,r9,r3
+       andi.   r9,r9,1
+       beq     6f
+
+5:     /* this is a hugepage user address */
+       li      r11,(SLB_VSID_USER|SLB_VSID_L)
+END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
+#endif /* CONFIG_HUGETLB_PAGE */
+
+6:     ld      r9,PACACONTEXTID(r13)
+
+9:     /* r9 = "context", r3 = esid, r11 = flags, r10 = entry */
+
+       rldimi  r9,r3,15,0              /* r9= VSID ordinal */
+
+7:     rldimi  r10,r3,28,0             /* r10= ESID<<28 | entry */
+       oris    r10,r10,SLB_ESID_V@h    /* r10 |= SLB_ESID_V */
+
+       /* r9 = ordinal, r3 = esid, r11 = flags, r10 = esid_data */
+
+       li      r3,VSID_RANDOMIZER@higher
+       sldi    r3,r3,32
+       oris    r3,r3,VSID_RANDOMIZER@h
+       ori     r3,r3,VSID_RANDOMIZER@l
+
+       mulld   r9,r3,r9                /* r9 = ordinal * VSID_RANDOMIZER */
+       clrldi  r9,r9,28                /* r9 &= VSID_MASK */
+       sldi    r9,r9,SLB_VSID_SHIFT    /* r9 <<= SLB_VSID_SHIFT */
+       or      r9,r9,r11               /* r9 |= flags */
+
+       /* r9 = vsid_data, r10 = esid_data, cr7 = <>KERNELBASE */
+
+       /*
+        * No need for an isync before or after this slbmte. The exception
+        * we enter with and the rfid we exit with are context synchronizing.
+        */
+       slbmte  r9,r10
+
+       bgelr   cr7                     /* we're done for kernel addresses */
+
+       /* Update the slb cache */
+       lhz     r3,PACASLBCACHEPTR(r13) /* offset = paca->slb_cache_ptr */
+       cmpldi  r3,SLB_CACHE_ENTRIES
+       bge     1f
+
+       /* still room in the slb cache */
+       sldi    r11,r3,1                /* r11 = offset * sizeof(u16) */
+       rldicl  r10,r10,36,28           /* get low 16 bits of the ESID */
+       add     r11,r11,r13             /* r11 = (u16 *)paca + offset */
+       sth     r10,PACASLBCACHE(r11)   /* paca->slb_cache[offset] = esid */
+       addi    r3,r3,1                 /* offset++ */
+       b       2f
+1:                                     /* offset >= SLB_CACHE_ENTRIES */
+       li      r3,SLB_CACHE_ENTRIES+1
+2:
+       sth     r3,PACASLBCACHEPTR(r13) /* paca->slb_cache_ptr = offset */
+       blr
+
+8:     /* invalid EA */
+       li      r9,0                    /* 0 VSID ordinal -> BAD_VSID */
+       li      r11,SLB_VSID_USER       /* flags don't much matter */
+       b       7b
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
new file mode 100644 (file)
index 0000000..1039196
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  linux/arch/s390/mm/mmap.c
+ *
+ *  flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; 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
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+       if (gap < MIN_GAP)
+               gap = MIN_GAP;
+       else if (gap > MAX_GAP)
+               gap = MAX_GAP;
+
+       return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+#ifdef CONFIG_ARCH_S390X
+       /*
+        * Force standard allocation for 64 bit programs.
+        */
+       if (!test_thread_flag(TIF_31BIT))
+               return 1;
+#endif
+       return sysctl_legacy_va_layout ||
+           (current->personality & ADDR_COMPAT_LAYOUT) ||
+           current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+       /*
+        * Fall back to the standard layout if the personality
+        * bit is set, or if the expected stack growth is unlimited:
+        */
+       if (mmap_is_legacy()) {
+               mm->mmap_base = TASK_UNMAPPED_BASE;
+               mm->get_unmapped_area = arch_get_unmapped_area;
+               mm->unmap_area = arch_unmap_area;
+       } else {
+               mm->mmap_base = mmap_base();
+               mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+               mm->unmap_area = arch_unmap_area_topdown;
+       }
+}
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
new file mode 100644 (file)
index 0000000..b724a51
--- /dev/null
@@ -0,0 +1,808 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_VOYAGERGX=y
+CONFIG_RTS7751R2D_REV11=y
+CONFIG_SH_PCLK_FREQ=60000000
+# CONFIG_CPU_FREQ is not set
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=8
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+# CONFIG_DMA_PAGE_OPS is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+CONFIG_PCI_DMA=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=m
+# CONFIG_ZNET is not set
+# CONFIG_SEEQ8005 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_RTC_9701JE=y
+
+#
+# Unix 98 PTY support
+#
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_HEARTBEAT=y
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# I2C Algorithms
+#
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_OSSEMUL is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ISA devices
+#
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4232 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_WAVEFRONT is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_SGALAXY is not set
+# CONFIG_SND_SSCAPE is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_YMFPCI=m
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VX222 is not set
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_BT878 is not set
+CONFIG_SOUND_CMPCI=m
+# CONFIG_SOUND_CMPCI_FM is not set
+# CONFIG_SOUND_CMPCI_MIDI is not set
+# CONFIG_SOUND_CMPCI_JOYSTICK is not set
+# CONFIG_SOUND_CMPCI_CM8738 is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_AD1980 is not set
+CONFIG_SOUND_VOYAGERGX=m
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
new file mode 100644 (file)
index 0000000..2d1b415
--- /dev/null
@@ -0,0 +1,659 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System type
+#
+# CONFIG_SH_GENERIC is not set
+# CONFIG_SH_SIMULATOR is not set
+CONFIG_SH_CAYMAN=y
+# CONFIG_SH_ROMRAM is not set
+# CONFIG_SH_HARP is not set
+
+#
+# Processor type and features
+#
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+# CONFIG_DCACHE_DISABLED is not set
+CONFIG_DCACHE_WRITE_BACK=y
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+CONFIG_HEARTBEAT=y
+CONFIG_HDSP253_LED=y
+CONFIG_SH_DMA=y
+CONFIG_PREEMPT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SH_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_E1355 is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+CONFIG_FB_KYRO=y
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+# CONFIG_SH64_PROC_TLB is not set
+# CONFIG_SH64_PROC_ASIDS is not set
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_SH_ALPHANUMERIC is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+CONFIG_FRAME_POINTER=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh64/defconfig b/arch/sh64/defconfig
new file mode 100644 (file)
index 0000000..8cfca49
--- /dev/null
@@ -0,0 +1,667 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH64=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System type
+#
+# CONFIG_SH_GENERIC is not set
+# CONFIG_SH_SIMULATOR is not set
+CONFIG_SH_CAYMAN=y
+# CONFIG_SH_ROMRAM is not set
+# CONFIG_SH_HARP is not set
+CONFIG_CPU_SH5=y
+CONFIG_CPU_SUBTYPE_SH5_101=y
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+CONFIG_LITTLE_ENDIAN=y
+# CONFIG_BIG_ENDIAN is not set
+# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+CONFIG_SH64_PGTABLE_2_LEVEL=y
+# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+
+#
+# Memory options
+#
+CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+CONFIG_MEMORY_START=0x80000000
+CONFIG_MEMORY_SIZE_IN_MB=128
+
+#
+# Cache options
+#
+# CONFIG_DCACHE_DISABLED is not set
+CONFIG_DCACHE_WRITE_BACK=y
+# CONFIG_DCACHE_WRITE_THROUGH is not set
+# CONFIG_ICACHE_DISABLED is not set
+CONFIG_PCIDEVICE_MEMORY_START=C0000000
+CONFIG_DEVICE_MEMORY_START=E0000000
+CONFIG_FLASH_MEMORY_START=0x00000000
+CONFIG_PCI_BLOCK_START=0x40000000
+
+#
+# CPU Subtype specific options
+#
+CONFIG_SH64_ID2815_WORKAROUND=y
+
+#
+# Misc options
+#
+CONFIG_HEARTBEAT=y
+CONFIG_HDSP253_LED=y
+CONFIG_SH_DMA=y
+CONFIG_PREEMPT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SH_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_E1355 is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+CONFIG_FB_KYRO=y
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
+# CONFIG_SH64_PROC_TLB is not set
+# CONFIG_SH64_PROC_ASIDS is not set
+CONFIG_SH64_SR_WATCH=y
+# CONFIG_SH_ALPHANUMERIC is not set
+# CONFIG_SH_NO_BSS_INIT is not set
+CONFIG_FRAME_POINTER=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sparc64/lib/splock.S b/arch/sparc64/lib/splock.S
new file mode 100644 (file)
index 0000000..e466ed2
--- /dev/null
@@ -0,0 +1,35 @@
+/* splock.S: Spinlock primitives too large to inline.
+ *
+ * Copyright (C) 2004 David S. Miller (davem@redhat.com)
+ */
+
+       .text
+       .align  64
+
+       .globl          _raw_spin_lock
+_raw_spin_lock:                /* %o0 = lock_ptr */
+1:     ldstub          [%o0], %g7
+       brnz,pn         %g7, 2f
+        membar         #StoreLoad | #StoreStore
+       retl
+        nop
+2:     ldub            [%o0], %g7
+       brnz,pt         %g7, 2b
+        membar         #LoadLoad
+       ba,a,pt         %xcc, 1b
+
+       .globl  _raw_spin_lock_flags
+_raw_spin_lock_flags:  /* %o0 = lock_ptr, %o1 = irq_flags */
+1:     ldstub          [%o0], %g7
+       brnz,pn         %g7, 2f
+        membar         #StoreLoad | #StoreStore
+       retl
+        nop
+
+2:     rdpr            %pil, %g2               ! Save PIL
+       wrpr            %o1, %pil               ! Set previous PIL
+3:     ldub            [%o0], %g7              ! Spin on lock set
+       brnz,pt         %g7, 3b
+        membar         #LoadLoad
+       ba,pt           %xcc, 1b                ! Retry lock acquire
+        wrpr           %g2, %pil               ! Restore PIL
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
new file mode 100644 (file)
index 0000000..d875d04
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __COW_H__
+#define __COW_H__
+
+#include <asm/types.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x)  bswap_64(x)
+# define htonll(x)  bswap_64(x)
+#else
+#error "__BYTE_ORDER not defined"
+#endif
+
+extern int init_cow_file(int fd, char *cow_file, char *backing_file, 
+                        int sectorsize, int alignment, int *bitmap_offset_out, 
+                        unsigned long *bitmap_len_out, int *data_offset_out);
+
+extern int file_reader(__u64 offset, char *buf, int len, void *arg);
+extern int read_cow_header(int (*reader)(__u64, char *, int, void *), 
+                          void *arg, __u32 *version_out, 
+                          char **backing_file_out, time_t *mtime_out, 
+                          __u64 *size_out, int *sectorsize_out, 
+                          __u32 *align_out, int *bitmap_offset_out);
+
+extern int write_cow_header(char *cow_file, int fd, char *backing_file, 
+                           int sectorsize, int alignment, long long *size);
+
+extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
+                     int bitmap_offset, unsigned long *bitmap_len_out, 
+                     int *data_offset_out);
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/cow_kern.c b/arch/um/drivers/cow_kern.c
new file mode 100644 (file)
index 0000000..ad843f3
--- /dev/null
@@ -0,0 +1,630 @@
+#define COW_MAJOR 60
+#define MAJOR_NR COW_MAJOR
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/stat.h>
+#include <linux/vmalloc.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/devfs_fs.h>
+#include <asm/uaccess.h>
+#include "2_5compat.h"
+#include "cow.h"
+#include "ubd_user.h"
+
+#define COW_SHIFT 4
+
+struct cow {
+       int count;
+       char *cow_path;
+       dev_t cow_dev;
+       struct block_device *cow_bdev;
+       char *backing_path;
+       dev_t backing_dev;
+       struct block_device *backing_bdev;
+       int sectorsize;
+       unsigned long *bitmap;
+       unsigned long bitmap_len;
+       int bitmap_offset;
+       int data_offset;
+       devfs_handle_t devfs;
+       struct semaphore sem;
+       struct semaphore io_sem;
+       atomic_t working;
+       spinlock_t io_lock;
+       struct buffer_head *bh;
+       struct buffer_head *bhtail;
+       void *end_io;
+};
+
+#define DEFAULT_COW { \
+       .count                  = 0, \
+       .cow_path               = NULL, \
+       .cow_dev                = 0, \
+       .backing_path           = NULL, \
+       .backing_dev            = 0, \
+        .bitmap                        = NULL, \
+       .bitmap_len             = 0, \
+       .bitmap_offset          = 0, \
+        .data_offset           = 0, \
+       .devfs                  = NULL, \
+       .working                = ATOMIC_INIT(0), \
+       .io_lock                = SPIN_LOCK_UNLOCKED, \
+}
+
+#define MAX_DEV (8)
+#define MAX_MINOR (MAX_DEV << COW_SHIFT)
+
+struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW };
+
+/* Not modified by this driver */
+static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
+static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
+
+/* Protected by cow_lock */
+static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
+
+static struct hd_struct        cow_part[MAX_MINOR] =
+       { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
+
+/* Protected by io_request_lock */
+static request_queue_t *cow_queue;
+
+static int cow_open(struct inode *inode, struct file *filp);
+static int cow_release(struct inode * inode, struct file * file);
+static int cow_ioctl(struct inode * inode, struct file * file,
+                    unsigned int cmd, unsigned long arg);
+static int cow_revalidate(kdev_t rdev);
+
+static struct block_device_operations cow_blops = {
+       .open           = cow_open,
+       .release        = cow_release,
+       .ioctl          = cow_ioctl,
+       .revalidate     = cow_revalidate,
+};
+
+/* Initialized in an initcall, and unchanged thereafter */
+devfs_handle_t cow_dir_handle;
+
+#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
+{ \
+       .major          = maj, \
+       .major_name     = name, \
+       .minor_shift    = shift, \
+       .max_p          = 1 << shift, \
+       .part           = parts, \
+       .sizes          = bsizes, \
+       .nr_real        = max, \
+       .real_devices   = NULL, \
+       .next           = NULL, \
+       .fops           = blops, \
+       .de_arr         = NULL, \
+       .flags          = 0 \
+}
+
+static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED;
+
+static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part,
+                                                COW_SHIFT, sizes, MAX_DEV, 
+                                                &cow_blops);
+
+static int cow_add(int n)
+{
+       struct cow *dev = &cow_dev[n];
+       char name[sizeof("nnnnnn\0")];
+       int err = -ENODEV;
+
+       if(dev->cow_path == NULL)
+               goto out;
+
+       sprintf(name, "%d", n);
+       dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE,
+                                   MAJOR_NR, n << COW_SHIFT, S_IFBLK | 
+                                   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+                                   &cow_blops, NULL);
+
+       init_MUTEX_LOCKED(&dev->sem);
+       init_MUTEX(&dev->io_sem);
+
+       return(0);
+
+ out:
+       return(err);
+}
+
+/*
+ * Add buffer_head to back of pending list
+ */
+static void cow_add_bh(struct cow *cow, struct buffer_head *bh)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cow->io_lock, flags);
+       if(cow->bhtail != NULL){
+               cow->bhtail->b_reqnext = bh;
+               cow->bhtail = bh;
+       }
+       else {
+               cow->bh = bh;
+               cow->bhtail = bh;
+       }
+       spin_unlock_irqrestore(&cow->io_lock, flags);
+}
+
+/*
+* Grab first pending buffer
+*/
+static struct buffer_head *cow_get_bh(struct cow *cow)
+{
+       struct buffer_head *bh;
+
+       spin_lock_irq(&cow->io_lock);
+       bh = cow->bh;
+       if(bh != NULL){
+               if(bh == cow->bhtail)
+                       cow->bhtail = NULL;
+               cow->bh = bh->b_reqnext;
+               bh->b_reqnext = NULL;
+       }
+       spin_unlock_irq(&cow->io_lock);
+
+       return(bh);
+}
+
+static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, 
+                         struct buffer_head **cow_bh, int ncow_bh)
+{
+       int i;
+
+       if(ncow_bh > 0)
+               ll_rw_block(WRITE, ncow_bh, cow_bh);
+
+       for(i = 0; i < ncow_bh ; i++){
+               wait_on_buffer(cow_bh[i]);
+               brelse(cow_bh[i]);
+       }
+
+       ll_rw_block(WRITE, 1, &bh);
+       brelse(bh);
+}
+
+static struct buffer_head *cow_new_bh(struct cow *dev, int sector)
+{
+       struct buffer_head *bh;
+
+       sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize;
+       bh = getblk(dev->cow_dev, sector, dev->sectorsize);
+       memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])),
+              dev->sectorsize);
+       return(bh);
+}
+
+/* Copied from loop.c, needed to avoid deadlocking in make_request. */
+
+static int cow_thread(void *data)
+{
+       struct cow *dev = data;
+       struct buffer_head *bh;
+
+       daemonize();
+       exit_files(current);
+
+       sprintf(current->comm, "cow%d", dev - cow_dev);
+
+       spin_lock_irq(&current->sigmask_lock);
+       sigfillset(&current->blocked);
+       flush_signals(current);
+       spin_unlock_irq(&current->sigmask_lock);
+
+       atomic_inc(&dev->working);
+
+       current->policy = SCHED_OTHER;
+       current->nice = -20;
+
+       current->flags |= PF_NOIO;
+
+       /*
+        * up sem, we are running
+        */
+       up(&dev->sem);
+
+       for(;;){
+               int start, len, nbh, i, update_bitmap = 0;
+               struct buffer_head *cow_bh[2];
+
+               down_interruptible(&dev->io_sem);
+               /*
+                * could be upped because of tear-down, not because of
+                * pending work
+                */
+               if(!atomic_read(&dev->working))
+                       break;
+
+               bh = cow_get_bh(dev);
+               if(bh == NULL){
+                       printk(KERN_ERR "cow: missing bh\n");
+                       continue;
+               }
+
+               start = bh->b_blocknr * bh->b_size / dev->sectorsize;
+               len = bh->b_size / dev->sectorsize;
+               for(i = 0; i < len ; i++){
+                       if(ubd_test_bit(start + i, 
+                                       (unsigned char *) dev->bitmap))
+                               continue;
+
+                       update_bitmap = 1;
+                       ubd_set_bit(start + i, (unsigned char *) dev->bitmap);
+               }
+
+               cow_bh[0] = NULL;
+               cow_bh[1] = NULL;
+               nbh = 0;
+               if(update_bitmap){
+                       cow_bh[0] = cow_new_bh(dev, start);
+                       nbh++;
+                       if(start / dev->sectorsize != 
+                          (start + len) / dev->sectorsize){
+                               cow_bh[1] = cow_new_bh(dev, start + len);
+                               nbh++;
+                       }
+               }
+               
+               bh->b_dev = dev->cow_dev;
+               bh->b_blocknr += dev->data_offset / dev->sectorsize;
+
+               cow_handle_bh(dev, bh, cow_bh, nbh);
+
+               /*
+                * upped both for pending work and tear-down, lo_pending
+                * will hit zero then
+                */
+               if(atomic_dec_and_test(&dev->working))
+                       break;
+       }
+
+       up(&dev->sem);
+       return(0);
+}
+
+static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh)
+{
+       struct cow *dev;
+       int n, minor;
+
+       minor = MINOR(bh->b_rdev);
+       n = minor >> COW_SHIFT;
+       dev = &cow_dev[n];
+
+       dev->end_io = NULL;
+       if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){
+               bh->b_rdev = dev->cow_dev;
+               bh->b_rsector += dev->data_offset / dev->sectorsize;
+       }
+       else if(rw == WRITE){
+               bh->b_dev = dev->cow_dev;
+               bh->b_blocknr += dev->data_offset / dev->sectorsize;
+
+               cow_add_bh(dev, bh);
+               up(&dev->io_sem);
+               return(0);
+       }
+       else {
+               bh->b_rdev = dev->backing_dev;
+       }
+
+       return(1);
+}
+
+int cow_init(void)
+{
+       int i;
+
+       cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL);
+       if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) {
+               printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR);
+               return -1;
+       }
+       read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
+       blksize_size[MAJOR_NR] = blk_sizes;
+       blk_size[MAJOR_NR] = sizes;
+       INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
+
+       cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
+       blk_init_queue(cow_queue, NULL);
+       INIT_ELV(cow_queue, &cow_queue->elevator);
+       blk_queue_make_request(cow_queue, cow_make_request);
+
+       add_gendisk(&cow_gendisk);
+
+       for(i=0;i<MAX_DEV;i++) 
+               cow_add(i);
+
+       return(0);
+}
+
+__initcall(cow_init);
+
+static int reader(__u64 start, char *buf, int count, void *arg)
+{
+       dev_t dev = *((dev_t *) arg);
+       struct buffer_head *bh;
+       __u64 block;
+       int cur, offset, left, n, blocksize = get_hardsect_size(dev);
+
+       if(blocksize == 0)
+               panic("Zero blocksize");
+
+       block = start / blocksize;
+       offset = start % blocksize;
+       left = count;
+       cur = 0;
+       while(left > 0){
+               n = (left > blocksize) ? blocksize : left;
+
+               bh = bread(dev, block, (n < 512) ? 512 : n);
+               if(bh == NULL)
+                       return(-EIO);
+
+               n -= offset;
+               memcpy(&buf[cur], bh->b_data + offset, n);
+               block++;
+               left -= n;
+               cur += n;
+               offset = 0;
+               brelse(bh);
+       }
+
+       return(count);
+}
+
+static int cow_open(struct inode *inode, struct file *filp)
+{
+       int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
+                        unsigned long);
+       mm_segment_t fs;
+       struct cow *dev;
+       __u64 size;
+       __u32 version, align;
+       time_t mtime;
+       char *backing_file;
+       int n, offset, err = 0;
+
+       n = DEVICE_NR(inode->i_rdev);
+       if(n >= MAX_DEV)
+               return(-ENODEV);
+       dev = &cow_dev[n];
+       offset = n << COW_SHIFT;
+
+       spin_lock(&cow_lock);
+
+       if(dev->count == 0){
+               dev->cow_dev = name_to_kdev_t(dev->cow_path);
+               if(dev->cow_dev == 0){
+                       printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
+                              "failed\n", dev->cow_path);
+                       err = -ENODEV;
+               }
+
+               dev->backing_dev = name_to_kdev_t(dev->backing_path);
+               if(dev->backing_dev == 0){
+                       printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
+                              "failed\n", dev->backing_path);
+                       err = -ENODEV;
+               }
+
+               if(err) 
+                       goto out;
+
+               dev->cow_bdev = bdget(dev->cow_dev);
+               if(dev->cow_bdev == NULL){
+                       printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
+                              dev->cow_path);
+                       err = -ENOMEM;
+               }
+               dev->backing_bdev = bdget(dev->backing_dev);
+               if(dev->backing_bdev == NULL){
+                       printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
+                              dev->backing_path);
+                       err = -ENOMEM;
+               }
+
+               if(err) 
+                       goto out;
+
+               err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, 
+                                BDEV_RAW);
+               if(err){
+                       printk("cow_open - blkdev_get of COW device failed, "
+                              "error = %d\n", err);
+                       goto out;
+               }
+               
+               err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW);
+               if(err){
+                       printk("cow_open - blkdev_get of backing device "
+                              "failed, error = %d\n", err);
+                       goto out;
+               }
+               
+               err = read_cow_header(reader, &dev->cow_dev, &version, 
+                                     &backing_file, &mtime, &size,
+                                     &dev->sectorsize, &align, 
+                                     &dev->bitmap_offset);
+               if(err){
+                       printk(KERN_ERR "cow_open - read_cow_header failed, "
+                              "err = %d\n", err);
+                       goto out;
+               }
+
+               cow_sizes(version, size, dev->sectorsize, align, 
+                         dev->bitmap_offset, &dev->bitmap_len, 
+                         &dev->data_offset);
+               dev->bitmap = (void *) vmalloc(dev->bitmap_len);
+               if(dev->bitmap == NULL){
+                       err = -ENOMEM;
+                       printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
+                       goto out;
+               }
+               flush_tlb_kernel_vm();
+               
+               err = reader(dev->bitmap_offset, (char *) dev->bitmap, 
+                            dev->bitmap_len, &dev->cow_dev);
+               if(err < 0){
+                       printk(KERN_ERR "Failed to read COW bitmap\n");
+                       vfree(dev->bitmap);
+                       goto out;
+               }
+
+               dev_ioctl = dev->backing_bdev->bd_op->ioctl;
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+               err = (*dev_ioctl)(inode, filp, BLKGETSIZE, 
+                                  (unsigned long) &sizes[offset]);
+               set_fs(fs);
+               if(err){
+                       printk(KERN_ERR "cow_open - BLKGETSIZE failed, "
+                              "error = %d\n", err);
+                       goto out;
+               }
+
+               kernel_thread(cow_thread, dev, 
+                             CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+               down(&dev->sem);
+       }
+       dev->count++;
+ out:
+       spin_unlock(&cow_lock);
+       return(err);
+}
+
+static int cow_release(struct inode * inode, struct file * file)
+{
+       struct cow *dev;
+       int n, err;
+
+       n = DEVICE_NR(inode->i_rdev);
+       if(n >= MAX_DEV)
+               return(-ENODEV);
+       dev = &cow_dev[n];
+
+       spin_lock(&cow_lock);
+
+       if(--dev->count > 0)
+               goto out;
+
+       err = blkdev_put(dev->cow_bdev, BDEV_RAW);
+       if(err)
+               printk("cow_release - blkdev_put of cow device failed, "
+                      "error = %d\n", err);
+       bdput(dev->cow_bdev);
+       dev->cow_bdev = 0;
+
+       err = blkdev_put(dev->backing_bdev, BDEV_RAW);
+       if(err)
+               printk("cow_release - blkdev_put of backing device failed, "
+                      "error = %d\n", err);
+       bdput(dev->backing_bdev);
+       dev->backing_bdev = 0;
+
+ out:
+       spin_unlock(&cow_lock);
+       return(0);
+}
+
+static int cow_ioctl(struct inode * inode, struct file * file,
+                    unsigned int cmd, unsigned long arg)
+{
+       struct cow *dev;
+       int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
+                        unsigned long);
+       int n;
+
+       n = DEVICE_NR(inode->i_rdev);
+       if(n >= MAX_DEV)
+               return(-ENODEV);
+       dev = &cow_dev[n];
+
+       dev_ioctl = dev->backing_bdev->bd_op->ioctl;
+       return((*dev_ioctl)(inode, file, cmd, arg));
+}
+
+static int cow_revalidate(kdev_t rdev)
+{
+       printk(KERN_ERR "Need to implement cow_revalidate\n");
+       return(0);
+}
+
+static int parse_unit(char **ptr)
+{
+       char *str = *ptr, *end;
+       int n = -1;
+
+       if(isdigit(*str)) {
+               n = simple_strtoul(str, &end, 0);
+               if(end == str)
+                       return(-1);
+               *ptr = end;
+       }
+       else if (('a' <= *str) && (*str <= 'h')) {
+               n = *str - 'a';
+               str++;
+               *ptr = str;
+       }
+       return(n);
+}
+
+static int cow_setup(char *str)
+{
+       struct cow *dev;
+       char *cow_name, *backing_name;
+       int unit;
+
+       unit = parse_unit(&str);
+       if(unit < 0){
+               printk(KERN_ERR "cow_setup - Couldn't parse unit number\n");
+               return(1);
+       }
+
+       if(*str != '='){
+               printk(KERN_ERR "cow_setup - Missing '=' after unit "
+                      "number\n");
+               return(1);
+       }
+       str++;
+
+       cow_name = str;
+       backing_name = strchr(str, ',');
+       if(backing_name == NULL){
+               printk(KERN_ERR "cow_setup - missing backing device name\n");
+               return(0);
+       }
+       *backing_name = '\0';
+       backing_name++;
+
+       spin_lock(&cow_lock);
+
+       dev = &cow_dev[unit];
+       dev->cow_path = cow_name;
+       dev->backing_path = backing_name;
+       
+       spin_unlock(&cow_lock);
+       return(0);
+}
+
+__setup("cow", cow_setup);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
new file mode 100644 (file)
index 0000000..ce251f0
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __COW_SYS_H__
+#define __COW_SYS_H__
+
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "user.h"
+
+static inline void *cow_malloc(int size)
+{
+       return(um_kmalloc(size));
+}
+
+static inline void cow_free(void *ptr)
+{
+       kfree(ptr);
+}
+
+#define cow_printf printk
+
+static inline char *cow_strdup(char *str)
+{
+       return(uml_strdup(str));
+}
+
+static inline int cow_seek_file(int fd, __u64 offset)
+{
+       return(os_seek_file(fd, offset));
+}
+
+static inline int cow_file_size(char *file, __u64 *size_out)
+{
+       return(os_file_size(file, size_out));
+}
+
+static inline int cow_write_file(int fd, char *buf, int size)
+{
+       return(os_write_file(fd, buf, size));
+}
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
new file mode 100644 (file)
index 0000000..9627e3f
--- /dev/null
@@ -0,0 +1,375 @@
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#include <netinet/in.h>
+
+#include "os.h"
+
+#include "cow.h"
+#include "cow_sys.h"
+
+#define PATH_LEN_V1 256
+
+struct cow_header_v1 {
+       int magic;
+       int version;
+       char backing_file[PATH_LEN_V1];
+       time_t mtime;
+       __u64 size;
+       int sectorsize;
+};
+
+#define PATH_LEN_V2 MAXPATHLEN
+
+struct cow_header_v2 {
+       __u32 magic;
+       __u32 version;
+       char backing_file[PATH_LEN_V2];
+       time_t mtime;
+       __u64 size;
+       int sectorsize;
+};
+
+/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in 
+ * case other systems have different values for MAXPATHLEN
+ */
+#define PATH_LEN_V3 4096
+
+/* Changes from V2 - 
+ *     PATH_LEN_V3 as described above
+ *     Explicitly specify field bit lengths for systems with different
+ *             lengths for the usual C types.  Not sure whether char or
+ *             time_t should be changed, this can be changed later without
+ *             breaking compatibility
+ *     Add alignment field so that different alignments can be used for the
+ *             bitmap and data
+ *     Add cow_format field to allow for the possibility of different ways
+ *             of specifying the COW blocks.  For now, the only value is 0,
+ *             for the traditional COW bitmap.
+ *     Move the backing_file field to the end of the header.  This allows
+ *             for the possibility of expanding it into the padding required
+ *             by the bitmap alignment.
+ *     The bitmap and data portions of the file will be aligned as specified
+ *             by the alignment field.  This is to allow COW files to be
+ *             put on devices with restrictions on access alignments, such as
+ *             /dev/raw, with a 512 byte alignment restriction.  This also
+ *             allows the data to be more aligned more strictly than on
+ *             sector boundaries.  This is needed for ubd-mmap, which needs
+ *             the data to be page aligned.
+ *     Fixed (finally!) the rounding bug
+ */
+
+struct cow_header_v3 {
+       __u32 magic;
+       __u32 version;
+       time_t mtime;
+       __u64 size;
+       __u32 sectorsize;
+       __u32 alignment;
+       __u32 cow_format;
+       char backing_file[PATH_LEN_V3];
+};
+
+/* COW format definitions - for now, we have only the usual COW bitmap */
+#define COW_BITMAP 0
+
+union cow_header {
+       struct cow_header_v1 v1;
+       struct cow_header_v2 v2;
+       struct cow_header_v3 v3;
+};
+
+#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+#define COW_VERSION 3
+
+#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
+#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
+
+void cow_sizes(int version, __u64 size, int sectorsize, int align, 
+              int bitmap_offset, unsigned long *bitmap_len_out, 
+              int *data_offset_out)
+{
+       if(version < 3){
+               *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+
+               *data_offset_out = bitmap_offset + *bitmap_len_out;
+               *data_offset_out = (*data_offset_out + sectorsize - 1) / 
+                       sectorsize;
+               *data_offset_out *= sectorsize;
+       }
+       else {
+               *bitmap_len_out = DIV_ROUND(size, sectorsize);
+               *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
+
+               *data_offset_out = bitmap_offset + *bitmap_len_out;
+               *data_offset_out = ROUND_UP(*data_offset_out, align);
+       }
+}
+
+static int absolutize(char *to, int size, char *from)
+{
+       char save_cwd[256], *slash;
+       int remaining;
+
+       if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+               cow_printf("absolutize : unable to get cwd - errno = %d\n", 
+                          errno);
+               return(-1);
+       }
+       slash = strrchr(from, '/');
+       if(slash != NULL){
+               *slash = '\0';
+               if(chdir(from)){
+                       *slash = '/';
+                       cow_printf("absolutize : Can't cd to '%s' - " 
+                                  "errno = %d\n", from, errno);
+                       return(-1);
+               }
+               *slash = '/';
+               if(getcwd(to, size) == NULL){
+                       cow_printf("absolutize : unable to get cwd of '%s' - "
+                              "errno = %d\n", from, errno);
+                       return(-1);
+               }
+               remaining = size - strlen(to);
+               if(strlen(slash) + 1 > remaining){
+                       cow_printf("absolutize : unable to fit '%s' into %d "
+                              "chars\n", from, size);
+                       return(-1);
+               }
+               strcat(to, slash);
+       }
+       else {
+               if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+                       cow_printf("absolutize : unable to fit '%s' into %d "
+                              "chars\n", from, size);
+                       return(-1);
+               }
+               strcpy(to, save_cwd);
+               strcat(to, "/");
+               strcat(to, from);
+       }
+       chdir(save_cwd);
+       return(0);
+}
+
+int write_cow_header(char *cow_file, int fd, char *backing_file, 
+                    int sectorsize, int alignment, long long *size)
+{
+       struct cow_header_v3 *header;
+       unsigned long modtime;
+       int err;
+
+       err = cow_seek_file(fd, 0);
+       if(err < 0){
+               cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
+               goto out;
+       }
+
+       err = -ENOMEM;
+       header = cow_malloc(sizeof(*header));
+       if(header == NULL){
+               cow_printf("Failed to allocate COW V3 header\n");
+               goto out;
+       }
+       header->magic = htonl(COW_MAGIC);
+       header->version = htonl(COW_VERSION);
+
+       err = -EINVAL;
+       if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+               cow_printf("Backing file name \"%s\" is too long - names are "
+                          "limited to %d characters\n", backing_file, 
+                          sizeof(header->backing_file) - 1);
+               goto out_free;
+       }
+
+       if(absolutize(header->backing_file, sizeof(header->backing_file), 
+                     backing_file))
+               goto out_free;
+
+       err = os_file_modtime(header->backing_file, &modtime);
+       if(err < 0){
+               cow_printf("Backing file '%s' mtime request failed, "
+                          "err = %d\n", header->backing_file, -err);
+               goto out_free;
+       }
+
+       err = cow_file_size(header->backing_file, size);
+       if(err < 0){
+               cow_printf("Couldn't get size of backing file '%s', "
+                          "err = %d\n", header->backing_file, -err);
+               goto out_free;
+       }
+
+       header->mtime = htonl(modtime);
+       header->size = htonll(*size);
+       header->sectorsize = htonl(sectorsize);
+       header->alignment = htonl(alignment);
+       header->cow_format = COW_BITMAP;
+
+       err = os_write_file(fd, header, sizeof(*header));
+       if(err != sizeof(*header)){
+               cow_printf("Write of header to new COW file '%s' failed, "
+                          "err = %d\n", cow_file, -err);
+               goto out_free;
+       }
+       err = 0;
+ out_free:
+       cow_free(header);
+ out:
+       return(err);
+}
+
+int file_reader(__u64 offset, char *buf, int len, void *arg)
+{
+       int fd = *((int *) arg);
+
+       return(pread(fd, buf, len, offset));
+}
+
+/* XXX Need to sanity-check the values read from the header */
+
+int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 
+                   __u32 *version_out, char **backing_file_out, 
+                   time_t *mtime_out, __u64 *size_out, 
+                   int *sectorsize_out, __u32 *align_out, 
+                   int *bitmap_offset_out)
+{
+       union cow_header *header;
+       char *file;
+       int err, n;
+       unsigned long version, magic;
+
+       header = cow_malloc(sizeof(*header));
+       if(header == NULL){
+               cow_printf("read_cow_header - Failed to allocate header\n");
+               return(-ENOMEM);
+       }
+       err = -EINVAL;
+       n = (*reader)(0, (char *) header, sizeof(*header), arg);
+       if(n < offsetof(typeof(header->v1), backing_file)){
+               cow_printf("read_cow_header - short header\n");
+               goto out;
+       }
+
+       magic = header->v1.magic;
+       if(magic == COW_MAGIC) {
+               version = header->v1.version;
+       }
+       else if(magic == ntohl(COW_MAGIC)){
+               version = ntohl(header->v1.version);
+       }
+       /* No error printed because the non-COW case comes through here */
+       else goto out;
+
+       *version_out = version;
+
+       if(version == 1){
+               if(n < sizeof(header->v1)){
+                       cow_printf("read_cow_header - failed to read V1 "
+                                  "header\n");
+                       goto out;
+               }
+               *mtime_out = header->v1.mtime;
+               *size_out = header->v1.size;
+               *sectorsize_out = header->v1.sectorsize;
+               *bitmap_offset_out = sizeof(header->v1);
+               *align_out = *sectorsize_out;
+               file = header->v1.backing_file;
+       }
+       else if(version == 2){
+               if(n < sizeof(header->v2)){
+                       cow_printf("read_cow_header - failed to read V2 "
+                                  "header\n");
+                       goto out;
+               }
+               *mtime_out = ntohl(header->v2.mtime);
+               *size_out = ntohll(header->v2.size);
+               *sectorsize_out = ntohl(header->v2.sectorsize);
+               *bitmap_offset_out = sizeof(header->v2);
+               *align_out = *sectorsize_out;
+               file = header->v2.backing_file;
+       }
+       else if(version == 3){
+               if(n < sizeof(header->v3)){
+                       cow_printf("read_cow_header - failed to read V2 "
+                                  "header\n");
+                       goto out;
+               }
+               *mtime_out = ntohl(header->v3.mtime);
+               *size_out = ntohll(header->v3.size);
+               *sectorsize_out = ntohl(header->v3.sectorsize);
+               *align_out = ntohl(header->v3.alignment);
+               *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
+               file = header->v3.backing_file;
+       }
+       else {
+               cow_printf("read_cow_header - invalid COW version\n");
+               goto out;               
+       }
+       err = -ENOMEM;
+       *backing_file_out = cow_strdup(file);
+       if(*backing_file_out == NULL){
+               cow_printf("read_cow_header - failed to allocate backing "
+                          "file\n");
+               goto out;
+       }
+       err = 0;
+ out:
+       cow_free(header);
+       return(err);
+}
+
+int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
+                 int alignment, int *bitmap_offset_out, 
+                 unsigned long *bitmap_len_out, int *data_offset_out)
+{
+       __u64 size, offset;
+       char zero = 0;
+       int err;
+
+       err = write_cow_header(cow_file, fd, backing_file, sectorsize, 
+                              alignment, &size);
+       if(err) 
+               goto out;
+       
+       *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
+       cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
+                 bitmap_len_out, data_offset_out);
+
+       offset = *data_offset_out + size - sizeof(zero);
+       err = cow_seek_file(fd, offset);
+       if(err < 0){
+               cow_printf("cow bitmap lseek failed : err = %d\n", -err);
+               goto out;
+       }
+
+       /* does not really matter how much we write it is just to set EOF 
+        * this also sets the entire COW bitmap
+        * to zero without having to allocate it 
+        */
+       err = cow_write_file(fd, &zero, sizeof(zero));
+       if(err != sizeof(zero)){
+               cow_printf("Write of bitmap to new COW file '%s' failed, "
+                          "err = %d\n", cow_file, -err);
+               err = -EINVAL;
+               goto out;
+       }
+
+       return(0);
+
+ out:
+       return(err);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/aio.h b/arch/um/include/aio.h
new file mode 100644 (file)
index 0000000..6096f4f
--- /dev/null
@@ -0,0 +1,36 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef AIO_H__
+#define AIO_H__
+
+enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP };
+
+struct aio_thread_reply {
+       void *data;
+       int err;
+};
+
+struct aio_context {
+       int reply_fd;
+};
+
+#define INIT_AIO_CONTEXT { .reply_fd   = -1 }
+
+extern int submit_aio(enum aio_type type, int fd, char *buf, int len, 
+                     unsigned long long offset, int reply_fd, void *data);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/filehandle.h b/arch/um/include/filehandle.h
new file mode 100644 (file)
index 0000000..adc5108
--- /dev/null
@@ -0,0 +1,51 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FILEHANDLE_H__
+#define __FILEHANDLE_H__
+
+#include "linux/list.h"
+#include "linux/fs.h"
+#include "os.h"
+
+struct file_handle {
+       struct list_head list;
+       int fd;
+       char *(*get_name)(struct inode *);
+       struct inode *inode;
+       struct openflags flags;
+};
+
+extern struct file_handle bad_filehandle;
+
+extern int open_file(char *name, struct openflags flags, int mode);
+extern void *open_dir(char *file);
+extern int open_filehandle(char *name, struct openflags flags, int mode, 
+                          struct file_handle *fh);
+extern int read_file(struct file_handle *fh, unsigned long long offset, 
+                    char *buf, int len);
+extern int write_file(struct file_handle *fh, unsigned long long offset, 
+                     const char *buf, int len);
+extern int truncate_file(struct file_handle *fh, unsigned long long size);
+extern int close_file(struct file_handle *fh);
+extern void not_reclaimable(struct file_handle *fh);
+extern void is_reclaimable(struct file_handle *fh, 
+                          char *(name_proc)(struct inode *),
+                          struct inode *inode);
+extern int filehandle_fd(struct file_handle *fh);
+extern int make_pipe(struct file_handle *fhs);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
new file mode 100644 (file)
index 0000000..4bcb829
--- /dev/null
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __IRQ_KERN_H__
+#define __IRQ_KERN_H__
+
+#include "linux/interrupt.h"
+
+extern int um_request_irq(unsigned int irq, int fd, int type,
+                         irqreturn_t (*handler)(int, void *, 
+                                                struct pt_regs *),
+                         unsigned long irqflags,  const char * devname,
+                         void *dev_id);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h
new file mode 100644 (file)
index 0000000..699d46d
--- /dev/null
@@ -0,0 +1,30 @@
+/* 
+ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MEM_KERN_H__
+#define __MEM_KERN_H__
+
+#include "linux/list.h"
+#include "linux/types.h"
+
+struct remapper {
+       struct list_head list;
+       int (*proc)(int, unsigned long, int, __u64, int);
+};
+
+extern void register_remapper(struct remapper *info);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/skas_ptregs.h b/arch/um/include/skas_ptregs.h
new file mode 100644 (file)
index 0000000..afd5fc3
--- /dev/null
@@ -0,0 +1,26 @@
+/* Automatically generated by arch/um/kernel/skas/util/mk_ptregs */
+
+#ifndef __SKAS_PT_REGS_
+#define __SKAS_PT_REGS_
+
+#define HOST_FRAME_SIZE 17
+#define HOST_FP_SIZE 27
+#define HOST_XFP_SIZE 128
+#define HOST_IP 12
+#define HOST_SP 15
+#define HOST_EFLAGS 14
+#define HOST_EAX 6
+#define HOST_EBX 0
+#define HOST_ECX 1
+#define HOST_EDX 2
+#define HOST_ESI 3
+#define HOST_EDI 4
+#define HOST_EBP 5
+#define HOST_CS 13
+#define HOST_SS 16
+#define HOST_DS 7
+#define HOST_FS 9
+#define HOST_ES 8
+#define HOST_GS 10
+
+#endif
diff --git a/arch/um/kernel/filehandle.c b/arch/um/kernel/filehandle.c
new file mode 100644 (file)
index 0000000..a44dccf
--- /dev/null
@@ -0,0 +1,250 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/slab.h"
+#include "linux/list.h"
+#include "linux/spinlock.h"
+#include "linux/fs.h"
+#include "linux/errno.h"
+#include "filehandle.h"
+#include "os.h"
+#include "kern_util.h"
+
+static spinlock_t open_files_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head open_files = LIST_HEAD_INIT(open_files);
+
+#define NUM_RECLAIM 128
+
+static void reclaim_fds(void)
+{
+       struct file_handle *victim;
+       int closed = NUM_RECLAIM;
+
+       spin_lock(&open_files_lock);
+       while(!list_empty(&open_files) && closed--){
+               victim = list_entry(open_files.prev, struct file_handle, list);
+               os_close_file(victim->fd);
+               victim->fd = -1;
+               list_del_init(&victim->list);
+       }
+       spin_unlock(&open_files_lock);
+}
+
+int open_file(char *name, struct openflags flags, int mode)
+{
+       int fd;
+
+       fd = os_open_file(name, flags, mode);
+       if(fd != -EMFILE)
+               return(fd);
+
+       reclaim_fds();
+       fd = os_open_file(name, flags, mode);
+
+       return(fd);
+}
+
+void *open_dir(char *file)
+{
+       void *dir;
+       int err;
+
+       dir = os_open_dir(file, &err);
+       if(dir != NULL)
+               return(dir);
+       if(err != -EMFILE)
+               return(ERR_PTR(err));
+
+       reclaim_fds();
+
+       dir = os_open_dir(file, &err);
+       if(dir == NULL)
+               dir = ERR_PTR(err);
+
+       return(dir);
+}
+
+void not_reclaimable(struct file_handle *fh)
+{
+       char *name;
+
+       if(fh->get_name == NULL)
+               return;
+
+       if(list_empty(&fh->list)){
+               name = (*fh->get_name)(fh->inode);
+               if(name != NULL){
+                       fh->fd = open_file(name, fh->flags, 0);
+                       kfree(name);
+               }
+               else printk("File descriptor %d has no name\n", fh->fd);
+       }
+       else {
+               spin_lock(&open_files_lock);
+               list_del_init(&fh->list);
+               spin_unlock(&open_files_lock);
+       }
+}
+
+void is_reclaimable(struct file_handle *fh, char *(name_proc)(struct inode *),
+                   struct inode *inode)
+{
+       fh->get_name = name_proc;
+       fh->inode = inode;
+
+       spin_lock(&open_files_lock);
+       list_add(&fh->list, &open_files);
+       spin_unlock(&open_files_lock);
+}
+
+static int active_handle(struct file_handle *fh)
+{
+       int fd;
+       char *name;
+
+       if(!list_empty(&fh->list))
+               list_move(&fh->list, &open_files);
+
+       if(fh->fd != -1)
+               return(0);
+
+       if(fh->inode == NULL)
+               return(-ENOENT);
+
+       name = (*fh->get_name)(fh->inode);
+       if(name == NULL)
+               return(-ENOMEM);
+
+       fd = open_file(name, fh->flags, 0);
+       kfree(name);
+       if(fd < 0)
+               return(fd);
+
+       fh->fd = fd;
+       is_reclaimable(fh, fh->get_name, fh->inode);
+
+       return(0);
+}
+
+int filehandle_fd(struct file_handle *fh)
+{
+       int err;
+
+       err = active_handle(fh);
+       if(err)
+               return(err);
+
+       return(fh->fd);
+}
+
+static void init_fh(struct file_handle *fh, int fd, struct openflags flags)
+{
+       flags.c = 0;
+       *fh = ((struct file_handle) { .list     = LIST_HEAD_INIT(fh->list),
+                                     .fd       = fd,
+                                     .get_name = NULL,
+                                     .inode    = NULL,
+                                     .flags    = flags });
+}
+
+int open_filehandle(char *name, struct openflags flags, int mode, 
+                   struct file_handle *fh)
+{
+       int fd;
+
+       fd = open_file(name, flags, mode);
+       if(fd < 0)
+               return(fd);
+
+       init_fh(fh, fd, flags);
+       return(0);
+}
+
+int close_file(struct file_handle *fh)
+{
+       spin_lock(&open_files_lock);
+       list_del(&fh->list);
+       spin_unlock(&open_files_lock);
+
+       os_close_file(fh->fd);
+
+       fh->fd = -1;
+       return(0);
+}
+
+int read_file(struct file_handle *fh, unsigned long long offset, char *buf,
+             int len)
+{
+       int err;
+
+       err = active_handle(fh);
+       if(err)
+               return(err);
+
+       err = os_seek_file(fh->fd, offset);
+       if(err)
+               return(err);
+
+       return(os_read_file(fh->fd, buf, len));
+}
+
+int write_file(struct file_handle *fh, unsigned long long offset, 
+              const char *buf, int len)
+{
+       int err;
+
+       err = active_handle(fh);
+       if(err)
+               return(err);
+
+       if(offset != -1)
+               err = os_seek_file(fh->fd, offset);
+       if(err)
+               return(err);
+
+       return(os_write_file(fh->fd, buf, len));
+}
+
+int truncate_file(struct file_handle *fh, unsigned long long size)
+{
+       int err;
+
+       err = active_handle(fh);
+       if(err)
+               return(err);
+
+       return(os_truncate_fd(fh->fd, size));
+}
+
+int make_pipe(struct file_handle *fhs)
+{
+       int fds[2], err;
+
+       err = os_pipe(fds, 1, 1);
+       if(err && (err != -EMFILE))
+               return(err);
+
+       if(err){
+               reclaim_fds();
+               err = os_pipe(fds, 1, 1);
+       }
+       if(err)
+               return(err);
+
+       init_fh(&fhs[0], fds[0], OPENFLAGS());
+       init_fh(&fhs[1], fds[1], OPENFLAGS());
+       return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
new file mode 100644 (file)
index 0000000..258e158
--- /dev/null
@@ -0,0 +1,483 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/ghash.h"
+#include "linux/slab.h"
+#include "linux/vmalloc.h"
+#include "linux/bootmem.h"
+#include "asm/types.h"
+#include "asm/pgtable.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "mode_kern.h"
+#include "mem.h"
+#include "mem_user.h"
+#include "os.h"
+#include "kern.h"
+#include "init.h"
+
+#if 0
+static pgd_t physmem_pgd[PTRS_PER_PGD];
+
+static struct phys_desc *lookup_mapping(void *addr)
+{
+       pgd = &physmem_pgd[pgd_index(addr)];
+       if(pgd_none(pgd))
+               return(NULL);
+
+       pmd = pmd_offset(pgd, addr);
+       if(pmd_none(pmd))
+               return(NULL);
+
+       pte = pte_offset_kernel(pmd, addr);
+       return((struct phys_desc *) pte_val(pte));
+}
+
+static struct add_mapping(void *addr, struct phys_desc *new)
+{
+}
+#endif
+
+#define PHYS_HASHSIZE (8192)
+
+struct phys_desc;
+
+DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
+
+struct phys_desc {
+       struct virtmem_ptrs virt_ptrs;
+       int fd;
+       __u64 offset;
+       void *virt;
+       unsigned long phys;
+       struct list_head list;
+};
+
+struct virtmem_table virtmem_hash;
+
+static int virt_cmp(void *virt1, void *virt2)
+{
+       return(virt1 != virt2);
+}
+
+static int virt_hash(void *virt)
+{
+       unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
+       return(addr % PHYS_HASHSIZE);
+}
+
+DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, 
+        virt_hash);
+
+LIST_HEAD(descriptor_mappings);
+
+struct desc_mapping {
+       int fd;
+       struct list_head list;
+       struct list_head pages;
+};
+
+static struct desc_mapping *find_mapping(int fd)
+{
+       struct desc_mapping *desc;
+       struct list_head *ele;
+
+       list_for_each(ele, &descriptor_mappings){
+               desc = list_entry(ele, struct desc_mapping, list);
+               if(desc->fd == fd)
+                       return(desc);
+       }
+
+       return(NULL);
+}
+
+static struct desc_mapping *descriptor_mapping(int fd)
+{
+       struct desc_mapping *desc;
+
+       desc = find_mapping(fd);
+       if(desc != NULL)
+               return(desc);
+
+       desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+       if(desc == NULL)
+               return(NULL);
+
+       *desc = ((struct desc_mapping) 
+               { .fd =         fd,
+                 .list =       LIST_HEAD_INIT(desc->list),
+                 .pages =      LIST_HEAD_INIT(desc->pages) });
+       list_add(&desc->list, &descriptor_mappings);
+
+       return(desc);
+}
+
+int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
+{
+       struct desc_mapping *fd_maps;
+       struct phys_desc *desc;
+       unsigned long phys;
+       int err;
+
+       phys = __pa(virt);
+       desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+       if(desc != NULL){
+               if((virt != desc->virt) || (fd != desc->fd) || 
+                  (offset != desc->offset))
+                       panic("Address 0x%p is already substituted\n", virt);
+               return(0);
+       }
+
+       fd_maps = descriptor_mapping(fd);
+       if(fd_maps == NULL)
+               return(-ENOMEM);
+
+       err = -ENOMEM;
+       desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+       if(desc == NULL)
+               goto out;
+
+       *desc = ((struct phys_desc) 
+               { .virt_ptrs =  { NULL, NULL },
+                 .fd =         fd,
+                 .offset =             offset,
+                 .virt =               virt,
+                 .phys =               __pa(virt),
+                 .list =               LIST_HEAD_INIT(desc->list) });
+       insert_virtmem_hash(&virtmem_hash, desc);
+
+       list_add(&desc->list, &fd_maps->pages);
+
+       virt = (void *) ((unsigned long) virt & PAGE_MASK);
+       err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
+       if(!err)
+               goto out;
+
+       remove_virtmem_hash(&virtmem_hash, desc);
+       kfree(desc);
+ out:
+       return(err);
+}
+
+static int physmem_fd = -1;
+
+static void remove_mapping(struct phys_desc *desc)
+{
+       void *virt = desc->virt;
+       int err;
+
+       remove_virtmem_hash(&virtmem_hash, desc);
+       list_del(&desc->list);
+       kfree(desc);
+
+       err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
+       if(err)
+               panic("Failed to unmap block device page from physical memory, "
+                     "errno = %d", -err);
+}
+
+int physmem_remove_mapping(void *virt)
+{
+       struct phys_desc *desc;
+
+       virt = (void *) ((unsigned long) virt & PAGE_MASK);
+       desc = find_virtmem_hash(&virtmem_hash, virt);
+       if(desc == NULL)
+               return(0);
+
+       remove_mapping(desc);
+       return(1);
+}
+
+void physmem_forget_descriptor(int fd)
+{
+       struct desc_mapping *desc;
+       struct phys_desc *page;
+       struct list_head *ele, *next;
+       __u64 offset;
+       void *addr;
+       int err;
+
+       desc = find_mapping(fd);
+       if(desc == NULL)
+               return;
+
+       if(!list_empty(&desc->pages))
+               printk("Still have mapped pages on fd %d\n", fd);
+
+       list_for_each_safe(ele, next, &desc->pages){
+               page = list_entry(ele, struct phys_desc, list);
+               offset = page->offset;
+               addr = page->virt;
+               remove_mapping(page);
+               err = os_seek_file(fd, offset);
+               if(err)
+                       panic("physmem_forget_descriptor - failed to seek "
+                             "to %lld in fd %d, error = %d\n",
+                             offset, fd, -err);
+               err = os_read_file(fd, addr, PAGE_SIZE);
+               if(err < 0)
+                       panic("physmem_forget_descriptor - failed to read "
+                             "from fd %d to 0x%p, error = %d\n",
+                             fd, addr, -err);
+       }
+
+       list_del(&desc->list);
+       kfree(desc);
+}
+
+void arch_free_page(struct page *page, int order)
+{
+       void *virt;
+       int i;
+
+       for(i = 0; i < (1 << order); i++){
+               virt = __va(page_to_phys(page + i));
+               physmem_remove_mapping(virt);
+       }
+}
+
+int is_remapped(const void *virt, int fd, __u64 offset)
+{
+       struct phys_desc *desc;
+
+       desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+       if(desc == NULL)
+               return(0);
+       if(offset != desc->offset)
+               printk("offset mismatch\n");
+       return(find_virtmem_hash(&virtmem_hash, (void *) virt) != NULL);
+}
+
+/* Changed during early boot */
+unsigned long high_physmem;
+
+extern unsigned long physmem_size;
+
+void *to_virt(unsigned long phys)
+{
+       return((void *) uml_physmem + phys);
+}
+
+unsigned long to_phys(void *virt)
+{
+       return(((unsigned long) virt) - uml_physmem);
+}
+
+int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
+{
+       struct page *p, *map;
+       unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
+       unsigned long iomem_len, iomem_pages, total_len, total_pages;
+       int i;
+
+       phys_pages = physmem >> PAGE_SHIFT;
+       phys_len = phys_pages * sizeof(struct page);
+
+       iomem_pages = iomem >> PAGE_SHIFT;
+       iomem_len = iomem_pages * sizeof(struct page);
+
+       highmem_pages = highmem >> PAGE_SHIFT;
+       highmem_len = highmem_pages * sizeof(struct page);
+
+       total_pages = phys_pages + iomem_pages + highmem_pages;
+       total_len = phys_len + iomem_pages + highmem_len;
+
+       if(kmalloc_ok){
+               map = kmalloc(total_len, GFP_KERNEL);
+               if(map == NULL) 
+                       map = vmalloc(total_len);
+       }
+       else map = alloc_bootmem_low_pages(total_len);
+
+       if(map == NULL)
+               return(-ENOMEM);
+
+       for(i = 0; i < total_pages; i++){
+               p = &map[i];
+               set_page_count(p, 0);
+               SetPageReserved(p);
+               INIT_LIST_HEAD(&p->lru);
+       }
+
+       mem_map = map;
+       max_mapnr = total_pages;
+       return(0);
+}
+
+struct page *phys_to_page(const unsigned long phys)
+{
+       return(&mem_map[phys >> PAGE_SHIFT]);
+}
+
+struct page *__virt_to_page(const unsigned long virt)
+{
+       return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
+}
+
+unsigned long page_to_phys(struct page *page)
+{
+       return((page - mem_map) << PAGE_SHIFT);
+}
+
+pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+       pte_t pte;
+
+       pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot);
+       if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte));
+       return(pte);
+}
+
+/* Changed during early boot */
+static unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+       if(kmem_top == 0) 
+               kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
+       return(kmem_top);
+}
+
+void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
+               int r, int w, int x)
+{
+       __u64 offset;
+       int fd, err;
+
+       fd = phys_mapping(phys, &offset);
+       err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
+       if(err)
+               panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
+                     "err = %d\n", virt, fd, offset, len, r, w, x, err);
+}
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+
+void setup_physmem(unsigned long start, unsigned long reserve_end,
+                  unsigned long len, unsigned long highmem)
+{
+       unsigned long reserve = reserve_end - start;
+       int pfn = PFN_UP(__pa(reserve_end));
+       int delta = (len - reserve) >> PAGE_SHIFT;
+       int err, offset, bootmap_size;
+
+       physmem_fd = create_mem_file(len + highmem);
+
+       offset = uml_reserved - uml_physmem;
+       err = os_map_memory((void *) uml_reserved, physmem_fd, offset, 
+                           len - offset, 1, 1, 0);
+       if(err < 0){
+               os_print_error(err, "Mapping memory");
+               exit(1);
+       }
+
+       bootmap_size = init_bootmem(pfn, pfn + delta);
+       free_bootmem(__pa(reserve_end) + bootmap_size,
+                    len - bootmap_size - reserve);
+}
+
+int phys_mapping(unsigned long phys, __u64 *offset_out)
+{
+       struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, 
+                                                  __va(phys & PAGE_MASK));
+       int fd = -1;
+
+       if(desc != NULL){
+               fd = desc->fd;
+               *offset_out = desc->offset;
+       }
+       else if(phys < physmem_size){
+               fd = physmem_fd;
+               *offset_out = phys;
+       }
+       else if(phys < __pa(end_iomem)){
+               struct iomem_region *region = iomem_regions;
+       
+               while(region != NULL){
+                       if((phys >= region->phys) && 
+                          (phys < region->phys + region->size)){
+                               fd = region->fd;
+                               *offset_out = phys - region->phys;
+                               break;
+                       }
+                       region = region->next;
+               }
+       }
+       else if(phys < __pa(end_iomem) + highmem){
+               fd = physmem_fd;
+               *offset_out = phys - iomem_size;
+       }
+
+       return(fd);
+}
+
+static int __init uml_mem_setup(char *line, int *add)
+{
+       char *retptr;
+       physmem_size = memparse(line,&retptr);
+       return 0;
+}
+__uml_setup("mem=", uml_mem_setup,
+"mem=<Amount of desired ram>\n"
+"    This controls how much \"physical\" memory the kernel allocates\n"
+"    for the system. The size is specified as a number followed by\n"
+"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+"    This is not related to the amount of memory in the host.  It can\n"
+"    be more, and the excess, if it's ever used, will just be swapped out.\n"
+"      Example: mem=64M\n\n"
+);
+
+unsigned long find_iomem(char *driver, unsigned long *len_out)
+{
+       struct iomem_region *region = iomem_regions;
+       
+       while(region != NULL){
+               if(!strcmp(region->driver, driver)){
+                       *len_out = region->size;
+                       return(region->virt);
+               }
+       }
+
+       return(0);
+}
+
+int setup_iomem(void)
+{
+       struct iomem_region *region = iomem_regions;
+       unsigned long iomem_start = high_physmem + PAGE_SIZE;
+       int err;
+
+       while(region != NULL){
+               err = os_map_memory((void *) iomem_start, region->fd, 0, 
+                                   region->size, 1, 1, 0);
+               if(err)
+                       printk("Mapping iomem region for driver '%s' failed, "
+                              "errno = %d\n", region->driver, -err);
+               else {
+                       region->virt = iomem_start;
+                       region->phys = __pa(region->virt);
+               }
+
+               iomem_start += region->size + PAGE_SIZE;
+               region = region->next;
+       }
+
+       return(0);
+}
+
+__initcall(setup_iomem);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
new file mode 100644 (file)
index 0000000..d7ff0b9
--- /dev/null
@@ -0,0 +1,250 @@
+/* 
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/string.h"
+#include "linux/fs.h"
+#include "linux/highmem.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+#include "user_util.h"
+
+extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
+                            pte_t *pte_out);
+
+static unsigned long maybe_map(unsigned long virt, int is_write)
+{
+       pte_t pte;
+       int err;
+
+       void *phys = um_virt_to_phys(current, virt, &pte);
+       int dummy_code;
+
+       if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+               err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
+               if(err)
+                       return(0);
+               phys = um_virt_to_phys(current, virt, NULL);
+       }
+       return((unsigned long) phys);
+}
+
+static int do_op(unsigned long addr, int len, int is_write, 
+                int (*op)(unsigned long addr, int len, void *arg), void *arg)
+{
+       struct page *page;
+       int n;
+
+       addr = maybe_map(addr, is_write);
+       if(addr == -1)
+               return(-1);
+
+       page = phys_to_page(addr);
+       addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
+       n = (*op)(addr, len, arg);
+       kunmap(page);
+
+       return(n);
+}
+
+static void do_buffer_op(void *jmpbuf, void *arg_ptr)
+{
+       va_list args = *((va_list *) arg_ptr);
+       unsigned long addr = va_arg(args, unsigned long);
+       int len = va_arg(args, int);
+       int is_write = va_arg(args, int);
+       int (*op)(unsigned long, int, void *) = va_arg(args, void *);
+       void *arg = va_arg(args, void *);
+       int *res = va_arg(args, int *);
+       int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
+       int remain = len, n;
+
+       current->thread.fault_catcher = jmpbuf;
+       n = do_op(addr, size, is_write, op, arg);
+       if(n != 0){
+               *res = (n < 0 ? remain : 0);
+               goto out;
+       }
+
+       addr += size;
+       remain -= size;
+       if(remain == 0){
+               *res = 0;
+               goto out;
+       }
+
+       while(addr < ((addr + remain) & PAGE_MASK)){
+               n = do_op(addr, PAGE_SIZE, is_write, op, arg);
+               if(n != 0){
+                       *res = (n < 0 ? remain : 0);
+                       goto out;
+               }
+
+               addr += PAGE_SIZE;
+               remain -= PAGE_SIZE;
+       }
+       if(remain == 0){
+               *res = 0;
+               goto out;
+       }
+
+       n = do_op(addr, remain, is_write, op, arg);
+       if(n != 0)
+               *res = (n < 0 ? remain : 0);
+       else *res = 0;
+ out:
+       current->thread.fault_catcher = NULL;
+}
+
+static int buffer_op(unsigned long addr, int len, int is_write,
+                    int (*op)(unsigned long addr, int len, void *arg),
+                    void *arg)
+{
+       int faulted, res;
+       
+       faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, 
+                                &res);
+       if(!faulted)
+               return(res);
+
+       return(addr + len - (unsigned long) current->thread.fault_addr);
+}
+
+static int copy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+       unsigned long *to_ptr = arg, to = *to_ptr;
+
+       memcpy((void *) to, (void *) from, len);
+       *to_ptr += len;
+       return(0);
+}
+
+int copy_from_user_skas(void *to, const void *from, int n)
+{
+       if(segment_eq(get_fs(), KERNEL_DS)){
+               memcpy(to, from, n);
+               return(0);
+       }
+
+       return(access_ok_skas(VERIFY_READ, from, n) ?
+              buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
+              n);
+}
+
+static int copy_chunk_to_user(unsigned long to, int len, void *arg)
+{
+       unsigned long *from_ptr = arg, from = *from_ptr;
+
+       memcpy((void *) to, (void *) from, len);
+       *from_ptr += len;
+       return(0);
+}
+
+int copy_to_user_skas(void *to, const void *from, int n)
+{
+       if(segment_eq(get_fs(), KERNEL_DS)){
+               memcpy(to, from, n);
+               return(0);
+       }
+
+       return(access_ok_skas(VERIFY_WRITE, to, n) ?
+              buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
+              n);
+}
+
+static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+       char **to_ptr = arg, *to = *to_ptr;
+       int n;
+
+       strncpy(to, (void *) from, len);
+       n = strnlen(to, len);
+       *to_ptr += n;
+
+       if(n < len) 
+               return(1);
+       return(0);
+}
+
+int strncpy_from_user_skas(char *dst, const char *src, int count)
+{
+       int n;
+       char *ptr = dst;
+
+       if(segment_eq(get_fs(), KERNEL_DS)){
+               strncpy(dst, src, count);
+               return(strnlen(dst, count));
+       }
+
+       if(!access_ok_skas(VERIFY_READ, src, 1))
+               return(-EFAULT);
+
+       n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, 
+                     &ptr);
+       if(n != 0)
+               return(-EFAULT);
+       return(strnlen(dst, count));
+}
+
+static int clear_chunk(unsigned long addr, int len, void *unused)
+{
+       memset((void *) addr, 0, len);
+       return(0);
+}
+
+int __clear_user_skas(void *mem, int len)
+{
+       return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
+}
+
+int clear_user_skas(void *mem, int len)
+{
+       if(segment_eq(get_fs(), KERNEL_DS)){
+               memset(mem, 0, len);
+               return(0);
+       }
+
+       return(access_ok_skas(VERIFY_WRITE, mem, len) ? 
+              buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
+}
+
+static int strnlen_chunk(unsigned long str, int len, void *arg)
+{
+       int *len_ptr = arg, n;
+
+       n = strnlen((void *) str, len);
+       *len_ptr += n;
+
+       if(n < len)
+               return(1);
+       return(0);
+}
+
+int strnlen_user_skas(const void *str, int len)
+{
+       int count = 0, n;
+
+       if(segment_eq(get_fs(), KERNEL_DS))
+               return(strnlen(str, len) + 1);
+
+       n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
+       if(n == 0)
+               return(count + 1);
+       return(-EFAULT);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644 (file)
index 0000000..9c84011
--- /dev/null
@@ -0,0 +1,73 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/uaccess.h"
+
+int copy_from_user_tt(void *to, const void *from, int n)
+{
+       if(!access_ok_tt(VERIFY_READ, from, n)) 
+               return(n);
+
+       return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
+                                  &current->thread.fault_catcher));
+}
+
+int copy_to_user_tt(void *to, const void *from, int n)
+{
+       if(!access_ok_tt(VERIFY_WRITE, to, n))
+               return(n);
+               
+       return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
+                                &current->thread.fault_catcher));
+}
+
+int strncpy_from_user_tt(char *dst, const char *src, int count)
+{
+       int n;
+
+       if(!access_ok_tt(VERIFY_READ, src, 1)) 
+               return(-EFAULT);
+
+       n = __do_strncpy_from_user(dst, src, count, 
+                                  &current->thread.fault_addr,
+                                  &current->thread.fault_catcher);
+       if(n < 0) return(-EFAULT);
+       return(n);
+}
+
+int __clear_user_tt(void *mem, int len)
+{
+       return(__do_clear_user(mem, len,
+                              &current->thread.fault_addr,
+                              &current->thread.fault_catcher));
+}
+
+int clear_user_tt(void *mem, int len)
+{
+       if(!access_ok_tt(VERIFY_WRITE, mem, len))
+               return(len);
+
+       return(__do_clear_user(mem, len, &current->thread.fault_addr,
+                              &current->thread.fault_catcher));
+}
+
+int strnlen_user_tt(const void *str, int len)
+{
+       return(__do_strnlen_user(str, len,
+                                &current->thread.fault_addr,
+                                &current->thread.fault_catcher));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
new file mode 100644 (file)
index 0000000..56b3782
--- /dev/null
@@ -0,0 +1,404 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include "os.h"
+#include "helper.h"
+#include "aio.h"
+#include "init.h"
+#include "user.h"
+#include "mode.h"
+
+struct aio_thread_req {
+       enum aio_type type;
+       int io_fd;
+       unsigned long long offset;
+       char *buf;
+       int len;
+       int reply_fd;
+       void *data;
+};
+
+static int aio_req_fd_r = -1;
+static int aio_req_fd_w = -1;
+
+#if defined(HAVE_AIO_ABI)
+#include <linux/aio_abi.h>
+
+/* If we have the headers, we are going to build with AIO enabled.
+ * If we don't have aio in libc, we define the necessary stubs here.
+ */
+
+#if !defined(HAVE_AIO_LIBC)
+
+#define __NR_io_setup 245
+#define __NR_io_getevents 247
+#define __NR_io_submit 248
+
+static long io_setup(int n, aio_context_t *ctxp)
+{
+  return(syscall(__NR_io_setup, n, ctxp));
+}
+
+static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
+{
+  return(syscall(__NR_io_submit, ctx, nr, iocbpp));
+}
+
+static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
+                        struct io_event *events, struct timespec *timeout)
+{
+  return(syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout));
+}
+
+#endif
+
+/* The AIO_MMAP cases force the mmapped page into memory here
+ * rather than in whatever place first touches the data.  I used
+ * to do this by touching the page, but that's delicate because
+ * gcc is prone to optimizing that away.  So, what's done here
+ * is we read from the descriptor from which the page was 
+ * mapped.  The caller is required to pass an offset which is
+ * inside the page that was mapped.  Thus, when the read 
+ * returns, we know that the page is in the page cache, and
+ * that it now backs the mmapped area.
+ */
+
+static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, 
+                 int len, unsigned long long offset, void *data)
+{
+       struct iocb iocb, *iocbp = &iocb;
+       char c;
+       int err;
+
+       iocb = ((struct iocb) { .aio_data       = (unsigned long) data,
+                               .aio_reqprio    = 0,
+                               .aio_fildes     = fd,
+                               .aio_buf        = (unsigned long) buf,
+                               .aio_nbytes     = len,
+                               .aio_offset     = offset,
+                               .aio_reserved1  = 0,
+                               .aio_reserved2  = 0,
+                               .aio_reserved3  = 0 });
+
+       switch(type){
+       case AIO_READ:
+               iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+               err = io_submit(ctx, 1, &iocbp);
+               break;
+       case AIO_WRITE:
+               iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
+               err = io_submit(ctx, 1, &iocbp);
+               break;
+       case AIO_MMAP:
+               iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+               iocb.aio_buf = (unsigned long) &c;
+               iocb.aio_nbytes = sizeof(c);
+               err = io_submit(ctx, 1, &iocbp);
+               break;
+       default:
+               printk("Bogus op in do_aio - %d\n", type);
+               err = -EINVAL;
+               break;
+       }
+       if(err > 0)
+               err = 0;
+
+       return(err);    
+}
+
+static aio_context_t ctx = 0;
+
+static int aio_thread(void *arg)
+{
+       struct aio_thread_reply reply;
+       struct io_event event;
+       int err, n, reply_fd;
+
+       signal(SIGWINCH, SIG_IGN);
+
+       while(1){
+               n = io_getevents(ctx, 1, 1, &event, NULL);
+               if(n < 0){
+                       if(errno == EINTR)
+                               continue;
+                       printk("aio_thread - io_getevents failed, "
+                              "errno = %d\n", errno);
+               }
+               else {
+                       reply = ((struct aio_thread_reply) 
+                               { .data = (void *) event.data,
+                                 .err  = event.res });
+                       reply_fd = 
+                               ((struct aio_context *) event.data)->reply_fd;
+                       err = os_write_file(reply_fd, &reply, sizeof(reply));
+                       if(err != sizeof(reply))
+                               printk("not_aio_thread - write failed, "
+                                      "fd = %d, err = %d\n", 
+                                      aio_req_fd_r, -err);
+               }
+       }
+       return(0);
+}
+
+#endif
+
+static int do_not_aio(struct aio_thread_req *req)
+{
+       char c;
+       int err;
+
+       switch(req->type){
+       case AIO_READ:
+               err = os_seek_file(req->io_fd, req->offset);
+               if(err)
+                       goto out;
+
+               err = os_read_file(req->io_fd, req->buf, req->len);
+               break;
+       case AIO_WRITE:
+               err = os_seek_file(req->io_fd, req->offset);
+               if(err)
+                       goto out;
+
+               err = os_write_file(req->io_fd, req->buf, req->len);
+               break;
+       case AIO_MMAP:
+               err = os_seek_file(req->io_fd, req->offset);
+               if(err)
+                       goto out;
+
+               err = os_read_file(req->io_fd, &c, sizeof(c));
+               break;
+       default:
+               printk("do_not_aio - bad request type : %d\n", req->type);
+               err = -EINVAL;
+               break;
+       }
+
+ out:
+       return(err);
+}
+
+static int not_aio_thread(void *arg)
+{
+       struct aio_thread_req req;
+       struct aio_thread_reply reply;
+       int err;
+
+       signal(SIGWINCH, SIG_IGN);
+       while(1){
+               err = os_read_file(aio_req_fd_r, &req, sizeof(req));
+               if(err != sizeof(req)){
+                       if(err < 0)
+                               printk("not_aio_thread - read failed, fd = %d, "
+                                      "err = %d\n", aio_req_fd_r, -err);
+                       else {
+                               printk("not_aio_thread - short read, fd = %d, "
+                                      "length = %d\n", aio_req_fd_r, err);
+                       }
+                       continue;
+               }
+               err = do_not_aio(&req);
+               reply = ((struct aio_thread_reply) { .data      = req.data,
+                                                    .err       = err });
+               err = os_write_file(req.reply_fd, &reply, sizeof(reply));
+               if(err != sizeof(reply))
+                       printk("not_aio_thread - write failed, fd = %d, "
+                              "err = %d\n", aio_req_fd_r, -err);
+       }
+}
+
+static int aio_pid = -1;
+
+static int init_aio_24(void)
+{
+       unsigned long stack;
+       int fds[2], err;
+       
+       err = os_pipe(fds, 1, 1);
+       if(err)
+               goto out;
+
+       aio_req_fd_w = fds[0];
+       aio_req_fd_r = fds[1];
+       err = run_helper_thread(not_aio_thread, NULL, 
+                               CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+       if(err < 0)
+               goto out_close_pipe;
+
+       aio_pid = err;
+       goto out;
+
+ out_close_pipe:
+       os_close_file(fds[0]);
+       os_close_file(fds[1]);
+       aio_req_fd_w = -1;
+       aio_req_fd_r = -1;      
+ out:
+       return(0);
+}
+
+#ifdef HAVE_AIO_ABI
+#define DEFAULT_24_AIO 0
+static int init_aio_26(void)
+{
+       unsigned long stack;
+       int err;
+       
+       if(io_setup(256, &ctx)){
+               printk("aio_thread failed to initialize context, err = %d\n",
+                      errno);
+               return(-errno);
+       }
+
+       err = run_helper_thread(aio_thread, NULL, 
+                               CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+       if(err < 0)
+               return(-errno);
+
+       aio_pid = err;
+       err = 0;
+ out:
+       return(err);
+}
+
+int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, 
+                 unsigned long long offset, int reply_fd, void *data)
+{
+       struct aio_thread_reply reply;
+       int err;
+
+       ((struct aio_context *) data)->reply_fd = reply_fd;
+
+       err = do_aio(ctx, type, io_fd, buf, len, offset, data);
+       if(err){
+               reply = ((struct aio_thread_reply) { .data = data,
+                                                    .err  = err });
+               err = os_write_file(reply_fd, &reply, sizeof(reply));
+               if(err != sizeof(reply))
+                       printk("submit_aio_26 - write failed, "
+                              "fd = %d, err = %d\n", reply_fd, -err);
+               else err = 0;
+       }
+
+       return(err);
+}
+
+#else
+#define DEFAULT_24_AIO 1
+static int init_aio_26(void)
+{
+       return(-ENOSYS);
+}
+
+int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, 
+                 unsigned long long offset, int reply_fd, void *data)
+{
+       return(-ENOSYS);
+}
+#endif
+
+static int aio_24 = DEFAULT_24_AIO;
+
+static int __init set_aio_24(char *name, int *add)
+{
+       aio_24 = 1;
+       return(0);
+}
+
+__uml_setup("aio=2.4", set_aio_24,
+"aio=2.4\n"
+"    This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
+"    available.  2.4 AIO is a single thread that handles one request at a\n"
+"    time, synchronously.  2.6 AIO is a thread which uses 2.5 AIO interface\n"
+"    to handle an arbitrary number of pending requests.  2.6 AIO is not\n"
+"    available in tt mode, on 2.4 hosts, or when UML is built with\n"
+"    /usr/include/linux/aio_abi no available.\n\n"
+);
+
+static int init_aio(void)
+{
+       int err;
+
+       CHOOSE_MODE(({ 
+               if(!aio_24){ 
+                       printk("Disabling 2.6 AIO in tt mode\n");
+                       aio_24 = 1;
+               } }), (void) 0);
+
+       if(!aio_24){
+               err = init_aio_26();
+               if(err && (errno == ENOSYS)){
+                       printk("2.6 AIO not supported on the host - "
+                              "reverting to 2.4 AIO\n");
+                       aio_24 = 1;
+               }
+               else return(err);
+       }
+
+       if(aio_24)
+               return(init_aio_24());
+
+       return(0);
+}
+
+__initcall(init_aio);
+
+static void exit_aio(void)
+{
+       if(aio_pid != -1)
+               os_kill_process(aio_pid, 1);
+}
+
+__uml_exitcall(exit_aio);
+
+int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, 
+                 unsigned long long offset, int reply_fd, void *data)
+{
+       struct aio_thread_req req = { .type             = type,
+                                     .io_fd            = io_fd,
+                                     .offset           = offset,
+                                     .buf              = buf,
+                                     .len              = len,
+                                     .reply_fd         = reply_fd,
+                                     .data             = data,
+       };
+       int err;
+
+       err = os_write_file(aio_req_fd_w, &req, sizeof(req));
+       if(err == sizeof(req))
+               err = 0;
+
+       return(err);
+}
+
+int submit_aio(enum aio_type type, int io_fd, char *buf, int len, 
+              unsigned long long offset, int reply_fd, void *data)
+{
+       if(aio_24)
+               return(submit_aio_24(type, io_fd, buf, len, offset, reply_fd, 
+                                    data));
+       else {
+               return(submit_aio_26(type, io_fd, buf, len, offset, reply_fd, 
+                                    data));
+       }
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
new file mode 100644 (file)
index 0000000..cf30a39
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <sys/time.h>
+
+unsigned long long os_usecs(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
new file mode 100644 (file)
index 0000000..ef0fb71
--- /dev/null
@@ -0,0 +1,88 @@
+#include "linux/types.h"
+#include "linux/module.h"
+
+/* Some of this are builtin function (some are not but could in the future),
+ * so I *must* declare good prototypes for them and then EXPORT them.
+ * The kernel code uses the macro defined by include/linux/string.h,
+ * so I undef macros; the userspace code does not include that and I
+ * add an EXPORT for the glibc one.*/
+
+#undef strlen
+#undef strstr
+#undef memcpy
+#undef memset
+
+extern size_t strlen(const char *);
+extern void *memcpy(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+extern int printf(const char *, ...);
+
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(printf);
+
+EXPORT_SYMBOL(strstr);
+
+/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
+ * However, the modules will use the CRC defined *here*, no matter if it is 
+ * good; so the versions of these symbols will always match
+ */
+#define EXPORT_SYMBOL_PROTO(sym)       \
+       int sym(void);                  \
+       EXPORT_SYMBOL(sym);
+
+EXPORT_SYMBOL_PROTO(__errno_location);
+
+EXPORT_SYMBOL_PROTO(access);
+EXPORT_SYMBOL_PROTO(open);
+EXPORT_SYMBOL_PROTO(open64);
+EXPORT_SYMBOL_PROTO(close);
+EXPORT_SYMBOL_PROTO(read);
+EXPORT_SYMBOL_PROTO(write);
+EXPORT_SYMBOL_PROTO(dup2);
+EXPORT_SYMBOL_PROTO(__xstat);
+EXPORT_SYMBOL_PROTO(__lxstat);
+EXPORT_SYMBOL_PROTO(__lxstat64);
+EXPORT_SYMBOL_PROTO(lseek);
+EXPORT_SYMBOL_PROTO(lseek64);
+EXPORT_SYMBOL_PROTO(chown);
+EXPORT_SYMBOL_PROTO(truncate);
+EXPORT_SYMBOL_PROTO(utime);
+EXPORT_SYMBOL_PROTO(chmod);
+EXPORT_SYMBOL_PROTO(rename);
+EXPORT_SYMBOL_PROTO(__xmknod);
+
+EXPORT_SYMBOL_PROTO(symlink);
+EXPORT_SYMBOL_PROTO(link);
+EXPORT_SYMBOL_PROTO(unlink);
+EXPORT_SYMBOL_PROTO(readlink);
+
+EXPORT_SYMBOL_PROTO(mkdir);
+EXPORT_SYMBOL_PROTO(rmdir);
+EXPORT_SYMBOL_PROTO(opendir);
+EXPORT_SYMBOL_PROTO(readdir);
+EXPORT_SYMBOL_PROTO(closedir);
+EXPORT_SYMBOL_PROTO(seekdir);
+EXPORT_SYMBOL_PROTO(telldir);
+
+EXPORT_SYMBOL_PROTO(ioctl);
+
+EXPORT_SYMBOL_PROTO(pread64);
+EXPORT_SYMBOL_PROTO(pwrite64);
+
+EXPORT_SYMBOL_PROTO(statfs);
+EXPORT_SYMBOL_PROTO(statfs64);
+
+EXPORT_SYMBOL_PROTO(getuid);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/bitops.c b/arch/um/sys-i386/bitops.c
new file mode 100644 (file)
index 0000000..97db385
--- /dev/null
@@ -0,0 +1,70 @@
+#include <linux/bitops.h>
+#include <linux/module.h>
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+int find_next_bit(const unsigned long *addr, int size, int offset)
+{
+       const unsigned long *p = addr + (offset >> 5);
+       int set = 0, bit = offset & 31, res;
+
+       if (bit) {
+               /*
+                * Look for nonzero in the first 32 bits:
+                */
+               __asm__("bsfl %1,%0\n\t"
+                       "jne 1f\n\t"
+                       "movl $32, %0\n"
+                       "1:"
+                       : "=r" (set)
+                       : "r" (*p >> bit));
+               if (set < (32 - bit))
+                       return set + offset;
+               set = 32 - bit;
+               p++;
+       }
+       /*
+        * No set bit yet, search remaining full words for a bit
+        */
+       res = find_first_bit (p, size - 32 * (p - addr));
+       return (offset + set + res);
+}
+EXPORT_SYMBOL(find_next_bit);
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+int find_next_zero_bit(const unsigned long *addr, int size, int offset)
+{
+       unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+       int set = 0, bit = offset & 31, res;
+
+       if (bit) {
+               /*
+                * Look for zero in the first 32 bits.
+                */
+               __asm__("bsfl %1,%0\n\t"
+                       "jne 1f\n\t"
+                       "movl $32, %0\n"
+                       "1:"
+                       : "=r" (set)
+                       : "r" (~(*p >> bit)));
+               if (set < (32 - bit))
+                       return set + offset;
+               set = 32 - bit;
+               p++;
+       }
+       /*
+        * No zero yet, search remaining full bytes for a zero
+        */
+       res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+       return (offset + set + res);
+}
+EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/um/sys-i386/semaphore.c b/arch/um/sys-i386/semaphore.c
new file mode 100644 (file)
index 0000000..073912c
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * i386 semaphore implementation.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Portions Copyright 1999 Red Hat, 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.
+ *
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@redhat.com>
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * "sleeping" and the contention routine ordering is protected
+ * by the spinlock in the semaphore's waitqueue head.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+/*
+ * Logic:
+ *  - only on a boundary condition do we need to care. When we go
+ *    from a negative count to a non-negative, we wake people up.
+ *  - when we go from a non-negative count to a negative do we
+ *    (a) synchronize with the "sleeper" count and (b) make sure
+ *    that we're on the wakeup list before we synchronize so that
+ *    we cannot lose wakeup events.
+ */
+
+asmlinkage void __up(struct semaphore *sem)
+{
+       wake_up(&sem->wait);
+}
+
+asmlinkage void __sched __down(struct semaphore * sem)
+{
+       struct task_struct *tsk = current;
+       DECLARE_WAITQUEUE(wait, tsk);
+       unsigned long flags;
+
+       tsk->state = TASK_UNINTERRUPTIBLE;
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       add_wait_queue_exclusive_locked(&sem->wait, &wait);
+
+       sem->sleepers++;
+       for (;;) {
+               int sleepers = sem->sleepers;
+
+               /*
+                * Add "everybody else" into it. They aren't
+                * playing, because we own the spinlock in
+                * the wait_queue_head.
+                */
+               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+                       sem->sleepers = 0;
+                       break;
+               }
+               sem->sleepers = 1;      /* us - see -1 above */
+               spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+               schedule();
+
+               spin_lock_irqsave(&sem->wait.lock, flags);
+               tsk->state = TASK_UNINTERRUPTIBLE;
+       }
+       remove_wait_queue_locked(&sem->wait, &wait);
+       wake_up_locked(&sem->wait);
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+       tsk->state = TASK_RUNNING;
+}
+
+asmlinkage int __sched __down_interruptible(struct semaphore * sem)
+{
+       int retval = 0;
+       struct task_struct *tsk = current;
+       DECLARE_WAITQUEUE(wait, tsk);
+       unsigned long flags;
+
+       tsk->state = TASK_INTERRUPTIBLE;
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       add_wait_queue_exclusive_locked(&sem->wait, &wait);
+
+       sem->sleepers++;
+       for (;;) {
+               int sleepers = sem->sleepers;
+
+               /*
+                * With signals pending, this turns into
+                * the trylock failure case - we won't be
+                * sleeping, and we* can't get the lock as
+                * it has contention. Just correct the count
+                * and exit.
+                */
+               if (signal_pending(current)) {
+                       retval = -EINTR;
+                       sem->sleepers = 0;
+                       atomic_add(sleepers, &sem->count);
+                       break;
+               }
+
+               /*
+                * Add "everybody else" into it. They aren't
+                * playing, because we own the spinlock in
+                * wait_queue_head. The "-1" is because we're
+                * still hoping to get the semaphore.
+                */
+               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+                       sem->sleepers = 0;
+                       break;
+               }
+               sem->sleepers = 1;      /* us - see -1 above */
+               spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+               schedule();
+
+               spin_lock_irqsave(&sem->wait.lock, flags);
+               tsk->state = TASK_INTERRUPTIBLE;
+       }
+       remove_wait_queue_locked(&sem->wait, &wait);
+       wake_up_locked(&sem->wait);
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+       tsk->state = TASK_RUNNING;
+       return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ *
+ * We could have done the trylock with a
+ * single "cmpxchg" without failure cases,
+ * but then it wouldn't work on a 386.
+ */
+asmlinkage int __down_trylock(struct semaphore * sem)
+{
+       int sleepers;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       sleepers = sem->sleepers + 1;
+       sem->sleepers = 0;
+
+       /*
+        * Add "everybody else" and us into it. They aren't
+        * playing, because we own the spinlock in the
+        * wait_queue_head.
+        */
+       if (!atomic_add_negative(sleepers, &sem->count)) {
+               wake_up_locked(&sem->wait);
+       }
+
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+       return 1;
+}
+
+
+/*
+ * The semaphore operations have a special calling sequence that
+ * allow us to do a simpler in-line version of them. These routines
+ * need to convert that sequence back into the C sequence when
+ * there is contention on the semaphore.
+ *
+ * %ecx contains the semaphore pointer on entry. Save the C-clobbered
+ * registers (%eax, %edx and %ecx) except %eax when used as a return
+ * value..
+ */
+asm(
+".section .sched.text\n"
+".align 4\n"
+".globl __down_failed\n"
+"__down_failed:\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "pushl %ebp\n\t"
+       "movl  %esp,%ebp\n\t"
+#endif
+       "pushl %eax\n\t"
+       "pushl %edx\n\t"
+       "pushl %ecx\n\t"
+       "call __down\n\t"
+       "popl %ecx\n\t"
+       "popl %edx\n\t"
+       "popl %eax\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "movl %ebp,%esp\n\t"
+       "popl %ebp\n\t"
+#endif
+       "ret"
+);
+
+asm(
+".section .sched.text\n"
+".align 4\n"
+".globl __down_failed_interruptible\n"
+"__down_failed_interruptible:\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "pushl %ebp\n\t"
+       "movl  %esp,%ebp\n\t"
+#endif
+       "pushl %edx\n\t"
+       "pushl %ecx\n\t"
+       "call __down_interruptible\n\t"
+       "popl %ecx\n\t"
+       "popl %edx\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "movl %ebp,%esp\n\t"
+       "popl %ebp\n\t"
+#endif
+       "ret"
+);
+
+asm(
+".section .sched.text\n"
+".align 4\n"
+".globl __down_failed_trylock\n"
+"__down_failed_trylock:\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "pushl %ebp\n\t"
+       "movl  %esp,%ebp\n\t"
+#endif
+       "pushl %edx\n\t"
+       "pushl %ecx\n\t"
+       "call __down_trylock\n\t"
+       "popl %ecx\n\t"
+       "popl %edx\n\t"
+#if defined(CONFIG_FRAME_POINTER)
+       "movl %ebp,%esp\n\t"
+       "popl %ebp\n\t"
+#endif
+       "ret"
+);
+
+asm(
+".section .sched.text\n"
+".align 4\n"
+".globl __up_wakeup\n"
+"__up_wakeup:\n\t"
+       "pushl %eax\n\t"
+       "pushl %edx\n\t"
+       "pushl %ecx\n\t"
+       "call __up\n\t"
+       "popl %ecx\n\t"
+       "popl %edx\n\t"
+       "popl %eax\n\t"
+       "ret"
+);
+
+/*
+ * rw spinlock fallbacks
+ */
+#if defined(CONFIG_SMP)
+asm(
+".section .sched.text\n"
+".align        4\n"
+".globl        __write_lock_failed\n"
+"__write_lock_failed:\n\t"
+       LOCK "addl      $" RW_LOCK_BIAS_STR ",(%eax)\n"
+"1:    rep; nop\n\t"
+       "cmpl   $" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+       "jne    1b\n\t"
+       LOCK "subl      $" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+       "jnz    __write_lock_failed\n\t"
+       "ret"
+);
+
+asm(
+".section .sched.text\n"
+".align        4\n"
+".globl        __read_lock_failed\n"
+"__read_lock_failed:\n\t"
+       LOCK "incl      (%eax)\n"
+"1:    rep; nop\n\t"
+       "cmpl   $1,(%eax)\n\t"
+       "js     1b\n\t"
+       LOCK "decl      (%eax)\n\t"
+       "js     __read_lock_failed\n\t"
+       "ret"
+);
+#endif
diff --git a/arch/x86_64/mm/mmap.c b/arch/x86_64/mm/mmap.c
new file mode 100644 (file)
index 0000000..011bb4c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  linux/arch/x86-64/mm/mmap.c
+ *
+ *  flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; 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
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+       unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+       if (gap < MIN_GAP)
+               gap = MIN_GAP;
+       else if (gap > MAX_GAP)
+               gap = MAX_GAP;
+
+       return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+       /*
+        * Force standard allocation for 64 bit programs.
+        */
+       if (!test_thread_flag(TIF_IA32))
+               return 1;
+               
+       if (current->personality & ADDR_COMPAT_LAYOUT) 
+               return 1;
+       
+       if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+               return 1;
+               
+       return sysctl_legacy_va_layout;
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+       /*
+        * Fall back to the standard layout if the personality
+        * bit is set, or if the expected stack growth is unlimited:
+        */
+       if (mmap_is_legacy()) {
+               mm->mmap_base = TASK_UNMAPPED_BASE;
+               mm->get_unmapped_area = arch_get_unmapped_area;
+               mm->unmap_area = arch_unmap_area;
+       } else {
+               mm->mmap_base = mmap_base();
+               mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+               mm->get_unmapped_exec_area = arch_get_unmapped_exec_area;
+               mm->unmap_area = arch_unmap_area_topdown;
+       }
+}
diff --git a/configs/kernel-2.6.8-i586-smp.config b/configs/kernel-2.6.8-i586-smp.config
new file mode 100644 (file)
index 0000000..7a0cf3d
--- /dev/null
@@ -0,0 +1,2487 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_MODULE_SIG=y
+# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+CONFIG_M586=y
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_ALIGNMENT_16=y
+CONFIG_X86_INTEL_USERCOPY=y
+# CONFIG_X86_4G is not set
+# CONFIG_X86_SWITCH_PAGETABLES is not set
+# CONFIG_X86_4G_VM_LAYOUT is not set
+# CONFIG_X86_UACCESS_INDIRECT is not set
+# CONFIG_X86_HIGH_ENTRY is not set
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_SCHED_SMT=y
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
+CONFIG_X86_MCE_P4THERMAL=y
+CONFIG_TOSHIBA=m
+CONFIG_I8K=m
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+
+#
+# Firmware Drivers
+#
+CONFIG_EDD=m
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MTRR=y
+# CONFIG_EFI is not set
+# CONFIG_IRQBALANCE is not set
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_REGPARM=y
+
+#
+# Power management options (ACPI, APM)
+#
+CONFIG_PM=y
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_PM_DISK is not set
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_TOSHIBA=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_X86_PM_TIMER=y
+
+#
+# APM (Advanced Power Management) BIOS Support
+#
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+CONFIG_APM_CPU_IDLE=y
+# CONFIG_APM_DISPLAY_BLANK is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_APM_ALLOW_INTS is not set
+# CONFIG_APM_REAL_MODE_POWER_OFF is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+
+#
+# CPUFreq processor drivers
+#
+CONFIG_X86_ACPI_CPUFREQ=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+CONFIG_X86_POWERNOW_K6=m
+CONFIG_X86_POWERNOW_K7=y
+CONFIG_X86_POWERNOW_K8=m
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_SPEEDSTEP_CENTRINO=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_SPEEDSTEP_ICH=y
+CONFIG_X86_SPEEDSTEP_SMI=m
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_SPEEDSTEP_LIB=y
+# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
+CONFIG_X86_LONGRUN=y
+# CONFIG_X86_LONGHAUL is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SCx200 is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_COMPAQ=m
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_HOTPLUG_PCI_IBM=m
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+CONFIG_HOTPLUG_PCI_PCIE=m
+CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_REDBOOT_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PNC2000 is not set
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_ELAN_104NC=m
+CONFIG_MTD_SCx200_DOCFLASH=m
+CONFIG_MTD_AMD76XROM=m
+# CONFIG_MTD_ICHXROM is not set
+CONFIG_MTD_SCB2_FLASH=m
+# CONFIG_MTD_NETtel is not set
+# CONFIG_MTD_DILNETPC is not set
+CONFIG_MTD_L440GX=m
+CONFIG_MTD_PCI=m
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+CONFIG_MTD_DOC2000=m
+# CONFIG_MTD_DOC2001 is not set
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+CONFIG_PARPORT_SERIAL=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_CMD640 is not set
+CONFIG_BLK_DEV_IDEPNP=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_ADMA=y
+CONFIG_BLK_DEV_AEC62XX=y
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+CONFIG_BLK_DEV_ATIIXP=y
+CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_TRIFLEX=y
+CONFIG_BLK_DEV_CY82C693=y
+CONFIG_BLK_DEV_CS5520=y
+CONFIG_BLK_DEV_CS5530=y
+CONFIG_BLK_DEV_HPT34X=y
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NS87415 is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=y
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+CONFIG_PDC202XX_FORCE=y
+CONFIG_BLK_DEV_SVWKS=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_BLK_DEV_SIS5513=y
+CONFIG_BLK_DEV_SLC90E66=y
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+# CONFIG_SCSI_7000FASST is not set
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=4
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=4
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_DPT_I2O is not set
+CONFIG_SCSI_IN2000=m
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_ISP=m
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA2XXX=m
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=m
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+# CONFIG_IEEE1394_ETH1394 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+
+#
+# I2O device support
+#
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+# CONFIG_ATM_MPOA is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_NET_DIVERT=y
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+
+#
+# Old SIR device drivers
+#
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+# CONFIG_TUX is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_ETHERTAP=m
+CONFIG_NET_SB1000=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+# CONFIG_TYPHOON is not set
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI52=m
+CONFIG_NI65=m
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_AT1700 is not set
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+# CONFIG_NET_ISA is not set
+CONFIG_NE2000=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_AMD8111E_NAPI=y
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_DGRS=m
+CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
+CONFIG_E100=m
+CONFIG_E100_NAPI=y
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_POCKET=y
+CONFIG_ATP=m
+CONFIG_DE600=m
+CONFIG_DE620=m
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_E1000_NAPI=y
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SK98LIN=m
+CONFIG_TIGON3=m
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_IXGB=m
+CONFIG_IXGB_NAPI=y
+CONFIG_S2IO=m
+CONFIG_S2IO_NAPI=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_AIRO=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+# CONFIG_ATM_ZATM is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+# CONFIG_ATM_IA is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+# CONFIG_ATM_FORE200E_PCA is not set
+CONFIG_ATM_HE=m
+# CONFIG_ATM_HE_USE_SUNI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+CONFIG_SKFP=m
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+CONFIG_NET_FC=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETDUMP=m
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+
+#
+# Old ISDN4Linux
+#
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+
+#
+# ISDN feature submodules
+#
+
+#
+# ISDN4Linux hardware drivers
+#
+
+#
+# Passive cards
+#
+CONFIG_ISDN_DRV_HISAX=m
+
+#
+# D-channel protocol features
+#
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+CONFIG_HISAX_NO_SENDCOMPLETE=y
+CONFIG_HISAX_NO_LLC=y
+CONFIG_HISAX_NO_KEYPAD=y
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+
+#
+# HiSax supported cards
+#
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+
+#
+# HiSax PCMCIA card service modules
+#
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+
+#
+# HiSax sub driver modules
+#
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+
+#
+# Active cards
+#
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_DRV_TPAM=m
+
+#
+# CAPI subsystem
+#
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+
+#
+# CAPI hardware drivers
+#
+
+#
+# Active AVM cards
+#
+CONFIG_CAPI_AVM=y
+
+#
+# Active Eicon DIVA Server cards
+#
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+CONFIG_GAMEPORT=m
+CONFIG_SOUND_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461x=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+CONFIG_MOUSE_ATIXL=y
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDDLER=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+# CONFIG_INPUT_JOYDUMP is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_ROCKETPORT=m
+# CONFIG_CYCLADES is not set
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+CONFIG_STALDRV=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+# CONFIG_SERIAL_8250_ACPI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_CRASH=m
+CONFIG_PRINTER=m
+CONFIG_LP_CONSOLE=y
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+# CONFIG_SCx200_WDT is not set
+# CONFIG_60XX_WDT is not set
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+
+#
+# ISA-based Watchdog Cards
+#
+CONFIG_PCWATCHDOG=m
+# CONFIG_MIXCOMWD is not set
+CONFIG_WDT=m
+# CONFIG_WDT_501 is not set
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_HW_RANDOM=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+# CONFIG_APPLICOM is not set
+CONFIG_SONYPI=m
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=y
+CONFIG_AGP_ALI=y
+CONFIG_AGP_ATI=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_INTEL_MCH=y
+CONFIG_AGP_NVIDIA=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_SWORKS=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_EFFICEON=y
+CONFIG_DRM=y
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_GAMMA=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+
+#
+# PCMCIA character devices
+#
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+CONFIG_HANGCHECK_TIMER=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+CONFIG_IBM_ASM=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MEYE=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_OVCAMCHIP=m
+
+#
+# Radio Adapters
+#
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported Frontend Modules
+#
+CONFIG_DVB_TWINHAN_DST=m
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_ALPS_TDLB7 is not set
+CONFIG_DVB_ALPS_TDMB7=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_GRUNDIG_29504_491=m
+CONFIG_DVB_GRUNDIG_29504_401=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
+# CONFIG_DVB_TDA1004X is not set
+CONFIG_DVB_NXT6000=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_SKYSTAR=m
+
+#
+# Supported BT878 Adapters
+#
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_VESA=y
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_HGA=m
+CONFIG_FB_HGA_ACCEL=y
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_I810=m
+CONFIG_FB_I810_GTF=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
+# CONFIG_FB_SIS is not set
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+CONFIG_FB_3DFX_ACCEL=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+# CONFIG_SND_SERIAL_U16550 is not set
+CONFIG_SND_MPU401=m
+
+#
+# ISA devices
+#
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+# CONFIG_SND_WAVEFRONT is not set
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+
+#
+# PCI devices
+#
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VX222=m
+
+#
+# ALSA USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+CONFIG_SND_PDAUDIOCF=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_MIDI=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_RW_DETECT=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+# CONFIG_USB_EMI26 is not set
+CONFIG_USB_TIGL=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_TEST=m
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+CONFIG_VXFS_FS=m
+# CONFIG_HPFS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_FRAME_POINTER is not set
+CONFIG_X86_FIND_SMP_CONFIG=y
+CONFIG_X86_MPPARSE=y
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+# CONFIG_SECURITY_SELINUX_MLS is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES_586=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_SIGNATURE=y
+CONFIG_CRYPTO_SIGNATURE_DSA=y
+CONFIG_CRYPTO_MPILIB=y
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_X86_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_PC=y
diff --git a/configs/kernel-2.6.8-i586.config b/configs/kernel-2.6.8-i586.config
new file mode 100644 (file)
index 0000000..fa9b74e
--- /dev/null
@@ -0,0 +1,2504 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_MODULE_SIG=y
+# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+CONFIG_M586=y
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_ALIGNMENT_16=y
+CONFIG_X86_INTEL_USERCOPY=y
+# CONFIG_X86_4G is not set
+# CONFIG_X86_SWITCH_PAGETABLES is not set
+# CONFIG_X86_4G_VM_LAYOUT is not set
+# CONFIG_X86_UACCESS_INDIRECT is not set
+# CONFIG_X86_HIGH_ENTRY is not set
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_X86_UP_APIC is not set
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
+CONFIG_TOSHIBA=m
+CONFIG_I8K=m
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+
+#
+# Firmware Drivers
+#
+CONFIG_EDD=m
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MTRR=y
+# CONFIG_EFI is not set
+CONFIG_REGPARM=y
+
+#
+# Power management options (ACPI, APM)
+#
+CONFIG_PM=y
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_PM_DISK is not set
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_TOSHIBA=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_X86_PM_TIMER=y
+
+#
+# APM (Advanced Power Management) BIOS Support
+#
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+CONFIG_APM_CPU_IDLE=y
+# CONFIG_APM_DISPLAY_BLANK is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_APM_ALLOW_INTS is not set
+# CONFIG_APM_REAL_MODE_POWER_OFF is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+
+#
+# CPUFreq processor drivers
+#
+CONFIG_X86_ACPI_CPUFREQ=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+CONFIG_X86_POWERNOW_K6=m
+CONFIG_X86_POWERNOW_K7=y
+CONFIG_X86_POWERNOW_K8=m
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_SPEEDSTEP_CENTRINO=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_SPEEDSTEP_ICH=y
+CONFIG_X86_SPEEDSTEP_SMI=m
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_SPEEDSTEP_LIB=y
+# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
+CONFIG_X86_LONGRUN=y
+# CONFIG_X86_LONGHAUL is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SCx200 is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_COMPAQ=m
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+CONFIG_HOTPLUG_PCI_PCIE=m
+CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_REDBOOT_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PNC2000 is not set
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_ELAN_104NC=m
+CONFIG_MTD_SCx200_DOCFLASH=m
+CONFIG_MTD_AMD76XROM=m
+# CONFIG_MTD_ICHXROM is not set
+CONFIG_MTD_SCB2_FLASH=m
+# CONFIG_MTD_NETtel is not set
+# CONFIG_MTD_DILNETPC is not set
+CONFIG_MTD_L440GX=m
+CONFIG_MTD_PCI=m
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+CONFIG_MTD_DOC2000=m
+# CONFIG_MTD_DOC2001 is not set
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+CONFIG_PARPORT_SERIAL=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_CMD640 is not set
+CONFIG_BLK_DEV_IDEPNP=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_ADMA=y
+CONFIG_BLK_DEV_AEC62XX=y
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+CONFIG_BLK_DEV_ATIIXP=y
+CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_TRIFLEX=y
+CONFIG_BLK_DEV_CY82C693=y
+CONFIG_BLK_DEV_CS5520=y
+CONFIG_BLK_DEV_CS5530=y
+CONFIG_BLK_DEV_HPT34X=y
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NS87415 is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=y
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+CONFIG_PDC202XX_FORCE=y
+CONFIG_BLK_DEV_SVWKS=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_BLK_DEV_SIS5513=y
+CONFIG_BLK_DEV_SLC90E66=y
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+# CONFIG_SCSI_7000FASST is not set
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=4
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=4
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_DPT_I2O is not set
+CONFIG_SCSI_IN2000=m
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_ISP=m
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA2XXX=m
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=m
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+# CONFIG_IEEE1394_ETH1394 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+
+#
+# I2O device support
+#
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+# CONFIG_ATM_MPOA is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_NET_DIVERT=y
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+
+#
+# Old SIR device drivers
+#
+CONFIG_IRPORT_SIR=m
+
+#
+# Old Serial dongle support
+#
+# CONFIG_DONGLE_OLD is not set
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+# CONFIG_TUX is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_ETHERTAP=m
+CONFIG_NET_SB1000=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+# CONFIG_TYPHOON is not set
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+# CONFIG_NI5010 is not set
+CONFIG_NI52=m
+CONFIG_NI65=m
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_AT1700 is not set
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+# CONFIG_NET_ISA is not set
+CONFIG_NE2000=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_AMD8111E_NAPI=y
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_DGRS=m
+CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
+CONFIG_E100=m
+CONFIG_E100_NAPI=y
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_POCKET=y
+CONFIG_ATP=m
+CONFIG_DE600=m
+CONFIG_DE620=m
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_E1000_NAPI=y
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SK98LIN=m
+CONFIG_TIGON3=m
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_IXGB=m
+CONFIG_IXGB_NAPI=y
+CONFIG_S2IO=m
+CONFIG_S2IO_NAPI=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_AIRO=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+# CONFIG_ATM_ZATM is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+# CONFIG_ATM_IA is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+# CONFIG_ATM_FORE200E_PCA is not set
+CONFIG_ATM_HE=m
+# CONFIG_ATM_HE_USE_SUNI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+CONFIG_SKFP=m
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+CONFIG_NET_FC=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETDUMP=m
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+
+#
+# Old ISDN4Linux
+#
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+
+#
+# ISDN feature submodules
+#
+CONFIG_ISDN_DRV_LOOP=m
+
+#
+# ISDN4Linux hardware drivers
+#
+
+#
+# Passive cards
+#
+CONFIG_ISDN_DRV_HISAX=m
+
+#
+# D-channel protocol features
+#
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+CONFIG_HISAX_NO_SENDCOMPLETE=y
+CONFIG_HISAX_NO_LLC=y
+CONFIG_HISAX_NO_KEYPAD=y
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+
+#
+# HiSax supported cards
+#
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+
+#
+# HiSax PCMCIA card service modules
+#
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+
+#
+# HiSax sub driver modules
+#
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+
+#
+# Active cards
+#
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_DRV_TPAM=m
+CONFIG_HYSDN=m
+CONFIG_HYSDN_CAPI=y
+
+#
+# CAPI subsystem
+#
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+
+#
+# CAPI hardware drivers
+#
+
+#
+# Active AVM cards
+#
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_T1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+
+#
+# Active Eicon DIVA Server cards
+#
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+CONFIG_GAMEPORT=m
+CONFIG_SOUND_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461x=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+CONFIG_MOUSE_ATIXL=y
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDDLER=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+# CONFIG_INPUT_JOYDUMP is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+CONFIG_ROCKETPORT=m
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+CONFIG_STALDRV=y
+# CONFIG_STALLION is not set
+# CONFIG_ISTALLION is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+# CONFIG_SERIAL_8250_ACPI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_CRASH=m
+CONFIG_PRINTER=m
+CONFIG_LP_CONSOLE=y
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+# CONFIG_SCx200_WDT is not set
+# CONFIG_60XX_WDT is not set
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+
+#
+# ISA-based Watchdog Cards
+#
+CONFIG_PCWATCHDOG=m
+# CONFIG_MIXCOMWD is not set
+CONFIG_WDT=m
+# CONFIG_WDT_501 is not set
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_HW_RANDOM=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+# CONFIG_APPLICOM is not set
+CONFIG_SONYPI=m
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+CONFIG_AGP_ALI=y
+CONFIG_AGP_ATI=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_INTEL_MCH=y
+CONFIG_AGP_NVIDIA=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_SWORKS=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_EFFICEON=y
+CONFIG_DRM=y
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_GAMMA=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+
+#
+# PCMCIA character devices
+#
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+CONFIG_HANGCHECK_TIMER=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+CONFIG_IBM_ASM=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MEYE=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_OVCAMCHIP=m
+
+#
+# Radio Adapters
+#
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported Frontend Modules
+#
+CONFIG_DVB_TWINHAN_DST=m
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_ALPS_TDLB7 is not set
+CONFIG_DVB_ALPS_TDMB7=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_GRUNDIG_29504_491=m
+CONFIG_DVB_GRUNDIG_29504_401=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
+# CONFIG_DVB_TDA1004X is not set
+CONFIG_DVB_NXT6000=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_SKYSTAR=m
+
+#
+# Supported BT878 Adapters
+#
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_VESA=y
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_HGA=m
+CONFIG_FB_HGA_ACCEL=y
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_I810=m
+CONFIG_FB_I810_GTF=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
+# CONFIG_FB_SIS is not set
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+CONFIG_FB_3DFX_ACCEL=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+# CONFIG_SND_SERIAL_U16550 is not set
+CONFIG_SND_MPU401=m
+
+#
+# ISA devices
+#
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+# CONFIG_SND_WAVEFRONT is not set
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+
+#
+# PCI devices
+#
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VX222=m
+
+#
+# ALSA USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+CONFIG_SND_PDAUDIOCF=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_MIDI=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_RW_DETECT=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+# CONFIG_USB_EMI26 is not set
+CONFIG_USB_TIGL=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_TEST=m
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+CONFIG_VXFS_FS=m
+# CONFIG_HPFS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+# CONFIG_SECURITY_SELINUX_MLS is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES_586=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_SIGNATURE=y
+CONFIG_CRYPTO_SIGNATURE_DSA=y
+CONFIG_CRYPTO_MPILIB=y
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_PC=y
diff --git a/configs/kernel-2.6.8-i686-smp.config b/configs/kernel-2.6.8-i686-smp.config
new file mode 100644 (file)
index 0000000..1c85fe6
--- /dev/null
@@ -0,0 +1,2490 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_MODULE_SIG=y
+# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+# CONFIG_X86_PC is not set
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+CONFIG_X86_GENERICARCH=y
+# CONFIG_X86_ES7000 is not set
+CONFIG_X86_CYCLONE_TIMER=y
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+CONFIG_M686=y
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_4G=y
+CONFIG_X86_SWITCH_PAGETABLES=y
+CONFIG_X86_4G_VM_LAYOUT=y
+CONFIG_X86_UACCESS_INDIRECT=y
+CONFIG_X86_HIGH_ENTRY=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_SCHED_SMT=y
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_TSC=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
+CONFIG_X86_MCE_P4THERMAL=y
+CONFIG_TOSHIBA=m
+CONFIG_I8K=m
+CONFIG_MICROCODE=m
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+
+#
+# Firmware Drivers
+#
+CONFIG_EDD=m
+# CONFIG_NOHIGHMEM is not set
+# CONFIG_HIGHMEM4G is not set
+CONFIG_HIGHMEM64G=y
+CONFIG_HIGHMEM=y
+CONFIG_X86_PAE=y
+# CONFIG_NUMA is not set
+CONFIG_HIGHPTE=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MTRR=y
+# CONFIG_EFI is not set
+# CONFIG_IRQBALANCE is not set
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_REGPARM=y
+
+#
+# Power management options (ACPI, APM)
+#
+CONFIG_PM=y
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_PM_DISK is not set
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_TOSHIBA=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_X86_PM_TIMER=y
+
+#
+# APM (Advanced Power Management) BIOS Support
+#
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+CONFIG_APM_CPU_IDLE=y
+# CONFIG_APM_DISPLAY_BLANK is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_APM_ALLOW_INTS is not set
+# CONFIG_APM_REAL_MODE_POWER_OFF is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+
+#
+# CPUFreq processor drivers
+#
+CONFIG_X86_ACPI_CPUFREQ=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+CONFIG_X86_POWERNOW_K6=m
+CONFIG_X86_POWERNOW_K7=y
+CONFIG_X86_POWERNOW_K8=m
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_SPEEDSTEP_CENTRINO=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_SPEEDSTEP_ICH=y
+CONFIG_X86_SPEEDSTEP_SMI=m
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_SPEEDSTEP_LIB=y
+# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
+CONFIG_X86_LONGRUN=y
+# CONFIG_X86_LONGHAUL is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SCx200 is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_COMPAQ=m
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_HOTPLUG_PCI_IBM=m
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+CONFIG_HOTPLUG_PCI_PCIE=m
+CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_REDBOOT_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PNC2000 is not set
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_ELAN_104NC=m
+CONFIG_MTD_SCx200_DOCFLASH=m
+CONFIG_MTD_AMD76XROM=m
+# CONFIG_MTD_ICHXROM is not set
+CONFIG_MTD_SCB2_FLASH=m
+# CONFIG_MTD_NETtel is not set
+# CONFIG_MTD_DILNETPC is not set
+CONFIG_MTD_L440GX=m
+CONFIG_MTD_PCI=m
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+CONFIG_MTD_DOC2000=m
+# CONFIG_MTD_DOC2001 is not set
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+CONFIG_PARPORT_SERIAL=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_CMD640 is not set
+CONFIG_BLK_DEV_IDEPNP=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_ADMA=y
+CONFIG_BLK_DEV_AEC62XX=y
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+CONFIG_BLK_DEV_ATIIXP=y
+CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_TRIFLEX=y
+CONFIG_BLK_DEV_CY82C693=y
+CONFIG_BLK_DEV_CS5520=y
+CONFIG_BLK_DEV_CS5530=y
+CONFIG_BLK_DEV_HPT34X=y
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NS87415 is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=y
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+CONFIG_PDC202XX_FORCE=y
+CONFIG_BLK_DEV_SVWKS=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_BLK_DEV_SIS5513=y
+CONFIG_BLK_DEV_SLC90E66=y
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+# CONFIG_SCSI_7000FASST is not set
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=4
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=4
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_DPT_I2O is not set
+CONFIG_SCSI_IN2000=m
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_ISP=m
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA2XXX=m
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=m
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+# CONFIG_IEEE1394_ETH1394 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+
+#
+# I2O device support
+#
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+# CONFIG_ATM_MPOA is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_NET_DIVERT=y
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+
+#
+# Old SIR device drivers
+#
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+# CONFIG_TUX is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_ETHERTAP=m
+CONFIG_NET_SB1000=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI52=m
+CONFIG_NI65=m
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_AT1700 is not set
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+# CONFIG_NET_ISA is not set
+CONFIG_NE2000=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_AMD8111E_NAPI=y
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_DGRS=m
+CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
+CONFIG_E100=m
+CONFIG_E100_NAPI=y
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_POCKET=y
+CONFIG_ATP=m
+CONFIG_DE600=m
+CONFIG_DE620=m
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_E1000_NAPI=y
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SK98LIN=m
+CONFIG_TIGON3=m
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_IXGB=m
+CONFIG_IXGB_NAPI=y
+CONFIG_S2IO=m
+CONFIG_S2IO_NAPI=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_AIRO=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+# CONFIG_ATM_ZATM is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+# CONFIG_ATM_IA is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+# CONFIG_ATM_FORE200E_PCA is not set
+CONFIG_ATM_HE=m
+# CONFIG_ATM_HE_USE_SUNI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+CONFIG_SKFP=m
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+CONFIG_NET_FC=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETDUMP=m
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+
+#
+# Old ISDN4Linux
+#
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+
+#
+# ISDN feature submodules
+#
+
+#
+# ISDN4Linux hardware drivers
+#
+
+#
+# Passive cards
+#
+CONFIG_ISDN_DRV_HISAX=m
+
+#
+# D-channel protocol features
+#
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+CONFIG_HISAX_NO_SENDCOMPLETE=y
+CONFIG_HISAX_NO_LLC=y
+CONFIG_HISAX_NO_KEYPAD=y
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+
+#
+# HiSax supported cards
+#
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+
+#
+# HiSax PCMCIA card service modules
+#
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+
+#
+# HiSax sub driver modules
+#
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+
+#
+# Active cards
+#
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_DRV_TPAM=m
+
+#
+# CAPI subsystem
+#
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+
+#
+# CAPI hardware drivers
+#
+
+#
+# Active AVM cards
+#
+CONFIG_CAPI_AVM=y
+
+#
+# Active Eicon DIVA Server cards
+#
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+CONFIG_GAMEPORT=m
+CONFIG_SOUND_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461x=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+CONFIG_MOUSE_ATIXL=y
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDDLER=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+# CONFIG_INPUT_JOYDUMP is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_ROCKETPORT=m
+# CONFIG_CYCLADES is not set
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+CONFIG_STALDRV=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+# CONFIG_SERIAL_8250_ACPI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_CRASH=m
+CONFIG_PRINTER=m
+CONFIG_LP_CONSOLE=y
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+# CONFIG_SCx200_WDT is not set
+# CONFIG_60XX_WDT is not set
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+
+#
+# ISA-based Watchdog Cards
+#
+CONFIG_PCWATCHDOG=m
+# CONFIG_MIXCOMWD is not set
+CONFIG_WDT=m
+# CONFIG_WDT_501 is not set
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_HW_RANDOM=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+# CONFIG_APPLICOM is not set
+CONFIG_SONYPI=m
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=y
+CONFIG_AGP_ALI=y
+CONFIG_AGP_ATI=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_INTEL_MCH=y
+CONFIG_AGP_NVIDIA=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_SWORKS=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_EFFICEON=y
+CONFIG_DRM=y
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_GAMMA=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+
+#
+# PCMCIA character devices
+#
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+CONFIG_HANGCHECK_TIMER=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+CONFIG_IBM_ASM=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_OVCAMCHIP=m
+
+#
+# Radio Adapters
+#
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported Frontend Modules
+#
+CONFIG_DVB_TWINHAN_DST=m
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_ALPS_TDLB7 is not set
+CONFIG_DVB_ALPS_TDMB7=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_GRUNDIG_29504_491=m
+CONFIG_DVB_GRUNDIG_29504_401=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
+# CONFIG_DVB_TDA1004X is not set
+CONFIG_DVB_NXT6000=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_SKYSTAR=m
+
+#
+# Supported BT878 Adapters
+#
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_VESA=y
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_HGA=m
+CONFIG_FB_HGA_ACCEL=y
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_I810=m
+CONFIG_FB_I810_GTF=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
+# CONFIG_FB_SIS is not set
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+CONFIG_FB_3DFX_ACCEL=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+# CONFIG_SND_SERIAL_U16550 is not set
+CONFIG_SND_MPU401=m
+
+#
+# ISA devices
+#
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+# CONFIG_SND_WAVEFRONT is not set
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+
+#
+# PCI devices
+#
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VX222=m
+
+#
+# ALSA USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+CONFIG_SND_PDAUDIOCF=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_MIDI=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_RW_DETECT=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+# CONFIG_USB_EMI26 is not set
+CONFIG_USB_TIGL=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_TEST=m
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+CONFIG_VXFS_FS=m
+# CONFIG_HPFS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_FRAME_POINTER is not set
+CONFIG_X86_FIND_SMP_CONFIG=y
+CONFIG_X86_MPPARSE=y
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+# CONFIG_SECURITY_SELINUX_MLS is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES_586=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_SIGNATURE=y
+CONFIG_CRYPTO_SIGNATURE_DSA=y
+CONFIG_CRYPTO_MPILIB=y
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_X86_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_PC=y
diff --git a/configs/kernel-2.6.8-i686.config b/configs/kernel-2.6.8-i686.config
new file mode 100644 (file)
index 0000000..3349989
--- /dev/null
@@ -0,0 +1,2505 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_MODULE_SIG=y
+# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+CONFIG_M686=y
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_4G=y
+CONFIG_X86_SWITCH_PAGETABLES=y
+CONFIG_X86_4G_VM_LAYOUT=y
+CONFIG_X86_UACCESS_INDIRECT=y
+CONFIG_X86_HIGH_ENTRY=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_X86_UP_APIC is not set
+CONFIG_X86_TSC=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
+CONFIG_TOSHIBA=m
+CONFIG_I8K=m
+CONFIG_MICROCODE=m
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+
+#
+# Firmware Drivers
+#
+CONFIG_EDD=m
+# CONFIG_NOHIGHMEM is not set
+CONFIG_HIGHMEM4G=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MTRR=y
+# CONFIG_EFI is not set
+CONFIG_REGPARM=y
+
+#
+# Power management options (ACPI, APM)
+#
+CONFIG_PM=y
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_PM_DISK is not set
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_AC=m
+CONFIG_ACPI_BATTERY=m
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_ASUS=m
+CONFIG_ACPI_TOSHIBA=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_EC=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+CONFIG_X86_PM_TIMER=y
+
+#
+# APM (Advanced Power Management) BIOS Support
+#
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+CONFIG_APM_CPU_IDLE=y
+# CONFIG_APM_DISPLAY_BLANK is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_APM_ALLOW_INTS is not set
+# CONFIG_APM_REAL_MODE_POWER_OFF is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+
+#
+# CPUFreq processor drivers
+#
+CONFIG_X86_ACPI_CPUFREQ=m
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
+CONFIG_X86_POWERNOW_K6=m
+CONFIG_X86_POWERNOW_K7=y
+CONFIG_X86_POWERNOW_K8=m
+# CONFIG_X86_GX_SUSPMOD is not set
+CONFIG_X86_SPEEDSTEP_CENTRINO=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
+CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y
+CONFIG_X86_SPEEDSTEP_ICH=y
+CONFIG_X86_SPEEDSTEP_SMI=m
+CONFIG_X86_P4_CLOCKMOD=m
+CONFIG_X86_SPEEDSTEP_LIB=y
+# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set
+CONFIG_X86_LONGRUN=y
+# CONFIG_X86_LONGHAUL is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SCx200 is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+CONFIG_PD6729=m
+CONFIG_I82092=m
+CONFIG_I82365=m
+CONFIG_TCIC=m
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_COMPAQ=m
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+CONFIG_HOTPLUG_PCI_PCIE=m
+CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+CONFIG_MTD_REDBOOT_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PNC2000 is not set
+CONFIG_MTD_SC520CDP=m
+CONFIG_MTD_NETSC520=m
+CONFIG_MTD_SBC_GXX=m
+CONFIG_MTD_ELAN_104NC=m
+CONFIG_MTD_SCx200_DOCFLASH=m
+CONFIG_MTD_AMD76XROM=m
+# CONFIG_MTD_ICHXROM is not set
+CONFIG_MTD_SCB2_FLASH=m
+# CONFIG_MTD_NETtel is not set
+# CONFIG_MTD_DILNETPC is not set
+CONFIG_MTD_L440GX=m
+CONFIG_MTD_PCI=m
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_PMC551=m
+# CONFIG_MTD_PMC551_BUGFIX is not set
+# CONFIG_MTD_PMC551_DEBUG is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+CONFIG_MTD_DOC2000=m
+# CONFIG_MTD_DOC2001 is not set
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+# CONFIG_MTD_DOCPROBE_ADVANCED is not set
+CONFIG_MTD_DOCPROBE_ADDRESS=0
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+CONFIG_PARPORT_SERIAL=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_LBD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_CMD640 is not set
+CONFIG_BLK_DEV_IDEPNP=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_ADMA=y
+CONFIG_BLK_DEV_AEC62XX=y
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_WDC_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+CONFIG_BLK_DEV_ATIIXP=y
+CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_TRIFLEX=y
+CONFIG_BLK_DEV_CY82C693=y
+CONFIG_BLK_DEV_CS5520=y
+CONFIG_BLK_DEV_CS5530=y
+CONFIG_BLK_DEV_HPT34X=y
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NS87415 is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=y
+# CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=y
+CONFIG_PDC202XX_FORCE=y
+CONFIG_BLK_DEV_SVWKS=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_BLK_DEV_SIS5513=y
+CONFIG_BLK_DEV_SLC90E66=y
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+
+#
+# SCSI low-level drivers
+#
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+# CONFIG_SCSI_7000FASST is not set
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=4
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=4
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_DPT_I2O is not set
+CONFIG_SCSI_IN2000=m
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_NV=m
+CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SX4=m
+CONFIG_SCSI_SATA_SIL=m
+CONFIG_SCSI_SATA_SIS=m
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=m
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_ISP=m
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA2XXX=m
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+CONFIG_SCSI_QLA6312=m
+CONFIG_SCSI_QLA6322=m
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+CONFIG_PCMCIA_QLOGIC=m
+CONFIG_PCMCIA_SYM53C500=m
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=m
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+# CONFIG_IEEE1394_ETH1394 is not set
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
+
+#
+# I2O device support
+#
+CONFIG_I2O=m
+CONFIG_I2O_CONFIG=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+# CONFIG_ATM_MPOA is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_NET_DIVERT=y
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+
+#
+# Old SIR device drivers
+#
+CONFIG_IRPORT_SIR=m
+
+#
+# Old Serial dongle support
+#
+# CONFIG_DONGLE_OLD is not set
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_NSC_FIR=m
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+CONFIG_BT_HCIVHCI=m
+# CONFIG_TUX is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_ETHERTAP=m
+CONFIG_NET_SB1000=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+# CONFIG_NI5010 is not set
+CONFIG_NI52=m
+CONFIG_NI65=m
+
+#
+# Tulip family network device support
+#
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_TULIP_NAPI is not set
+CONFIG_DE4X5=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_PCMCIA_XIRCOM=m
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_AT1700 is not set
+CONFIG_DEPCA=m
+CONFIG_HP100=m
+# CONFIG_NET_ISA is not set
+CONFIG_NE2000=m
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_AMD8111_ETH=m
+CONFIG_AMD8111E_NAPI=y
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_B44=m
+CONFIG_FORCEDETH=m
+CONFIG_CS89x0=m
+CONFIG_DGRS=m
+CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
+CONFIG_E100=m
+CONFIG_E100_NAPI=y
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
+CONFIG_NE2K_PCI=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+CONFIG_EPIC100=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_POCKET=y
+CONFIG_ATP=m
+CONFIG_DE600=m
+CONFIG_DE620=m
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_DL2K=m
+CONFIG_E1000=m
+CONFIG_E1000_NAPI=y
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SK98LIN=m
+CONFIG_TIGON3=m
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_IXGB=m
+CONFIG_IXGB_NAPI=y
+CONFIG_S2IO=m
+CONFIG_S2IO_NAPI=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_AIRO=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_PCMCIA_WL3501=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+# CONFIG_ATM_ZATM is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+# CONFIG_ATM_IA is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+# CONFIG_ATM_FORE200E_PCA is not set
+CONFIG_ATM_HE=m
+# CONFIG_ATM_HE_USE_SUNI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+CONFIG_SKFP=m
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+CONFIG_NET_FC=y
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETDUMP=m
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+
+#
+# Old ISDN4Linux
+#
+CONFIG_ISDN_I4L=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_IPPP_FILTER=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
+CONFIG_ISDN_AUDIO=y
+CONFIG_ISDN_TTY_FAX=y
+
+#
+# ISDN feature submodules
+#
+CONFIG_ISDN_DRV_LOOP=m
+
+#
+# ISDN4Linux hardware drivers
+#
+
+#
+# Passive cards
+#
+CONFIG_ISDN_DRV_HISAX=m
+
+#
+# D-channel protocol features
+#
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+CONFIG_HISAX_NO_SENDCOMPLETE=y
+CONFIG_HISAX_NO_LLC=y
+CONFIG_HISAX_NO_KEYPAD=y
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_NI1=y
+CONFIG_HISAX_MAX_CARDS=8
+
+#
+# HiSax supported cards
+#
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NETJET_U=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+CONFIG_HISAX_HFC_SX=y
+CONFIG_HISAX_ENTERNOW_PCI=y
+# CONFIG_HISAX_DEBUG is not set
+
+#
+# HiSax PCMCIA card service modules
+#
+CONFIG_HISAX_SEDLBAUER_CS=m
+CONFIG_HISAX_ELSA_CS=m
+CONFIG_HISAX_AVM_A1_CS=m
+CONFIG_HISAX_TELES_CS=m
+
+#
+# HiSax sub driver modules
+#
+CONFIG_HISAX_ST5481=m
+CONFIG_HISAX_HFCUSB=m
+CONFIG_HISAX_FRITZ_PCIPNP=m
+CONFIG_HISAX_HDLC=y
+
+#
+# Active cards
+#
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_SC=m
+CONFIG_ISDN_DRV_ACT2000=m
+CONFIG_ISDN_DRV_TPAM=m
+CONFIG_HYSDN=m
+CONFIG_HYSDN_CAPI=y
+
+#
+# CAPI subsystem
+#
+CONFIG_ISDN_CAPI=m
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
+CONFIG_ISDN_CAPI_MIDDLEWARE=y
+CONFIG_ISDN_CAPI_CAPI20=m
+CONFIG_ISDN_CAPI_CAPIFS_BOOL=y
+CONFIG_ISDN_CAPI_CAPIFS=m
+CONFIG_ISDN_CAPI_CAPIDRV=m
+
+#
+# CAPI hardware drivers
+#
+
+#
+# Active AVM cards
+#
+CONFIG_CAPI_AVM=y
+CONFIG_ISDN_DRV_AVMB1_B1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCI=m
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y
+CONFIG_ISDN_DRV_AVMB1_T1ISA=m
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m
+CONFIG_ISDN_DRV_AVMB1_AVM_CS=m
+CONFIG_ISDN_DRV_AVMB1_T1PCI=m
+CONFIG_ISDN_DRV_AVMB1_C4=m
+
+#
+# Active Eicon DIVA Server cards
+#
+CONFIG_CAPI_EICON=y
+CONFIG_ISDN_DIVAS=m
+CONFIG_ISDN_DIVAS_BRIPCI=y
+CONFIG_ISDN_DIVAS_PRIPCI=y
+CONFIG_ISDN_DIVAS_DIVACAPI=m
+CONFIG_ISDN_DIVAS_USERIDI=m
+CONFIG_ISDN_DIVAS_MAINT=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+CONFIG_GAMEPORT=m
+CONFIG_SOUND_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_VORTEX=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_GAMEPORT_CS461x=m
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_INPORT=m
+CONFIG_MOUSE_ATIXL=y
+CONFIG_MOUSE_LOGIBM=m
+CONFIG_MOUSE_PC110PAD=m
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=y
+CONFIG_JOYSTICK_IFORCE_232=y
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDDLER=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+# CONFIG_INPUT_JOYDUMP is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=m
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+CONFIG_ROCKETPORT=m
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+CONFIG_SYNCLINK=m
+CONFIG_SYNCLINKMP=m
+CONFIG_N_HDLC=m
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+CONFIG_STALDRV=y
+# CONFIG_STALLION is not set
+# CONFIG_ISTALLION is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+# CONFIG_SERIAL_8250_ACPI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_MULTIPORT=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_CRASH=m
+CONFIG_PRINTER=m
+CONFIG_LP_CONSOLE=y
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_SC520_WDT=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_WAFER_WDT=m
+CONFIG_I8XX_TCO=m
+CONFIG_SC1200_WDT=m
+# CONFIG_SCx200_WDT is not set
+# CONFIG_60XX_WDT is not set
+CONFIG_CPU5_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_MACHZ_WDT=m
+
+#
+# ISA-based Watchdog Cards
+#
+CONFIG_PCWATCHDOG=m
+# CONFIG_MIXCOMWD is not set
+CONFIG_WDT=m
+# CONFIG_WDT_501 is not set
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_WDT_501_PCI=y
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_HW_RANDOM=m
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+CONFIG_DTLK=m
+CONFIG_R3964=m
+# CONFIG_APPLICOM is not set
+CONFIG_SONYPI=m
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+CONFIG_AGP_ALI=y
+CONFIG_AGP_ATI=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_INTEL_MCH=y
+CONFIG_AGP_NVIDIA=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_SWORKS=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_EFFICEON=y
+CONFIG_DRM=y
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_GAMMA=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_I810=m
+CONFIG_DRM_I830=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+
+#
+# PCMCIA character devices
+#
+CONFIG_SYNCLINK_CS=m
+CONFIG_MWAVE=m
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+CONFIG_HANGCHECK_TIMER=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_I801=m
+CONFIG_I2C_I810=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_NFORCE2=m
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_PROSAVAGE=m
+CONFIG_I2C_SAVAGE4=m
+# CONFIG_SCx200_ACB is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_VOODOO3=m
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_FSCHER=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_RTC8564=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+CONFIG_IBM_ASM=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+CONFIG_VIDEO_CPIA_USB=m
+CONFIG_VIDEO_SAA5246A=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_TUNER_3036=m
+CONFIG_VIDEO_STRADIS=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_ZORAN_BUZ=m
+CONFIG_VIDEO_ZORAN_DC10=m
+CONFIG_VIDEO_ZORAN_DC30=m
+CONFIG_VIDEO_ZORAN_LML33=m
+CONFIG_VIDEO_ZORAN_LML33R10=m
+CONFIG_VIDEO_MEYE=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_MXB=m
+CONFIG_VIDEO_DPC=m
+CONFIG_VIDEO_HEXIUM_ORION=m
+CONFIG_VIDEO_HEXIUM_GEMINI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_OVCAMCHIP=m
+
+#
+# Radio Adapters
+#
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_GEMTEK_PCI=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_MAESTRO=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_SF16FMR2=m
+CONFIG_RADIO_TERRATEC=m
+CONFIG_RADIO_TRUST=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+
+#
+# Supported Frontend Modules
+#
+CONFIG_DVB_TWINHAN_DST=m
+CONFIG_DVB_STV0299=m
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_ALPS_TDLB7 is not set
+CONFIG_DVB_ALPS_TDMB7=m
+CONFIG_DVB_ATMEL_AT76C651=m
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_GRUNDIG_29504_491=m
+CONFIG_DVB_GRUNDIG_29504_401=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
+# CONFIG_DVB_TDA1004X is not set
+CONFIG_DVB_NXT6000=m
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+CONFIG_DVB_AV7110=m
+CONFIG_DVB_AV7110_OSD=y
+CONFIG_DVB_BUDGET=m
+CONFIG_DVB_BUDGET_CI=m
+CONFIG_DVB_BUDGET_AV=m
+CONFIG_DVB_BUDGET_PATCH=m
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_SKYSTAR=m
+
+#
+# Supported BT878 Adapters
+#
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
+CONFIG_VIDEO_VIDEOBUF=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_BUF=m
+CONFIG_VIDEO_BTCX=m
+CONFIG_VIDEO_IR=m
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=m
+CONFIG_FB_VESA=y
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_HGA=m
+CONFIG_FB_HGA_ACCEL=y
+CONFIG_FB_RIVA=m
+# CONFIG_FB_RIVA_I2C is not set
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_I810=m
+CONFIG_FB_I810_GTF=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=m
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
+# CONFIG_FB_SIS is not set
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+CONFIG_FB_3DFX_ACCEL=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_TRIDENT_ACCEL=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_MDA_CONSOLE=m
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_RTCTIMER=m
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_OPL4_LIB=m
+CONFIG_SND_VX_LIB=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+# CONFIG_SND_SERIAL_U16550 is not set
+CONFIG_SND_MPU401=m
+
+#
+# ISA devices
+#
+CONFIG_SND_AD1816A=m
+CONFIG_SND_AD1848=m
+CONFIG_SND_CS4231=m
+CONFIG_SND_CS4232=m
+CONFIG_SND_CS4236=m
+CONFIG_SND_ES968=m
+CONFIG_SND_ES1688=m
+CONFIG_SND_ES18XX=m
+CONFIG_SND_GUSCLASSIC=m
+CONFIG_SND_GUSEXTREME=m
+CONFIG_SND_GUSMAX=m
+CONFIG_SND_INTERWAVE=m
+CONFIG_SND_INTERWAVE_STB=m
+CONFIG_SND_OPTI92X_AD1848=m
+CONFIG_SND_OPTI92X_CS4231=m
+CONFIG_SND_OPTI93X=m
+CONFIG_SND_SB8=m
+CONFIG_SND_SB16=m
+CONFIG_SND_SBAWE=m
+CONFIG_SND_SB16_CSP=y
+# CONFIG_SND_WAVEFRONT is not set
+CONFIG_SND_ALS100=m
+CONFIG_SND_AZT2320=m
+CONFIG_SND_CMI8330=m
+CONFIG_SND_DT019X=m
+CONFIG_SND_OPL3SA2=m
+CONFIG_SND_SGALAXY=m
+CONFIG_SND_SSCAPE=m
+
+#
+# PCI devices
+#
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AZT3328=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_NEW_DSP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_HDSP=m
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VX222=m
+
+#
+# ALSA USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+CONFIG_SND_PDAUDIOCF=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_MIDI=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_RW_DETECT=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_AIPTEK=m
+CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
+CONFIG_USB_MTOUCH=m
+CONFIG_USB_EGALAX=m
+CONFIG_USB_XPAD=m
+CONFIG_USB_ATI_REMOTE=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+CONFIG_USB_W9968CF=m
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+# CONFIG_USB_EMI26 is not set
+CONFIG_USB_TIGL=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_TEST=m
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+CONFIG_VXFS_FS=m
+# CONFIG_HPFS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+# CONFIG_SECURITY_SELINUX_MLS is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES_586=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_SIGNATURE=y
+CONFIG_CRYPTO_SIGNATURE_DSA=y
+CONFIG_CRYPTO_MPILIB=y
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_PC=y
diff --git a/crypto/signature/ksign-keyring.c b/crypto/signature/ksign-keyring.c
new file mode 100644 (file)
index 0000000..ee288b6
--- /dev/null
@@ -0,0 +1,112 @@
+/* ksign-keyring.c: public key cache
+ *
+ * Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This file is derived from part of GnuPG.
+ *
+ * GnuPG is free software; 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.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 <linux/rwsem.h>
+#include "local.h"
+
+static LIST_HEAD(keyring);
+static DECLARE_RWSEM(keyring_sem);
+
+static int add_keyblock_key(struct ksign_public_key *pk, void *data)
+{
+       printk("- Added public key %X%X\n", pk->keyid[0], pk->keyid[1]);
+
+//     if (pk->expiredate && pk->expiredate < xtime.tv_sec)
+//             printk("  - public key has expired\n");
+
+       if (pk->timestamp > xtime.tv_sec )
+               printk("  - key was been created %lu seconds in future\n",
+                      pk->timestamp - xtime.tv_sec);
+
+       atomic_inc(&pk->count);
+
+       down_write(&keyring_sem);
+       list_add_tail(&pk->link, &keyring);
+       up_write(&keyring_sem);
+
+       return 0;
+}
+
+static int add_keyblock_uid(struct ksign_user_id *uid, void *data)
+{
+       printk("- User ID: %s\n", uid->name);
+       return 1;
+}
+
+/*****************************************************************************/
+/*
+ *
+ */
+int ksign_load_keyring_from_buffer(const void *buffer, size_t size)
+{
+    printk("Loading keyring\n");
+
+    return ksign_parse_packets((const uint8_t *) buffer,
+                              size,
+                              NULL,
+                              add_keyblock_key,
+                              add_keyblock_uid,
+                              NULL);
+} /* end ksign_load_keyring_from_buffer() */
+
+/*****************************************************************************/
+/*
+ *
+ */
+struct ksign_public_key *ksign_get_public_key(const uint32_t *keyid)
+{
+       struct ksign_public_key *pk;
+
+       down_read(&keyring_sem);
+
+       list_for_each_entry(pk, &keyring, link) {
+               if (memcmp(pk->keyid, keyid, sizeof(pk->keyid)) == 0) {
+                       atomic_inc(&pk->count);
+                       goto found;
+               }
+       }
+
+ found:
+       up_read(&keyring_sem);
+
+       return pk;
+} /* end ksign_get_public_key() */
+
+/*****************************************************************************/
+/*
+ * clear the public key keyring
+ */
+void ksign_clear_keyring(void)
+{
+       struct ksign_public_key *pk;
+
+       down_write(&keyring_sem);
+
+       while (!list_empty(&keyring)) {
+               pk = list_entry(keyring.next, struct ksign_public_key, link);
+               list_del(&pk->link);
+
+               ksign_put_public_key(pk);
+       }
+
+       up_write(&keyring_sem);
+} /* end ksign_clear_keyring() */
diff --git a/crypto/signature/ksign.c b/crypto/signature/ksign.c
new file mode 100644 (file)
index 0000000..b4adcfb
--- /dev/null
@@ -0,0 +1,179 @@
+/* ksign.c: signature checker
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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.
+ */
+
+#include <linux/kernel.h>
+#include <asm/errno.h>
+#include "local.h"
+
+#if 0
+#define _debug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
+#else
+#define _debug(FMT, ...) do { ; } while (0)
+#endif
+
+/*****************************************************************************/
+/*
+ * check the signature which is contained in SIG.
+ */
+static int ksign_signature_check(const struct ksign_signature *sig,
+                                struct crypto_tfm *sha1_tfm)
+{
+       struct ksign_public_key *pk;
+       uint8_t sha1[SHA1_DIGEST_SIZE];
+       MPI result = NULL;
+       int rc = 0;
+
+       pk = ksign_get_public_key(sig->keyid);
+       if (!pk) {
+               printk("ksign: module signed with unknown public key\n");
+               printk("- signature keyid: %08x%08x ver=%u\n",
+                      sig->keyid[0], sig->keyid[1], sig->version);
+               return -EPERM;
+       }
+
+       if (pk->timestamp > sig->timestamp)
+               printk("ksign:"
+                      " public key is %lu seconds newer than the signature\n",
+                      pk->timestamp - sig->timestamp);
+
+       /* complete the digest */
+       if (sig->version >= 4)
+               SHA1_putc(sha1_tfm, sig->version);
+       SHA1_putc(sha1_tfm, sig->sig_class);
+
+       if (sig->version < 4) {
+               u32 a = sig->timestamp;
+               SHA1_putc(sha1_tfm, (a >> 24) & 0xff);
+               SHA1_putc(sha1_tfm, (a >> 16) & 0xff);
+               SHA1_putc(sha1_tfm, (a >>  8) & 0xff);
+               SHA1_putc(sha1_tfm, (a >>  0) & 0xff);
+       }
+       else {
+               uint8_t buf[6];
+               size_t n;
+               SHA1_putc(sha1_tfm, PUBKEY_ALGO_DSA);
+               SHA1_putc(sha1_tfm, DIGEST_ALGO_SHA1);
+               if (sig->hashed_data) {
+                       n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
+                       SHA1_write(sha1_tfm, sig->hashed_data, n + 2);
+                       n += 6;
+               }
+               else {
+                       n = 6;
+               }
+
+               /* add some magic */
+               buf[0] = sig->version;
+               buf[1] = 0xff;
+               buf[2] = n >> 24;
+               buf[3] = n >> 16;
+               buf[4] = n >>  8;
+               buf[5] = n;
+               SHA1_write(sha1_tfm, buf, 6);
+       }
+
+       crypto_digest_final(sha1_tfm, sha1);
+       crypto_free_tfm(sha1_tfm);
+
+
+
+
+
+
+       rc = -ENOMEM;
+       result = mpi_alloc((SHA1_DIGEST_SIZE + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
+       if (!result)
+               goto cleanup;
+
+       rc = mpi_set_buffer(result, sha1, SHA1_DIGEST_SIZE, 0);
+       if (rc < 0)
+               goto cleanup;
+
+       rc = DSA_verify(result, sig->data, pk->pkey);
+
+ cleanup:
+       mpi_free(result);
+       ksign_put_public_key(pk);
+
+       return rc;
+} /* end ksign_signature_check() */
+
+/*****************************************************************************/
+/*
+ * examine the signatures that are parsed out of the signature data - we keep
+ * the first one that's appropriate and ignore the rest
+ * - return 0 if signature of interest (sig not freed by caller)
+ * - return 1 if no interest (caller frees)
+ */
+static int ksign_grab_signature(struct ksign_signature *sig, void *fnxdata)
+{
+       struct ksign_signature **_sig = fnxdata;
+
+       if (sig->sig_class != 0x00) {
+               _debug("ksign: standalone signature of class 0x%02x\n",
+                      sig->sig_class);
+               return 1;
+       }
+
+       if (*_sig)
+               return 1;
+
+       *_sig = sig;
+       return 0;
+} /* end ksign_grab_signature() */
+
+/*****************************************************************************/
+/*
+ * verify the signature of some data with one of the kernel's known public keys
+ * - the SHA1 context should be currently open with the signed data digested
+ *   into it so that more data can be appended
+ * - the SHA1 context is finalised and freed before returning
+ */
+int ksign_verify_signature(const char *sigdata, unsigned sig_size,
+                          struct crypto_tfm *sha1)
+{
+       struct ksign_signature *sig = NULL;
+       int retval;
+
+       /* parse the signature data to get the actual signature */
+       retval = ksign_parse_packets(sigdata, sig_size,
+                                    &ksign_grab_signature, NULL, NULL,
+                                    &sig);
+       if (retval < 0)
+               goto cleanup;
+
+       if (!sig) {
+               printk("Couldn't find valid DSA signature in module\n");
+               return -ENOENT;
+       }
+
+       _debug("signature keyid: %08x%08x ver=%u\n",
+              sig->keyid[0], sig->keyid[1], sig->version);
+
+       /* check the data SHA1 transformation against the public key */
+       retval = ksign_signature_check(sig, sha1);
+       if (retval == 0) {
+               _debug("ksign: Signature check succeeded\n");
+       }
+       else if (retval != -ENOMEM) {
+               _debug("ksign: Signature check failed\n");
+               retval = -EPERM;
+       }
+       else {
+               _debug("ksign: Signature check ENOMEM\n");
+       }
+
+ cleanup:
+       if (sig)
+               ksign_free_signature(sig);
+
+       return retval;
+} /* end ksign_verify_signature() */
diff --git a/drivers/char/drm/drm_irq.h b/drivers/char/drm/drm_irq.h
new file mode 100644 (file)
index 0000000..04bb0ac
--- /dev/null
@@ -0,0 +1,371 @@
+/**
+ * \file drm_irq.h 
+ * IRQ support
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Gareth Hughes <gareth@valinux.com>
+ */
+
+/*
+ * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * 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, 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 (including the next
+ * paragraph) 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "drmP.h"
+
+#include <linux/interrupt.h>   /* For task queue support */
+
+#ifndef __HAVE_SHARED_IRQ
+#define __HAVE_SHARED_IRQ      0
+#endif
+
+#if __HAVE_SHARED_IRQ
+#define DRM_IRQ_TYPE           SA_SHIRQ
+#else
+#define DRM_IRQ_TYPE           0
+#endif
+
+/**
+ * Get interrupt from bus id.
+ * 
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_irq_busid structure.
+ * \return zero on success or a negative number on failure.
+ * 
+ * Finds the PCI device with the specified bus id and gets its IRQ number.
+ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
+ * to that of the device that this DRM instance attached to.
+ */
+int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+                  unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_irq_busid_t __user *argp = (void __user *)arg;
+       drm_irq_busid_t p;
+
+       if (copy_from_user(&p, argp, sizeof(p)))
+               return -EFAULT;
+
+       if ((p.busnum >> 8) != dev->pci_domain ||
+           (p.busnum & 0xff) != dev->pci_bus ||
+           p.devnum != dev->pci_slot ||
+           p.funcnum != dev->pci_func)
+               return -EINVAL;
+
+       p.irq = dev->irq;
+
+       DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+                 p.busnum, p.devnum, p.funcnum, p.irq);
+       if (copy_to_user(argp, &p, sizeof(p)))
+               return -EFAULT;
+       return 0;
+}
+
+#if __HAVE_IRQ
+
+/**
+ * Install IRQ handler.
+ *
+ * \param dev DRM device.
+ * \param irq IRQ number.
+ *
+ * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
+ * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
+ * before and after the installation.
+ */
+int DRM(irq_install)( drm_device_t *dev )
+{
+       int ret;
+       if ( dev->irq == 0 )
+               return -EINVAL;
+
+       down( &dev->struct_sem );
+
+       /* Driver must have been initialized */
+       if ( !dev->dev_private ) {
+               up( &dev->struct_sem );
+               return -EINVAL;
+       }
+
+       if ( dev->irq_enabled ) {
+               up( &dev->struct_sem );
+               return -EBUSY;
+       }
+       dev->irq_enabled = 1;
+       up( &dev->struct_sem );
+
+       DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+#if __HAVE_DMA
+       dev->dma->next_buffer = NULL;
+       dev->dma->next_queue = NULL;
+       dev->dma->this_buffer = NULL;
+#endif
+
+#ifdef __HAVE_IRQ_BH
+       INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev);
+#endif
+
+#ifdef __HAVE_VBL_IRQ
+       init_waitqueue_head(&dev->vbl_queue);
+
+       spin_lock_init( &dev->vbl_lock );
+
+       INIT_LIST_HEAD( &dev->vbl_sigs.head );
+
+       dev->vbl_pending = 0;
+#endif
+
+                               /* Before installing handler */
+       DRM(driver_irq_preinstall)(dev);
+
+                               /* Install handler */
+       ret = request_irq( dev->irq, DRM(irq_handler),
+                          DRM_IRQ_TYPE, dev->devname, dev );
+       if ( ret < 0 ) {
+               down( &dev->struct_sem );
+               dev->irq_enabled = 0;
+               up( &dev->struct_sem );
+               return ret;
+       }
+
+                               /* After installing handler */
+       DRM(driver_irq_postinstall)(dev);
+
+       return 0;
+}
+
+/**
+ * Uninstall the IRQ handler.
+ *
+ * \param dev DRM device.
+ *
+ * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq.
+ */
+int DRM(irq_uninstall)( drm_device_t *dev )
+{
+       int irq_enabled;
+
+       down( &dev->struct_sem );
+       irq_enabled = dev->irq_enabled;
+       dev->irq_enabled = 0;
+       up( &dev->struct_sem );
+
+       if ( !irq_enabled )
+               return -EINVAL;
+
+       DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+       DRM(driver_irq_uninstall)( dev );
+
+       free_irq( dev->irq, dev );
+
+       return 0;
+}
+
+/**
+ * IRQ control ioctl.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_control structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Calls irq_install() or irq_uninstall() according to \p arg.
+ */
+int DRM(control)( struct inode *inode, struct file *filp,
+                 unsigned int cmd, unsigned long arg )
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_control_t ctl;
+
+       if ( copy_from_user( &ctl, (drm_control_t __user *)arg, sizeof(ctl) ) )
+               return -EFAULT;
+
+       switch ( ctl.func ) {
+       case DRM_INST_HANDLER:
+               if (dev->if_version < DRM_IF_VERSION(1, 2) &&
+                   ctl.irq != dev->irq)
+                       return -EINVAL;
+               return DRM(irq_install)( dev );
+       case DRM_UNINST_HANDLER:
+               return DRM(irq_uninstall)( dev );
+       default:
+               return -EINVAL;
+       }
+}
+
+#ifdef __HAVE_VBL_IRQ
+
+/**
+ * Wait for VBLANK.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param data user argument, pointing to a drm_wait_vblank structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Verifies the IRQ is installed. 
+ *
+ * If a signal is requested checks if this task has already scheduled the same signal
+ * for the same vblank sequence number - nothing to be done in
+ * that case. If the number of tasks waiting for the interrupt exceeds 100 the
+ * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
+ * task.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+int DRM(wait_vblank)( DRM_IOCTL_ARGS )
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_wait_vblank_t __user *argp = (void __user *)data;
+       drm_wait_vblank_t vblwait;
+       struct timeval now;
+       int ret = 0;
+       unsigned int flags;
+
+       if (!dev->irq)
+               return -EINVAL;
+
+       DRM_COPY_FROM_USER_IOCTL( vblwait, argp, sizeof(vblwait) );
+
+       switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
+       case _DRM_VBLANK_RELATIVE:
+               vblwait.request.sequence += atomic_read( &dev->vbl_received );
+               vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+       case _DRM_VBLANK_ABSOLUTE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+       
+       if ( flags & _DRM_VBLANK_SIGNAL ) {
+               unsigned long irqflags;
+               drm_vbl_sig_t *vbl_sig;
+               
+               vblwait.reply.sequence = atomic_read( &dev->vbl_received );
+
+               spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+               /* Check if this task has already scheduled the same signal
+                * for the same vblank sequence number; nothing to be done in
+                * that case
+                */
+               list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
+                       if (vbl_sig->sequence == vblwait.request.sequence
+                           && vbl_sig->info.si_signo == vblwait.request.signal
+                           && vbl_sig->task == current)
+                       {
+                               spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+                               goto done;
+                       }
+               }
+
+               if ( dev->vbl_pending >= 100 ) {
+                       spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+                       return -EBUSY;
+               }
+
+               dev->vbl_pending++;
+
+               spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+
+               if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
+                       return -ENOMEM;
+               }
+
+               memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
+
+               vbl_sig->sequence = vblwait.request.sequence;
+               vbl_sig->info.si_signo = vblwait.request.signal;
+               vbl_sig->task = current;
+
+               spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+               list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
+
+               spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+       } else {
+               ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
+
+               do_gettimeofday( &now );
+               vblwait.reply.tval_sec = now.tv_sec;
+               vblwait.reply.tval_usec = now.tv_usec;
+       }
+
+done:
+       DRM_COPY_TO_USER_IOCTL( argp, vblwait, sizeof(vblwait) );
+
+       return ret;
+}
+
+/**
+ * Send the VBLANK signals.
+ *
+ * \param dev DRM device.
+ *
+ * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+void DRM(vbl_send_signals)( drm_device_t *dev )
+{
+       struct list_head *list, *tmp;
+       drm_vbl_sig_t *vbl_sig;
+       unsigned int vbl_seq = atomic_read( &dev->vbl_received );
+       unsigned long flags;
+
+       spin_lock_irqsave( &dev->vbl_lock, flags );
+
+       list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
+               vbl_sig = list_entry( list, drm_vbl_sig_t, head );
+               if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
+                       vbl_sig->info.si_code = vbl_seq;
+                       send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
+
+                       list_del( list );
+
+                       DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
+
+                       dev->vbl_pending--;
+               }
+       }
+
+       spin_unlock_irqrestore( &dev->vbl_lock, flags );
+}
+
+#endif /* __HAVE_VBL_IRQ */
+
+#endif /* __HAVE_IRQ */
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
new file mode 100644 (file)
index 0000000..5e8c472
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+ * Intel & MS High Precision Event Timer Implementation.
+ *
+ * Copyright (C) 2003 Intel Corporation
+ *     Venki Pallipadi
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ *     Bob Picco <robert.picco@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/wait.h>
+#include <linux/bcd.h>
+#include <linux/seq_file.h>
+
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/div64.h>
+
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <linux/hpet.h>
+
+/*
+ * The High Precision Event Timer driver.
+ * This driver is closely modelled after the rtc.c driver.
+ * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ */
+#define        HPET_USER_FREQ  (64)
+#define        HPET_DRIFT      (500)
+
+static u32 hpet_ntimer, hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+
+/* A lock for concurrent access by app and isr hpet activity. */
+static spinlock_t hpet_lock = SPIN_LOCK_UNLOCKED;
+/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
+static spinlock_t hpet_task_lock = SPIN_LOCK_UNLOCKED;
+
+#define        HPET_DEV_NAME   (7)
+
+struct hpet_dev {
+       struct hpets *hd_hpets;
+       struct hpet *hd_hpet;
+       struct hpet_timer *hd_timer;
+       unsigned long hd_ireqfreq;
+       unsigned long hd_irqdata;
+       wait_queue_head_t hd_waitqueue;
+       struct fasync_struct *hd_async_queue;
+       struct hpet_task *hd_task;
+       unsigned int hd_flags;
+       unsigned int hd_irq;
+       unsigned int hd_hdwirq;
+       char hd_name[HPET_DEV_NAME];
+};
+
+struct hpets {
+       struct hpets *hp_next;
+       struct hpet *hp_hpet;
+       unsigned long hp_period;
+       unsigned long hp_delta;
+       unsigned int hp_ntimer;
+       unsigned int hp_which;
+       struct hpet_dev hp_dev[1];
+};
+
+static struct hpets *hpets;
+
+#define        HPET_OPEN               0x0001
+#define        HPET_IE                 0x0002  /* interrupt enabled */
+#define        HPET_PERIODIC           0x0004
+
+#if BITS_PER_LONG == 64
+#define        write_counter(V, MC)    writeq(V, MC)
+#define        read_counter(MC)        readq(MC)
+#else
+#define        write_counter(V, MC)    writel(V, MC)
+#define        read_counter(MC)        readl(MC)
+#endif
+
+#ifndef readq
+static unsigned long long __inline readq(void *addr)
+{
+       return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static void __inline writeq(unsigned long long v, void *addr)
+{
+       writel(v & 0xffffffff, addr);
+       writel(v >> 32, addr + 4);
+}
+#endif
+
+static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+       struct hpet_dev *devp;
+       unsigned long isr;
+
+       devp = data;
+
+       spin_lock(&hpet_lock);
+       devp->hd_irqdata++;
+
+       /*
+        * For non-periodic timers, increment the accumulator.
+        * This has the effect of treating non-periodic like periodic.
+        */
+       if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
+               unsigned long m, t;
+
+               t = devp->hd_ireqfreq;
+               m = read_counter(&devp->hd_hpet->hpet_mc);
+               write_counter(t + m + devp->hd_hpets->hp_delta,
+                             &devp->hd_timer->hpet_compare);
+       }
+
+       isr = (1 << (devp - devp->hd_hpets->hp_dev));
+       writeq(isr, &devp->hd_hpet->hpet_isr);
+       spin_unlock(&hpet_lock);
+
+       spin_lock(&hpet_task_lock);
+       if (devp->hd_task)
+               devp->hd_task->ht_func(devp->hd_task->ht_data);
+       spin_unlock(&hpet_task_lock);
+
+       wake_up_interruptible(&devp->hd_waitqueue);
+
+       kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
+
+       return IRQ_HANDLED;
+}
+
+static int hpet_open(struct inode *inode, struct file *file)
+{
+       struct hpet_dev *devp;
+       struct hpets *hpetp;
+       int i;
+
+       if (file->f_mode & FMODE_WRITE)
+               return -EINVAL;
+
+       spin_lock_irq(&hpet_lock);
+
+       for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+               for (i = 0; i < hpetp->hp_ntimer; i++)
+                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
+                           || hpetp->hp_dev[i].hd_task)
+                               continue;
+                       else {
+                               devp = &hpetp->hp_dev[i];
+                               break;
+                       }
+
+       if (!devp) {
+               spin_unlock_irq(&hpet_lock);
+               return -EBUSY;
+       }
+
+       file->private_data = devp;
+       devp->hd_irqdata = 0;
+       devp->hd_flags |= HPET_OPEN;
+       spin_unlock_irq(&hpet_lock);
+
+       return 0;
+}
+
+static ssize_t
+hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long data;
+       ssize_t retval;
+       struct hpet_dev *devp;
+
+       devp = file->private_data;
+       if (!devp->hd_ireqfreq)
+               return -EIO;
+
+       if (count < sizeof(unsigned long))
+               return -EINVAL;
+
+       add_wait_queue(&devp->hd_waitqueue, &wait);
+
+       for ( ; ; ) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               spin_lock_irq(&hpet_lock);
+               data = devp->hd_irqdata;
+               devp->hd_irqdata = 0;
+               spin_unlock_irq(&hpet_lock);
+
+               if (data)
+                       break;
+               else if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               } else if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+               schedule();
+       }
+
+       retval = put_user(data, (unsigned long __user *)buf);
+       if (!retval)
+               retval = sizeof(unsigned long);
+out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&devp->hd_waitqueue, &wait);
+
+       return retval;
+}
+
+static unsigned int hpet_poll(struct file *file, poll_table * wait)
+{
+       unsigned long v;
+       struct hpet_dev *devp;
+
+       devp = file->private_data;
+
+       if (!devp->hd_ireqfreq)
+               return 0;
+
+       poll_wait(file, &devp->hd_waitqueue, wait);
+
+       spin_lock_irq(&hpet_lock);
+       v = devp->hd_irqdata;
+       spin_unlock_irq(&hpet_lock);
+
+       if (v != 0)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_HPET_MMAP
+       struct hpet_dev *devp;
+       unsigned long addr;
+
+       if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+               return -EINVAL;
+
+       devp = file->private_data;
+       addr = (unsigned long)devp->hd_hpet;
+
+       if (addr & (PAGE_SIZE - 1))
+               return -ENOSYS;
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       addr = __pa(addr);
+
+       if (remap_page_range
+           (vma, vma->vm_start, addr, PAGE_SIZE, vma->vm_page_prot)) {
+               printk(KERN_ERR "remap_page_range failed in hpet.c\n");
+               return -EAGAIN;
+       }
+
+       return 0;
+#else
+       return -ENOSYS;
+#endif
+}
+
+static int hpet_fasync(int fd, struct file *file, int on)
+{
+       struct hpet_dev *devp;
+
+       devp = file->private_data;
+
+       if (fasync_helper(fd, file, on, &devp->hd_async_queue) >= 0)
+               return 0;
+       else
+               return -EIO;
+}
+
+static int hpet_release(struct inode *inode, struct file *file)
+{
+       struct hpet_dev *devp;
+       struct hpet_timer *timer;
+       int irq = 0;
+
+       devp = file->private_data;
+       timer = devp->hd_timer;
+
+       spin_lock_irq(&hpet_lock);
+
+       writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+              &timer->hpet_config);
+
+       irq = devp->hd_irq;
+       devp->hd_irq = 0;
+
+       devp->hd_ireqfreq = 0;
+
+       if (devp->hd_flags & HPET_PERIODIC
+           && readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+               unsigned long v;
+
+               v = readq(&timer->hpet_config);
+               v ^= Tn_TYPE_CNF_MASK;
+               writeq(v, &timer->hpet_config);
+       }
+
+       devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC);
+       spin_unlock_irq(&hpet_lock);
+
+       if (irq)
+               free_irq(irq, devp);
+
+       if (file->f_flags & FASYNC)
+               hpet_fasync(-1, file, 0);
+
+       file->private_data = NULL;
+       return 0;
+}
+
+static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
+
+static int
+hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+          unsigned long arg)
+{
+       struct hpet_dev *devp;
+
+       devp = file->private_data;
+       return hpet_ioctl_common(devp, cmd, arg, 0);
+}
+
+static int hpet_ioctl_ieon(struct hpet_dev *devp)
+{
+       struct hpet_timer *timer;
+       struct hpet *hpet;
+       struct hpets *hpetp;
+       int irq;
+       unsigned long g, v, t, m;
+       unsigned long flags, isr;
+
+       timer = devp->hd_timer;
+       hpet = devp->hd_hpet;
+       hpetp = devp->hd_hpets;
+
+       v = readq(&timer->hpet_config);
+       spin_lock_irq(&hpet_lock);
+
+       if (devp->hd_flags & HPET_IE) {
+               spin_unlock_irq(&hpet_lock);
+               return -EBUSY;
+       }
+
+       devp->hd_flags |= HPET_IE;
+       spin_unlock_irq(&hpet_lock);
+
+       t = readq(&timer->hpet_config);
+       irq = devp->hd_hdwirq;
+
+       if (irq) {
+               sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
+
+               if (request_irq
+                   (irq, hpet_interrupt, SA_INTERRUPT, devp->hd_name, (void *)devp)) {
+                       printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+                       irq = 0;
+               }
+       }
+
+       if (irq == 0) {
+               spin_lock_irq(&hpet_lock);
+               devp->hd_flags ^= HPET_IE;
+               spin_unlock_irq(&hpet_lock);
+               return -EIO;
+       }
+
+       devp->hd_irq = irq;
+       t = devp->hd_ireqfreq;
+       v = readq(&timer->hpet_config);
+       g = v | Tn_INT_ENB_CNF_MASK;
+
+       if (devp->hd_flags & HPET_PERIODIC) {
+               write_counter(t, &timer->hpet_compare);
+               g |= Tn_TYPE_CNF_MASK;
+               v |= Tn_TYPE_CNF_MASK;
+               writeq(v, &timer->hpet_config);
+               v |= Tn_VAL_SET_CNF_MASK;
+               writeq(v, &timer->hpet_config);
+               local_irq_save(flags);
+               m = read_counter(&hpet->hpet_mc);
+               write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+       } else {
+               local_irq_save(flags);
+               m = read_counter(&hpet->hpet_mc);
+               write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+       }
+
+       isr = (1 << (devp - hpets->hp_dev));
+       writeq(isr, &hpet->hpet_isr);
+       writeq(g, &timer->hpet_config);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static inline unsigned long hpet_time_div(unsigned long dis)
+{
+       unsigned long long m = 1000000000000000ULL;
+
+       do_div(m, dis);
+
+       return (unsigned long)m;
+}
+
+static int
+hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
+{
+       struct hpet_timer *timer;
+       struct hpet *hpet;
+       struct hpets *hpetp;
+       int err;
+       unsigned long v;
+
+       switch (cmd) {
+       case HPET_IE_OFF:
+       case HPET_INFO:
+       case HPET_EPI:
+       case HPET_DPI:
+       case HPET_IRQFREQ:
+               timer = devp->hd_timer;
+               hpet = devp->hd_hpet;
+               hpetp = devp->hd_hpets;
+               break;
+       case HPET_IE_ON:
+               return hpet_ioctl_ieon(devp);
+       default:
+               return -EINVAL;
+       }
+
+       err = 0;
+
+       switch (cmd) {
+       case HPET_IE_OFF:
+               if ((devp->hd_flags & HPET_IE) == 0)
+                       break;
+               v = readq(&timer->hpet_config);
+               v &= ~Tn_INT_ENB_CNF_MASK;
+               writeq(v, &timer->hpet_config);
+               if (devp->hd_irq) {
+                       free_irq(devp->hd_irq, devp);
+                       devp->hd_irq = 0;
+               }
+               devp->hd_flags ^= HPET_IE;
+               break;
+       case HPET_INFO:
+               {
+                       struct hpet_info info;
+
+                       info.hi_ireqfreq = hpet_time_div(hpetp->hp_period *
+                                                        devp->hd_ireqfreq);
+                       info.hi_flags =
+                           readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
+                       info.hi_hpet = devp->hd_hpets->hp_which;
+                       info.hi_timer = devp - devp->hd_hpets->hp_dev;
+                       if (copy_to_user((void __user *)arg, &info, sizeof(info)))
+                               err = -EFAULT;
+                       break;
+               }
+       case HPET_EPI:
+               v = readq(&timer->hpet_config);
+               if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+                       err = -ENXIO;
+                       break;
+               }
+               devp->hd_flags |= HPET_PERIODIC;
+               break;
+       case HPET_DPI:
+               v = readq(&timer->hpet_config);
+               if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+                       err = -ENXIO;
+                       break;
+               }
+               if (devp->hd_flags & HPET_PERIODIC &&
+                   readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+                       v = readq(&timer->hpet_config);
+                       v ^= Tn_TYPE_CNF_MASK;
+                       writeq(v, &timer->hpet_config);
+               }
+               devp->hd_flags &= ~HPET_PERIODIC;
+               break;
+       case HPET_IRQFREQ:
+               if (!kernel && (arg > hpet_max_freq) &&
+                   !capable(CAP_SYS_RESOURCE)) {
+                       err = -EACCES;
+                       break;
+               }
+
+               if (arg & (arg - 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               devp->hd_ireqfreq = hpet_time_div(hpetp->hp_period * arg);
+       }
+
+       return err;
+}
+
+static struct file_operations hpet_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .read = hpet_read,
+       .poll = hpet_poll,
+       .ioctl = hpet_ioctl,
+       .open = hpet_open,
+       .release = hpet_release,
+       .fasync = hpet_fasync,
+       .mmap = hpet_mmap,
+};
+
+EXPORT_SYMBOL(hpet_alloc);
+EXPORT_SYMBOL(hpet_register);
+EXPORT_SYMBOL(hpet_unregister);
+EXPORT_SYMBOL(hpet_control);
+
+int hpet_register(struct hpet_task *tp, int periodic)
+{
+       unsigned int i;
+       u64 mask;
+       struct hpet_timer *timer;
+       struct hpet_dev *devp;
+       struct hpets *hpetp;
+
+       switch (periodic) {
+       case 1:
+               mask = Tn_PER_INT_CAP_MASK;
+               break;
+       case 0:
+               mask = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irq(&hpet_task_lock);
+       spin_lock(&hpet_lock);
+
+       for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+               for (timer = hpetp->hp_hpet->hpet_timers, i = 0;
+                    i < hpetp->hp_ntimer; i++, timer++) {
+                       if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK)
+                           != mask)
+                               continue;
+
+                       devp = &hpetp->hp_dev[i];
+
+                       if (devp->hd_flags & HPET_OPEN || devp->hd_task) {
+                               devp = NULL;
+                               continue;
+                       }
+
+                       tp->ht_opaque = devp;
+                       devp->hd_task = tp;
+                       break;
+               }
+
+       spin_unlock(&hpet_lock);
+       spin_unlock_irq(&hpet_task_lock);
+
+       if (tp->ht_opaque)
+               return 0;
+       else
+               return -EBUSY;
+}
+
+static inline int hpet_tpcheck(struct hpet_task *tp)
+{
+       struct hpet_dev *devp;
+       struct hpets *hpetp;
+
+       devp = tp->ht_opaque;
+
+       if (!devp)
+               return -ENXIO;
+
+       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+               if (devp >= hpetp->hp_dev
+                   && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
+                   && devp->hd_hpet == hpetp->hp_hpet)
+                       return 0;
+
+       return -ENXIO;
+}
+
+int hpet_unregister(struct hpet_task *tp)
+{
+       struct hpet_dev *devp;
+       struct hpet_timer *timer;
+       int err;
+
+       if ((err = hpet_tpcheck(tp)))
+               return err;
+
+       spin_lock_irq(&hpet_task_lock);
+       spin_lock(&hpet_lock);
+
+       devp = tp->ht_opaque;
+       if (devp->hd_task != tp) {
+               spin_unlock(&hpet_lock);
+               spin_unlock_irq(&hpet_task_lock);
+               return -ENXIO;
+       }
+
+       timer = devp->hd_timer;
+       writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+              &timer->hpet_config);
+       devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
+       devp->hd_task = NULL;
+       spin_unlock(&hpet_lock);
+       spin_unlock_irq(&hpet_task_lock);
+
+       return 0;
+}
+
+int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
+{
+       struct hpet_dev *devp;
+       int err;
+
+       if ((err = hpet_tpcheck(tp)))
+               return err;
+
+       spin_lock_irq(&hpet_lock);
+       devp = tp->ht_opaque;
+       if (devp->hd_task != tp) {
+               spin_unlock_irq(&hpet_lock);
+               return -ENXIO;
+       }
+       spin_unlock_irq(&hpet_lock);
+       return hpet_ioctl_common(devp, cmd, arg, 1);
+}
+
+#ifdef CONFIG_TIME_INTERPOLATION
+
+static unsigned long hpet_offset, last_wall_hpet;
+static long hpet_nsecs_per_cycle, hpet_cycles_per_sec;
+
+static unsigned long hpet_getoffset(void)
+{
+       return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) -
+                             last_wall_hpet) * hpet_nsecs_per_cycle;
+}
+
+static void hpet_update(long delta)
+{
+       unsigned long mc;
+       unsigned long offset;
+
+       mc = read_counter(&hpets->hp_hpet->hpet_mc);
+       offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle;
+
+       if (delta < 0 || (unsigned long)delta < offset)
+               hpet_offset = offset - delta;
+       else
+               hpet_offset = 0;
+       last_wall_hpet = mc;
+}
+
+static void hpet_reset(void)
+{
+       hpet_offset = 0;
+       last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc);
+}
+
+static struct time_interpolator hpet_interpolator = {
+       .get_offset = hpet_getoffset,
+       .update = hpet_update,
+       .reset = hpet_reset
+};
+
+#endif
+
+static ctl_table hpet_table[] = {
+       {
+        .ctl_name = 1,
+        .procname = "max-user-freq",
+        .data = &hpet_max_freq,
+        .maxlen = sizeof(int),
+        .mode = 0644,
+        .proc_handler = &proc_dointvec,
+        },
+       {.ctl_name = 0}
+};
+
+static ctl_table hpet_root[] = {
+       {
+        .ctl_name = 1,
+        .procname = "hpet",
+        .maxlen = 0,
+        .mode = 0555,
+        .child = hpet_table,
+        },
+       {.ctl_name = 0}
+};
+
+static ctl_table dev_root[] = {
+       {
+        .ctl_name = CTL_DEV,
+        .procname = "dev",
+        .maxlen = 0,
+        .mode = 0555,
+        .child = hpet_root,
+        },
+       {.ctl_name = 0}
+};
+
+static struct ctl_table_header *sysctl_header;
+
+/*
+ * Adjustment for when arming the timer with
+ * initial conditions.  That is, main counter
+ * ticks expired before interrupts are enabled.
+ */
+#define        TICK_CALIBRATE  (1000UL)
+
+static unsigned long __init hpet_calibrate(struct hpets *hpetp)
+{
+       struct hpet_timer *timer = NULL;
+       unsigned long t, m, count, i, flags, start;
+       struct hpet_dev *devp;
+       int j;
+       struct hpet *hpet;
+
+       for (j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer; j++, devp++)
+               if ((devp->hd_flags & HPET_OPEN) == 0) {
+                       timer = devp->hd_timer;
+                       break;
+               }
+
+       if (!timer)
+               return 0;
+
+       hpet = hpets->hp_hpet;
+       t = read_counter(&timer->hpet_compare);
+
+       i = 0;
+       count = hpet_time_div(hpetp->hp_period * TICK_CALIBRATE);
+
+       local_irq_save(flags);
+
+       start = read_counter(&hpet->hpet_mc);
+
+       do {
+               m = read_counter(&hpet->hpet_mc);
+               write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+       } while (i++, (m - start) < count);
+
+       local_irq_restore(flags);
+
+       return (m - start) / i;
+}
+
+int __init hpet_alloc(struct hpet_data *hdp)
+{
+       u64 cap, mcfg;
+       struct hpet_dev *devp;
+       u32 i, ntimer;
+       struct hpets *hpetp;
+       size_t siz;
+       struct hpet *hpet;
+       static struct hpets *last __initdata = (struct hpets *)0;
+
+       /*
+        * hpet_alloc can be called by platform dependent code.
+        * if platform dependent code has allocated the hpet
+        * ACPI also reports hpet, then we catch it here.
+        */
+       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+               if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+                       return 0;
+
+       siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
+                                     sizeof(struct hpet_dev));
+
+       hpetp = kmalloc(siz, GFP_KERNEL);
+
+       if (!hpetp)
+               return -ENOMEM;
+
+       memset(hpetp, 0, siz);
+
+       hpetp->hp_which = hpet_nhpet++;
+       hpetp->hp_hpet = (struct hpet *)hdp->hd_address;
+
+       hpetp->hp_ntimer = hdp->hd_nirqs;
+
+       for (i = 0; i < hdp->hd_nirqs; i++)
+               hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+
+       hpet = hpetp->hp_hpet;
+
+       cap = readq(&hpet->hpet_cap);
+
+       ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
+
+       if (hpetp->hp_ntimer != ntimer) {
+               printk(KERN_WARNING "hpet: number irqs doesn't agree"
+                      " with number of timers\n");
+               kfree(hpetp);
+               return -ENODEV;
+       }
+
+       if (last)
+               last->hp_next = hpetp;
+       else
+               hpets = hpetp;
+
+       last = hpetp;
+
+       hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+           HPET_COUNTER_CLK_PERIOD_SHIFT;
+
+       mcfg = readq(&hpet->hpet_config);
+       if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
+               write_counter(0L, &hpet->hpet_mc);
+               mcfg |= HPET_ENABLE_CNF_MASK;
+               writeq(mcfg, &hpet->hpet_config);
+       }
+
+       for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer;
+            i++, hpet_ntimer++, devp++) {
+               unsigned long v;
+               struct hpet_timer *timer;
+
+               timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
+               v = readq(&timer->hpet_config);
+
+               devp->hd_hpets = hpetp;
+               devp->hd_hpet = hpet;
+               devp->hd_timer = timer;
+
+               /*
+                * If the timer was reserved by platform code,
+                * then make timer unavailable for opens.
+                */
+               if (hdp->hd_state & (1 << i)) {
+                       devp->hd_flags = HPET_OPEN;
+                       continue;
+               }
+
+               init_waitqueue_head(&devp->hd_waitqueue);
+       }
+
+       hpetp->hp_delta = hpet_calibrate(hpetp);
+
+       return 0;
+}
+
+static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
+{
+       struct hpet_data *hdp;
+       acpi_status status;
+       struct acpi_resource_address64 addr;
+       struct hpets *hpetp;
+
+       hdp = data;
+
+       status = acpi_resource_to_address64(res, &addr);
+
+       if (ACPI_SUCCESS(status)) {
+               unsigned long size;
+
+               size = addr.max_address_range - addr.min_address_range + 1;
+               hdp->hd_address =
+                   (unsigned long)ioremap(addr.min_address_range, size);
+
+               for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+                       if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+                               return -EBUSY;
+       } else if (res->id == ACPI_RSTYPE_EXT_IRQ) {
+               struct acpi_resource_ext_irq *irqp;
+               int i;
+
+               irqp = &res->data.extended_irq;
+
+               if (irqp->number_of_interrupts > 0) {
+                       hdp->hd_nirqs = irqp->number_of_interrupts;
+
+                       for (i = 0; i < hdp->hd_nirqs; i++)
+                               hdp->hd_irq[i] =
+                                   acpi_register_gsi(irqp->interrupts[i],
+                                                     irqp->edge_level,
+                                                     irqp->active_high_low);
+               }
+       }
+
+       return AE_OK;
+}
+
+static int __init hpet_acpi_add(struct acpi_device *device)
+{
+       acpi_status result;
+       struct hpet_data data;
+
+       memset(&data, 0, sizeof(data));
+
+       result =
+           acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+                               hpet_resources, &data);
+
+       if (ACPI_FAILURE(result))
+               return -ENODEV;
+
+       if (!data.hd_address || !data.hd_nirqs) {
+               printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       return hpet_alloc(&data);
+}
+
+static int __init hpet_acpi_remove(struct acpi_device *device, int type)
+{
+       return 0;
+}
+
+static struct acpi_driver hpet_acpi_driver __initdata = {
+       .name = "hpet",
+       .class = "",
+       .ids = "PNP0103",
+       .ops = {
+               .add = hpet_acpi_add,
+               .remove = hpet_acpi_remove,
+               },
+};
+
+static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops };
+
+static int __init hpet_init(void)
+{
+       (void)acpi_bus_register_driver(&hpet_acpi_driver);
+
+       if (hpets) {
+               if (misc_register(&hpet_misc))
+                       return -ENODEV;
+
+               sysctl_header = register_sysctl_table(dev_root, 0);
+
+#ifdef CONFIG_TIME_INTERPOLATION
+               {
+                       struct hpet *hpet;
+
+                       hpet = hpets->hp_hpet;
+                       hpet_cycles_per_sec = hpet_time_div(hpets->hp_period);
+                       hpet_interpolator.frequency = hpet_cycles_per_sec;
+                       hpet_interpolator.drift = hpet_cycles_per_sec *
+                           HPET_DRIFT / 1000000;
+                       hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec;
+                       register_time_interpolator(&hpet_interpolator);
+               }
+#endif
+               return 0;
+       } else
+               return -ENODEV;
+}
+
+static void __exit hpet_exit(void)
+{
+       acpi_bus_unregister_driver(&hpet_acpi_driver);
+
+       if (hpets)
+               unregister_sysctl_table(sysctl_header);
+
+       return;
+}
+
+module_init(hpet_init);
+module_exit(hpet_exit);
+MODULE_AUTHOR("Bob Picco <Robert.Picco@hp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
new file mode 100644 (file)
index 0000000..96ca634
--- /dev/null
@@ -0,0 +1,1579 @@
+/*
+ * IBM eServer Hypervisor Virtual Console Server Device Driver
+ * Copyright (C) 2003, 2004 IBM Corp.
+ *  Ryan S. Arnold (rsa@us.ibm.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Author(s) :  Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This is the device driver for the IBM Hypervisor Virtual Console Server,
+ * "hvcs".  The IBM hvcs provides a tty driver interface to allow Linux
+ * user space applications access to the system consoles of logically
+ * partitioned operating systems, e.g. Linux, running on the same partitioned
+ * Power5 ppc64 system.  Physical hardware consoles per partition are not
+ * practical on this hardware so system consoles are accessed by this driver
+ * using inter-partition firmware interfaces to virtual terminal devices.
+ *
+ * A vty is known to the HMC as a "virtual serial server adapter".  It is a
+ * virtual terminal device that is created by firmware upon partition creation
+ * to act as a partitioned OS's console device.
+ *
+ * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64
+ * Linux system upon their creation by the HMC or their exposure during boot.
+ * The non-user interactive backend of this driver is implemented as a vio
+ * device driver so that it can receive notification of vty-server lifetimes
+ * after it registers with the vio bus to handle vty-server probe and remove
+ * callbacks.
+ *
+ * Many vty-servers can be configured to connect to one vty, but a vty can
+ * only be actively connected to by a single vty-server, in any manner, at one
+ * time.  If the HMC is currently hosting the console for a target Linux
+ * partition; attempts to open the tty device to the partition's console using
+ * the hvcs on any partition will return -EBUSY with every open attempt until
+ * the HMC frees the connection between its vty-server and the desired
+ * partition's vty device.  Conversely, a vty-server may only be connected to
+ * a single vty at one time even though it may have several configured vty
+ * partner possibilities.
+ *
+ * Firmware does not provide notification of vty partner changes to this
+ * driver.  This means that an HMC Super Admin may add or remove partner vtys
+ * from a vty-server's partner list but the changes will not be signaled to
+ * the vty-server.  Firmware only notifies the driver when a vty-server is
+ * added or removed from the system.  To compensate for this deficiency, this
+ * driver implements a sysfs update attribute which provides a method for
+ * rescanning partner information upon a user's request.
+ *
+ * Each vty-server, prior to being exposed to this driver is reference counted
+ * using the 2.6 Linux kernel kobject construct.  This kobject is also used by
+ * the vio bus to provide a vio device sysfs entry that this driver attaches
+ * device specific attributes to, including partner information.  The vio bus
+ * framework also provides a sysfs entry for each vio driver.  The hvcs driver
+ * provides driver attributes in this entry.
+ *
+ * For direction on installation and usage of this driver please reference
+ * Documentation/powerpc/hvcs.txt.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/hvconsole.h>
+#include <asm/hvcserver.h>
+#include <asm/uaccess.h>
+#include <asm/vio.h>
+
+/*
+ * 1.0.0 -> 1.1.0 Added kernel_thread scheduling methodology to driver to
+ * replace wait_task constructs.
+ *
+ * 1.1.0 -> 1.2.0 Moved pi_buff initialization out of arch code into driver code
+ * and added locking to share this buffer between hvcs_struct instances.  This
+ * is because the page_size kmalloc can't be done with a spin_lock held.
+ *
+ * Also added sysfs attribute to manually disconnect the vty-server from the vty
+ * due to stupid firmware behavior when opening the connection then sending data
+ * then then quickly closing the connection would cause data loss on the
+ * receiving side.  This required some reordering of the termination code.
+ *
+ * Fixed the hangup scenario and fixed memory leaks on module_exit.
+ *
+ * 1.2.0 -> 1.3.0 Moved from manual kernel thread creation & execution to
+ * kthread construct which replaced in-kernel IPC for thread termination with
+ * kthread_stop and kthread_should_stop.  Explicit wait_queue handling was
+ * removed because kthread handles this.  Minor bug fix to postpone partner_info
+ * clearing on hvcs_close until adapter removal to preserve context data for
+ * printk on partner connection free.  Added lock to protect hvcs_structs so
+ * that hvcs_struct instances aren't added or removed during list traversal.
+ * Cleaned up comment style, added spaces after commas, and broke function
+ * declaration lines to be under 80 columns.
+ */
+#define HVCS_DRIVER_VERSION "1.3.0"
+
+MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
+MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HVCS_DRIVER_VERSION);
+
+/*
+ * Since the Linux TTY code does not currently (2-04-2004) support dynamic
+ * addition of tty derived devices and we shouldn't allocate thousands of
+ * tty_device pointers when the number of vty-server & vty partner connections
+ * will most often be much lower than this, we'll arbitrarily allocate
+ * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we
+ * register the tty_driver. This can be overridden using an insmod parameter.
+ */
+#define HVCS_DEFAULT_SERVER_ADAPTERS   64
+
+/*
+ * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device
+ * nodes as a sanity check.  Theoretically there can be over 1 Billion
+ * vty-server & vty partner connections.
+ */
+#define HVCS_MAX_SERVER_ADAPTERS       1024
+
+/*
+ * We let Linux assign us a major number and we start the minors at zero.  There
+ * is no intuitive mapping between minor number and the target partition.  The
+ * mapping of minor number is related to the order the vty-servers are exposed
+ * to this driver via the hvcs_probe function.
+ */
+#define HVCS_MINOR_START       0
+
+/*
+ * The hcall interface involves putting 8 chars into each of two registers.
+ * We load up those 2 registers (in arch/ppc64/hvconsole.c) by casting char[16]
+ * to long[2].  It would work without __ALIGNED__, but a little (tiny) bit
+ * slower because an unaligned load is slower than aligned load.
+ */
+#define __ALIGNED__    __attribute__((__aligned__(8)))
+
+/* Converged location code string length + 1 null terminator */
+#define CLC_LENGTH             80
+
+/*
+ * How much data can firmware send with each hvc_put_chars()?  Maybe this
+ * should be moved into an architecture specific area.
+ */
+#define HVCS_BUFF_LEN  16
+
+/*
+ * This is the maximum amount of data we'll let the user send us (hvcs_write) at
+ * once in a chunk as a sanity check.
+ */
+#define HVCS_MAX_FROM_USER     4096
+
+/*
+ * Be careful when adding flags to this line discipline.  Don't add anything
+ * that will cause echoing or we'll go into recursive loop echoing chars back
+ * and forth with the console drivers.
+ */
+static struct termios hvcs_tty_termios = {
+       .c_iflag = IGNBRK | IGNPAR,
+       .c_oflag = OPOST,
+       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+       .c_cc = INIT_C_CC
+};
+
+/*
+ * This value is used to take the place of a command line parameter when the
+ * module is inserted.  It starts as -1 and stays as such if the user doesn't
+ * specify a module insmod parameter.  If they DO specify one then it is set to
+ * the value of the integer passed in.
+ */
+static int hvcs_parm_num_devs = -1;
+module_param(hvcs_parm_num_devs, int, 0);
+
+char hvcs_driver_name[] = "hvcs";
+char hvcs_device_node[] = "hvcs";
+char hvcs_driver_string[]
+       = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
+
+/* Status of partner info rescan triggered via sysfs. */
+static int hvcs_rescan_status = 0;
+
+static struct tty_driver *hvcs_tty_driver;
+
+/*
+ * This is used to associate a vty-server, as it is exposed to this driver, with
+ * a preallocated tty_struct.index.  The dev node and hvcs index numbers are not
+ * re-used after device removal otherwise removing and adding a new one would
+ * link a /dev/hvcs* entry to a different vty-server than it did before the
+ * removal.  Incidentally, a newly exposed vty-server will always map to an
+ * incrementally higher /dev/hvcs* entry than the last exposed vty-server.
+ */
+static int hvcs_struct_count = -1;
+
+/*
+ * Used by the khvcsd to pick up I/O operations when the kernel_thread is
+ * already awake but potentially shifted to TASK_INTERRUPTIBLE state.
+ */
+static int hvcs_kicked = 0;
+
+/* Used the the kthread construct for task operations */
+static struct task_struct *hvcs_task;
+
+/*
+ * We allocate this for the use of all of the hvcs_structs when they fetch
+ * partner info.
+ */
+static unsigned long *hvcs_pi_buff;
+
+static spinlock_t hvcs_pi_lock;
+
+/* One vty-server per hvcs_struct */
+struct hvcs_struct {
+       spinlock_t lock;
+
+       /*
+        * This index identifies this hvcs device as the complement to a
+        * specific tty index.
+        */
+       unsigned int index;
+
+       struct tty_struct *tty;
+       unsigned int open_count;
+
+       /*
+        * Used to tell the driver kernel_thread what operations need to take
+        * place upon this hvcs_struct instance.
+        */
+       int todo_mask;
+
+       /*
+        * This buffer is required so that when hvcs_write_room() reports that
+        * it can send HVCS_BUFF_LEN characters that it will buffer the full
+        * HVCS_BUFF_LEN characters if need be.  This is essential for opost
+        * writes since they do not do high level buffering and expect to be
+        * able to send what the driver commits to sending buffering
+        * [e.g. tab to space conversions in n_tty.c opost()].
+        */
+       char buffer[HVCS_BUFF_LEN];
+       int chars_in_buffer;
+
+       /*
+        * Any variable below the kobject is valid before a tty is connected and
+        * stays valid after the tty is disconnected.  These shouldn't be
+        * whacked until the koject refcount reaches zero though some entries
+        * may be changed via sysfs initiatives.
+        */
+       struct kobject kobj; /* ref count & hvcs_struct lifetime */
+       int connected; /* is the vty-server currently connected to a vty? */
+       unsigned int p_unit_address; /* partner unit address */
+       unsigned int p_partition_ID; /* partner partition ID */
+       char p_location_code[CLC_LENGTH];
+       struct list_head next; /* list management */
+       struct vio_dev *vdev;
+};
+
+/* Required to back map a kobject to its containing object */
+#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj)
+
+static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
+static spinlock_t hvcs_structs_lock;
+
+static void hvcs_unthrottle(struct tty_struct *tty);
+static void hvcs_throttle(struct tty_struct *tty);
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
+               struct pt_regs *regs);
+
+static int hvcs_write(struct tty_struct *tty, int from_user,
+               const unsigned char *buf, int count);
+static int hvcs_write_room(struct tty_struct *tty);
+static int hvcs_chars_in_buffer(struct tty_struct *tty);
+
+static int hvcs_has_pi(struct hvcs_struct *hvcsd);
+static void hvcs_set_pi(struct hvcs_partner_info *pi,
+               struct hvcs_struct *hvcsd);
+static int hvcs_get_pi(struct hvcs_struct *hvcsd);
+static int hvcs_rescan_devices_list(void);
+
+static int hvcs_partner_connect(struct hvcs_struct *hvcsd);
+static void hvcs_partner_free(struct hvcs_struct *hvcsd);
+
+static int hvcs_enable_device(struct hvcs_struct *hvcsd,
+               uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
+static void hvcs_final_close(struct hvcs_struct *hvcsd);
+
+static void destroy_hvcs_struct(struct kobject *kobj);
+static int hvcs_open(struct tty_struct *tty, struct file *filp);
+static void hvcs_close(struct tty_struct *tty, struct file *filp);
+static void hvcs_hangup(struct tty_struct * tty);
+
+static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd);
+static void hvcs_remove_device_attrs(struct vio_dev *vdev);
+static void hvcs_create_driver_attrs(void);
+static void hvcs_remove_driver_attrs(void);
+
+static int __devinit hvcs_probe(struct vio_dev *dev,
+               const struct vio_device_id *id);
+static int __devexit hvcs_remove(struct vio_dev *dev);
+static int __init hvcs_module_init(void);
+static void __exit hvcs_module_exit(void);
+
+#define HVCS_SCHED_READ        0x00000001
+#define HVCS_QUICK_READ        0x00000002
+#define HVCS_TRY_WRITE 0x00000004
+#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ)
+
+static void hvcs_kick(void)
+{
+       hvcs_kicked = 1;
+       wmb();
+       wake_up_process(hvcs_task);
+}
+
+static void hvcs_unthrottle(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       hvcs_kick();
+}
+
+static void hvcs_throttle(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       vio_disable_interrupts(hvcsd->vdev);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+/*
+ * If the device is being removed we don't have to worry about this interrupt
+ * handler taking any further interrupts because they are disabled which means
+ * the hvcs_struct will always be valid in this handler.
+ */
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
+               struct pt_regs *regs)
+{
+       struct hvcs_struct *hvcsd = dev_instance;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       vio_disable_interrupts(hvcsd->vdev);
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       hvcs_kick();
+
+       return IRQ_HANDLED;
+}
+
+/* This function must be called with the hvcsd->lock held */
+static void hvcs_try_write(struct hvcs_struct *hvcsd)
+{
+       unsigned int unit_address = hvcsd->vdev->unit_address;
+       struct tty_struct *tty = hvcsd->tty;
+       int sent;
+
+       if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
+               /* won't send partial writes */
+               sent = hvc_put_chars(unit_address,
+                               &hvcsd->buffer[0],
+                               hvcsd->chars_in_buffer );
+               if (sent > 0) {
+                       hvcsd->chars_in_buffer = 0;
+                       wmb();
+                       hvcsd->todo_mask &= ~(HVCS_TRY_WRITE);
+                       wmb();
+
+                       /*
+                        * We are still obligated to deliver the data to the
+                        * hypervisor even if the tty has been closed because
+                        * we commited to delivering it.  But don't try to wake
+                        * a non-existent tty.
+                        */
+                       if (tty) {
+                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+                                               && tty->ldisc.write_wakeup)
+                                       (tty->ldisc.write_wakeup) (tty);
+                               wake_up_interruptible(&tty->write_wait);
+                       }
+               }
+       }
+}
+
+static int hvcs_io(struct hvcs_struct *hvcsd)
+{
+       unsigned int unit_address;
+       struct tty_struct *tty;
+       char buf[HVCS_BUFF_LEN] __ALIGNED__;
+       unsigned long flags;
+       int got;
+       int i;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       unit_address = hvcsd->vdev->unit_address;
+       tty = hvcsd->tty;
+
+       hvcs_try_write(hvcsd);
+
+       if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
+               hvcsd->todo_mask &= ~(HVCS_READ_MASK);
+               goto bail;
+       } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
+               goto bail;
+
+       /* remove the read masks */
+       hvcsd->todo_mask &= ~(HVCS_READ_MASK);
+
+       if ((tty->flip.count + HVCS_BUFF_LEN) < TTY_FLIPBUF_SIZE) {
+               got = hvc_get_chars(unit_address,
+                               &buf[0],
+                               HVCS_BUFF_LEN);
+               for (i=0;got && i<got;i++)
+                       tty_insert_flip_char(tty, buf[i], TTY_NORMAL);
+       }
+
+       /* Give the TTY time to process the data we just sent. */
+       if (got)
+               hvcsd->todo_mask |= HVCS_QUICK_READ;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       if (tty->flip.count) {
+               /* This is synch because tty->low_latency == 1 */
+               tty_flip_buffer_push(tty);
+       }
+
+       if (!got) {
+               /* Do this _after_ the flip_buffer_push */
+               spin_lock_irqsave(&hvcsd->lock, flags);
+               vio_enable_interrupts(hvcsd->vdev);
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+       }
+
+       return hvcsd->todo_mask;
+
+ bail:
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return hvcsd->todo_mask;
+}
+
+static int khvcsd(void *unused)
+{
+       struct hvcs_struct *hvcsd = NULL;
+       struct list_head *element;
+       struct list_head *safe_temp;
+       int hvcs_todo_mask;
+       unsigned long structs_flags;
+
+       __set_current_state(TASK_RUNNING);
+
+       do {
+               hvcs_todo_mask = 0;
+               hvcs_kicked = 0;
+               wmb();
+
+               spin_lock_irqsave(&hvcs_structs_lock, structs_flags);
+               list_for_each_safe(element, safe_temp, &hvcs_structs) {
+                       hvcsd = list_entry(element, struct hvcs_struct, next);
+                               hvcs_todo_mask |= hvcs_io(hvcsd);
+               }
+               spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags);
+
+               /*
+                * If any of the hvcs adapters want to try a write or quick read
+                * don't schedule(), yield a smidgen then execute the hvcs_io
+                * thread again for those that want the write.
+                */
+                if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) {
+                       yield();
+                       continue;
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!hvcs_kicked)
+                       schedule();
+               __set_current_state(TASK_RUNNING);
+       } while (!kthread_should_stop());
+
+       return 0;
+}
+
+static struct vio_device_id hvcs_driver_table[] __devinitdata= {
+       {"serial-server", "hvterm2"},
+       { 0, }
+};
+MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
+
+/* callback when the kboject ref count reaches zero */
+static void destroy_hvcs_struct(struct kobject *kobj)
+{
+       struct hvcs_struct *hvcsd = from_kobj(kobj);
+       struct vio_dev *vdev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       /* the list_del poisons the pointers */
+       list_del(&(hvcsd->next));
+
+       if (hvcsd->connected == 1) {
+               hvcs_partner_free(hvcsd);
+               printk(KERN_INFO "HVCS: Closed vty-server@%X and"
+                               " partner vty@%X:%d connection.\n",
+                               hvcsd->vdev->unit_address,
+                               hvcsd->p_unit_address,
+                               (unsigned int)hvcsd->p_partition_ID);
+       }
+       printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n",
+                       hvcsd->vdev->unit_address);
+
+       vdev = hvcsd->vdev;
+       hvcsd->vdev = NULL;
+
+       hvcsd->p_unit_address = 0;
+       hvcsd->p_partition_ID = 0;
+       memset(&hvcsd->p_location_code[0], 0x00, CLC_LENGTH);
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       hvcs_remove_device_attrs(vdev);
+
+       kfree(hvcsd);
+}
+
+/* This function must be called with hvcsd->lock held. */
+static void hvcs_final_close(struct hvcs_struct *hvcsd)
+{
+       vio_disable_interrupts(hvcsd->vdev);
+       free_irq(hvcsd->vdev->irq, hvcsd);
+
+       hvcsd->todo_mask = 0;
+
+       /* These two may be redundant if the operation was a close. */
+       if (hvcsd->tty) {
+               hvcsd->tty->driver_data = NULL;
+               hvcsd->tty = NULL;
+       }
+
+       hvcsd->open_count = 0;
+
+       memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
+       hvcsd->chars_in_buffer = 0;
+}
+
+static struct kobj_type hvcs_kobj_type = {
+       .release = destroy_hvcs_struct,
+};
+
+static int __devinit hvcs_probe(
+       struct vio_dev *dev,
+       const struct vio_device_id *id)
+{
+       struct hvcs_struct *hvcsd;
+       unsigned long structs_flags;
+
+       if (!dev || !id) {
+               printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
+               return -EPERM;
+       }
+
+       hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL);
+       if (!hvcsd) {
+               return -ENODEV;
+       }
+
+       /* hvcsd->tty is zeroed out with the memset */
+       memset(hvcsd, 0x00, sizeof(*hvcsd));
+
+       hvcsd->lock = SPIN_LOCK_UNLOCKED;
+       /* Automatically incs the refcount the first time */
+       kobject_init(&hvcsd->kobj);
+       /* Set up the callback for terminating the hvcs_struct's life */
+       hvcsd->kobj.ktype = &hvcs_kobj_type;
+
+       hvcsd->vdev = dev;
+       dev->dev.driver_data = hvcsd;
+
+       hvcsd->index = ++hvcs_struct_count;
+       hvcsd->chars_in_buffer = 0;
+       hvcsd->todo_mask = 0;
+       hvcsd->connected = 0;
+
+       /*
+        * This will populate the hvcs_struct's partner info fields for the
+        * first time.
+        */
+       if (hvcs_get_pi(hvcsd)) {
+               printk(KERN_ERR "HVCS: Failed to fetch partner"
+                       " info for vty-server@%X on device probe.\n",
+                       hvcsd->vdev->unit_address);
+       }
+
+       /*
+        * If a user app opens a tty that corresponds to this vty-server before
+        * the hvcs_struct has been added to the devices list then the user app
+        * will get -ENODEV.
+        */
+
+       spin_lock_irqsave(&hvcs_structs_lock, structs_flags);
+
+       list_add_tail(&(hvcsd->next), &hvcs_structs);
+
+       spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags);
+
+       hvcs_create_device_attrs(hvcsd);
+
+       printk(KERN_INFO "HVCS: Added vty-server@%X.\n", dev->unit_address);
+
+       /*
+        * DON'T enable interrupts here because there is no user to receive the
+        * data.
+        */
+       return 0;
+}
+
+static int __devexit hvcs_remove(struct vio_dev *dev)
+{
+       struct hvcs_struct *hvcsd = dev->dev.driver_data;
+       unsigned long flags;
+       struct kobject *kobjp;
+       struct tty_struct *tty;
+
+       if (!hvcsd)
+               return -ENODEV;
+
+       /* By this time the vty-server won't be getting any more interrups */
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       tty = hvcsd->tty;
+
+       kobjp = &hvcsd->kobj;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       /*
+        * Let the last holder of this object cause it to be removed, which
+        * would probably be tty_hangup below.
+        */
+       kobject_put (kobjp);
+
+       /*
+        * The hangup is a scheduled function which will auto chain call
+        * hvcs_hangup.  The tty should always be valid at this time unless a
+        * simultaneous tty close already cleaned up the hvcs_struct.
+        */
+       if (tty)
+               tty_hangup(tty);
+
+       printk(KERN_INFO "HVCS: vty-server@%X removed from the"
+                       " vio bus.\n", dev->unit_address);
+       return 0;
+};
+
+static struct vio_driver hvcs_vio_driver = {
+       .name           = hvcs_driver_name,
+       .id_table       = hvcs_driver_table,
+       .probe          = hvcs_probe,
+       .remove         = hvcs_remove,
+};
+
+/* Only called from hvcs_get_pi please */
+static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd)
+{
+       int clclength;
+
+       hvcsd->p_unit_address = pi->unit_address;
+       hvcsd->p_partition_ID  = pi->partition_ID;
+       clclength = strlen(&pi->location_code[0]);
+       if (clclength > CLC_LENGTH - 1)
+               clclength = CLC_LENGTH - 1;
+
+       /* copy the null-term char too */
+       strncpy(&hvcsd->p_location_code[0],
+                       &pi->location_code[0], clclength + 1);
+}
+
+/*
+ * Traverse the list and add the partner info that is found to the hvcs_struct
+ * struct entry. NOTE: At this time I know that partner info will return a
+ * single entry but in the future there may be multiple partner info entries per
+ * vty-server and you'll want to zero out that list and reset it.  If for some
+ * reason you have an old version of this driver but there IS more than one
+ * partner info then hvcsd->p_* will hold the last partner info data from the
+ * firmware query.  A good way to update this code would be to replace the three
+ * partner info fields in hvcs_struct with a list of hvcs_partner_info
+ * instances.
+ *
+ * This function must be called with the hvcsd->lock held.
+ */
+static int hvcs_get_pi(struct hvcs_struct *hvcsd)
+{
+       /* struct hvcs_partner_info *head_pi = NULL; */
+       struct hvcs_partner_info *pi = NULL;
+       unsigned int unit_address = hvcsd->vdev->unit_address;
+       struct list_head head;
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcs_pi_lock, flags);
+       if (!hvcs_pi_buff) {
+               spin_unlock_irqrestore(&hvcs_pi_lock, flags);
+               return -EFAULT;
+       }
+       retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff);
+       spin_unlock_irqrestore(&hvcs_pi_lock, flags);
+       if (retval) {
+               printk(KERN_ERR "HVCS: Failed to fetch partner"
+                       " info for vty-server@%x.\n", unit_address);
+               return retval;
+       }
+
+       /* nixes the values if the partner vty went away */
+       hvcsd->p_unit_address = 0;
+       hvcsd->p_partition_ID = 0;
+
+       list_for_each_entry(pi, &head, node)
+               hvcs_set_pi(pi, hvcsd);
+
+       hvcs_free_partner_info(&head);
+       return 0;
+}
+
+/*
+ * This function is executed by the driver "rescan" sysfs entry.  It shouldn't
+ * be executed elsewhere, in order to prevent deadlock issues.
+ */
+static int hvcs_rescan_devices_list(void)
+{
+       struct hvcs_struct *hvcsd = NULL;
+       unsigned long flags;
+       unsigned long structs_flags;
+
+       spin_lock_irqsave(&hvcs_structs_lock, structs_flags);
+
+       list_for_each_entry(hvcsd, &hvcs_structs, next) {
+               spin_lock_irqsave(&hvcsd->lock, flags);
+               hvcs_get_pi(hvcsd);
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags);
+
+       return 0;
+}
+
+/*
+ * Farm this off into its own function because it could be more complex once
+ * multiple partners support is added. This function should be called with
+ * the hvcsd->lock held.
+ */
+static int hvcs_has_pi(struct hvcs_struct *hvcsd)
+{
+       if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID))
+               return 0;
+       return 1;
+}
+
+/*
+ * NOTE: It is possible that the super admin removed a partner vty and then
+ * added a different vty as the new partner.
+ *
+ * This function must be called with the hvcsd->lock held.
+ */
+static int hvcs_partner_connect(struct hvcs_struct *hvcsd)
+{
+       int retval;
+       unsigned int unit_address = hvcsd->vdev->unit_address;
+
+       /*
+        * If there wasn't any pi when the device was added it doesn't meant
+        * there isn't any now.  This driver isn't notified when a new partner
+        * vty is added to a vty-server so we discover changes on our own.
+        * Please see comments in hvcs_register_connection() for justification
+        * of this bizarre code.
+        */
+       retval = hvcs_register_connection(unit_address,
+                       hvcsd->p_partition_ID,
+                       hvcsd->p_unit_address);
+       if (!retval) {
+               hvcsd->connected = 1;
+               return 0;
+       } else if (retval != -EINVAL)
+               return retval;
+
+       /*
+        * As per the spec re-get the pi and try again if -EINVAL after the
+        * first connection attempt.
+        */
+       if (hvcs_get_pi(hvcsd))
+               return -ENOMEM;
+
+       if (!hvcs_has_pi(hvcsd))
+               return -ENODEV;
+
+       retval = hvcs_register_connection(unit_address,
+                       hvcsd->p_partition_ID,
+                       hvcsd->p_unit_address);
+       if (retval != -EINVAL) {
+               hvcsd->connected = 1;
+               return retval;
+       }
+
+       /*
+        * EBUSY is the most likely scenario though the vty could have been
+        * removed or there really could be an hcall error due to the parameter
+        * data but thanks to ambiguous firmware return codes we can't really
+        * tell.
+        */
+       printk(KERN_INFO "HVCS: vty-server or partner"
+                       " vty is busy.  Try again later.\n");
+       return -EBUSY;
+}
+
+/* This function must be called with the hvcsd->lock held */
+static void hvcs_partner_free(struct hvcs_struct *hvcsd)
+{
+       int retval;
+       do {
+               retval = hvcs_free_connection(hvcsd->vdev->unit_address);
+       } while (retval == -EBUSY);
+       hvcsd->connected = 0;
+}
+
+/* This helper function must be called WITHOUT the hvcsd->lock held */
+static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
+               unsigned int irq, struct vio_dev *vdev)
+{
+       unsigned long flags;
+
+       /*
+        * It is possible that the vty-server was removed between the time that
+        * the conn was registered and now.
+        */
+       if (!request_irq(irq, &hvcs_handle_interrupt,
+                               SA_INTERRUPT, "ibmhvcs", hvcsd)) {
+               /*
+                * It is possible the vty-server was removed after the irq was
+                * requested but before we have time to enable interrupts.
+                */
+               if (vio_enable_interrupts(vdev) == H_Success)
+                       return 0;
+               else {
+                       printk(KERN_ERR "HVCS: int enable failed for"
+                                       " vty-server@%X.\n", unit_address);
+                       free_irq(irq, hvcsd);
+               }
+       } else
+               printk(KERN_ERR "HVCS: irq req failed for"
+                               " vty-server@%X.\n", unit_address);
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       hvcs_partner_free(hvcsd);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       return -ENODEV;
+
+}
+
+/*
+ * This always increments the kobject ref count if the call is successful.
+ * Please remember to dec when you are done with the instance.
+ *
+ * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
+ * calling this function or you will get deadlock.
+ */
+struct hvcs_struct *hvcs_get_by_index(int index)
+{
+       struct hvcs_struct *hvcsd = NULL;
+       struct list_head *element;
+       struct list_head *safe_temp;
+       unsigned long flags;
+       unsigned long structs_flags;
+
+       spin_lock_irqsave(&hvcs_structs_lock, structs_flags);
+       /* We can immediately discard OOB requests */
+       if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
+               list_for_each_safe(element, safe_temp, &hvcs_structs) {
+                       hvcsd = list_entry(element, struct hvcs_struct, next);
+                       spin_lock_irqsave(&hvcsd->lock, flags);
+                       if (hvcsd->index == index) {
+                               kobject_get(&hvcsd->kobj);
+                               spin_unlock_irqrestore(&hvcsd->lock, flags);
+                               spin_unlock_irqrestore(&hvcs_structs_lock,
+                                               structs_flags);
+                               return hvcsd;
+                       }
+                       spin_unlock_irqrestore(&hvcsd->lock, flags);
+               }
+               hvcsd = NULL;
+       }
+
+       spin_unlock_irqrestore(&hvcs_structs_lock, structs_flags);
+       return hvcsd;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+       struct hvcs_struct *hvcsd = NULL;
+       int retval = 0;
+       unsigned long flags;
+       unsigned int irq;
+       struct vio_dev *vdev;
+       unsigned long unit_address;
+
+       if (tty->driver_data)
+               goto fast_open;
+
+       /*
+        * Is there a vty-server that shares the same index?
+        * This function increments the kobject index.
+        */
+       if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+               printk(KERN_WARNING "HVCS: open failed, no index.\n");
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       if (hvcsd->connected == 0)
+               if ((retval = hvcs_partner_connect(hvcsd)))
+                       goto error_release;
+
+       hvcsd->open_count = 1;
+       hvcsd->tty = tty;
+       tty->driver_data = hvcsd;
+
+       /*
+        * Set this driver to low latency so that we actually have a chance at
+        * catching a throttled TTY after we flip_buffer_push.  Otherwise the
+        * flush_to_async may not execute until after the kernel_thread has
+        * yielded and resumed the next flip_buffer_push resulting in data
+        * loss.
+        */
+       tty->low_latency = 1;
+
+       memset(&hvcsd->buffer[0], 0x3F, HVCS_BUFF_LEN);
+
+       /*
+        * Save these in the spinlock for the enable operations that need them
+        * outside of the spinlock.
+        */
+       irq = hvcsd->vdev->irq;
+       vdev = hvcsd->vdev;
+       unit_address = hvcsd->vdev->unit_address;
+
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       /*
+        * This must be done outside of the spinlock because it requests irqs
+        * and will grab the spinlcok and free the connection if it fails.
+        */
+       if ((hvcs_enable_device(hvcsd, unit_address, irq, vdev))) {
+               kobject_put(&hvcsd->kobj);
+               printk(KERN_WARNING "HVCS: enable device failed.\n");
+               return -ENODEV;
+       }
+
+       goto open_success;
+
+fast_open:
+       hvcsd = tty->driver_data;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       if (!kobject_get(&hvcsd->kobj)) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               printk(KERN_ERR "HVCS: Kobject of open"
+                       " hvcs doesn't exist.\n");
+               return -EFAULT; /* Is this the right return value? */
+       }
+
+       hvcsd->open_count++;
+
+       hvcsd->todo_mask |= HVCS_SCHED_READ;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+open_success:
+       hvcs_kick();
+
+       printk(KERN_INFO "HVCS: vty-server@%X opened.\n",
+               hvcsd->vdev->unit_address );
+
+       return 0;
+
+error_release:
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       kobject_put(&hvcsd->kobj);
+
+       printk(KERN_WARNING "HVCS: HVCS partner connect failed.\n");
+       return retval;
+}
+
+static void hvcs_close(struct tty_struct *tty, struct file *filp)
+{
+       struct hvcs_struct *hvcsd;
+       unsigned long flags;
+       struct kobject *kobjp;
+
+       /*
+        * Is someone trying to close the file associated with this device after
+        * we have hung up?  If so tty->driver_data wouldn't be valid.
+        */
+       if (tty_hung_up_p(filp))
+               return;
+
+       /*
+        * No driver_data means that this close was probably issued after a
+        * failed hvcs_open by the tty layer's release_dev() api and we can just
+        * exit cleanly.
+        */
+       if (!tty->driver_data)
+               return;
+
+       hvcsd = tty->driver_data;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       if (--hvcsd->open_count == 0) {
+
+               /*
+                * This line is important because it tells hvcs_open that this
+                * device needs to be re-configured the next time hvcs_open is
+                * called.
+                */
+               hvcsd->tty->driver_data = NULL;
+
+               /*
+                * NULL this early so that the kernel_thread doesn't try to
+                * execute any operations on the TTY even though it is obligated
+                * to deliver any pending I/O to the hypervisor.
+                */
+               hvcsd->tty = NULL;
+
+               /*
+                * Block the close until all the buffered data has been
+                * delivered.
+                */
+               while(hvcsd->chars_in_buffer) {
+                       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+                       /*
+                        * Give the kernel thread the hvcs_struct so that it can
+                        * try to deliver the remaining data but block the close
+                        * operation by spinning in this function so that other
+                        * tty operations have to wait.
+                        */
+                       yield();
+                       spin_lock_irqsave(&hvcsd->lock, flags);
+               }
+
+               hvcs_final_close(hvcsd);
+
+       } else if (hvcsd->open_count < 0) {
+               printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
+                               " is missmanaged.\n",
+                       hvcsd->vdev->unit_address, hvcsd->open_count);
+       }
+       kobjp = &hvcsd->kobj;
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       kobject_put(kobjp);
+}
+
+static void hvcs_hangup(struct tty_struct * tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+       int temp_open_count;
+       struct kobject *kobjp;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       /* Preserve this so that we know how many kobject refs to put */
+       temp_open_count = hvcsd->open_count;
+
+       /*
+        * Don't kobject put inside the spinlock because the destruction
+        * callback may use the spinlock and it may get called before the
+        * spinlock has been released.  Get a pointer to the kobject and
+        * kobject_put on that instead.
+        */
+       kobjp = &hvcsd->kobj;
+
+       /* Calling this will drop any buffered data on the floor. */
+       hvcs_final_close(hvcsd);
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+
+       /*
+        * We need to kobject_put() for every open_count we have since the
+        * tty_hangup() function doesn't invoke a close per open connection on a
+        * non-console device.
+        */
+       while(temp_open_count) {
+               --temp_open_count;
+               /*
+                * The final put will trigger destruction of the hvcs_struct.
+                * NOTE:  If this hangup was signaled from user space then the
+                * final put will never happen.
+                */
+               kobject_put(kobjp);
+       }
+}
+
+/*
+ * NOTE: This is almost always from_user since user level apps interact with the
+ * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by
+ * hvcs_remove (which removes the target device and executes tty_hangup()) that
+ * tty_hangup will allow hvcs_write time to complete execution before it
+ * terminates our device.
+ */
+static int hvcs_write(struct tty_struct *tty, int from_user,
+               const unsigned char *buf, int count)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned int unit_address;
+       unsigned char *charbuf;
+       unsigned long flags;
+       int total_sent = 0;
+       int tosend = 0;
+       int result = 0;
+
+       /*
+        * If they don't check the return code off of their open they may
+        * attempt this even if there is no connected device.
+        */
+       if (!hvcsd)
+               return -ENODEV;
+
+       /* Reasonable size to prevent user level flooding */
+       if (count > HVCS_MAX_FROM_USER) {
+               printk(KERN_WARNING "HVCS write: count being truncated to"
+                               " HVCS_MAX_FROM_USER.\n");
+               count = HVCS_MAX_FROM_USER;
+       }
+
+       if (!from_user)
+               charbuf = (unsigned char *)buf;
+       else {
+               charbuf = kmalloc(count, GFP_KERNEL);
+               if (!charbuf) {
+                       printk(KERN_WARNING "HVCS: write -ENOMEM.\n");
+                       return -ENOMEM;
+               }
+
+               if (copy_from_user(charbuf, buf, count)) {
+                       kfree(charbuf);
+                       printk(KERN_WARNING "HVCS: write -EFAULT.\n");
+                       return -EFAULT;
+               }
+       }
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       /*
+        * Somehow an open succedded but the device was removed or the
+        * connection terminated between the vty-server and partner vty during
+        * the middle of a write operation?  This is a crummy place to do this
+        * but we want to keep it all in the spinlock.
+        */
+       if (hvcsd->open_count <= 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               if (from_user)
+                       kfree(charbuf);
+               return -ENODEV;
+       }
+
+       unit_address = hvcsd->vdev->unit_address;
+
+       while (count > 0) {
+               tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer));
+               /*
+                * No more space, this probably means that the last call to
+                * hvcs_write() didn't succeed and the buffer was filled up.
+                */
+               if (!tosend)
+                       break;
+
+               memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer],
+                               &charbuf[total_sent],
+                               tosend);
+
+               hvcsd->chars_in_buffer += tosend;
+
+               result = 0;
+
+               /*
+                * If this is true then we don't want to try writing to the
+                * hypervisor because that is the kernel_threads job now.  We'll
+                * just add to the buffer.
+                */
+               if (!(hvcsd->todo_mask & HVCS_TRY_WRITE))
+                       /* won't send partial writes */
+                       result = hvc_put_chars(unit_address,
+                                       &hvcsd->buffer[0],
+                                       hvcsd->chars_in_buffer);
+
+               /*
+                * Since we know we have enough room in hvcsd->buffer for
+                * tosend we record that it was sent regardless of whether the
+                * hypervisor actually took it because we have it buffered.
+                */
+               total_sent+=tosend;
+               count-=tosend;
+               if (result == 0) {
+                       hvcsd->todo_mask |= HVCS_TRY_WRITE;
+                       hvcs_kick();
+                       break;
+               }
+
+               hvcsd->chars_in_buffer = 0;
+               /*
+                * Test after the chars_in_buffer reset otherwise this could
+                * deadlock our writes if hvc_put_chars fails.
+                */
+               if (result < 0)
+                       break;
+       }
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       if (from_user)
+               kfree(charbuf);
+
+       if (result == -1)
+               return -EIO;
+       else
+               return total_sent;
+}
+
+/*
+ * This is really asking how much can we guarentee that we can send or that we
+ * absolutely WILL BUFFER if we can't send it.  This driver MUST honor the
+ * return value, hence the reason for hvcs_struct buffering.
+ */
+static int hvcs_write_room(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+       int retval;
+
+       if (!hvcsd || hvcsd->open_count <= 0)
+               return 0;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+
+static int hvcs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = hvcsd->chars_in_buffer;
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+
+static struct tty_operations hvcs_ops = {
+       .open = hvcs_open,
+       .close = hvcs_close,
+       .hangup = hvcs_hangup,
+       .write = hvcs_write,
+       .write_room = hvcs_write_room,
+       .chars_in_buffer = hvcs_chars_in_buffer,
+       .unthrottle = hvcs_unthrottle,
+       .throttle = hvcs_throttle,
+};
+
+static int __init hvcs_module_init(void)
+{
+       int rc;
+       int num_ttys_to_alloc;
+
+       printk(KERN_INFO "Initializing %s\n", hvcs_driver_string);
+
+       /* Has the user specified an overload with an insmod param? */
+       if (hvcs_parm_num_devs <= 0 ||
+               (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) {
+               num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS;
+       } else
+               num_ttys_to_alloc = hvcs_parm_num_devs;
+
+       hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
+       if (!hvcs_tty_driver)
+               return -ENOMEM;
+
+       hvcs_tty_driver->owner = THIS_MODULE;
+
+       hvcs_tty_driver->driver_name = hvcs_driver_name;
+       hvcs_tty_driver->name = hvcs_device_node;
+
+       /*
+        * We'll let the system assign us a major number, indicated by leaving
+        * it blank.
+        */
+
+       hvcs_tty_driver->minor_start = HVCS_MINOR_START;
+       hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+
+       /*
+        * We role our own so that we DONT ECHO.  We can't echo because the
+        * device we are connecting to already echoes by default and this would
+        * throw us into a horrible recursive echo-echo-echo loop.
+        */
+       hvcs_tty_driver->init_termios = hvcs_tty_termios;
+       hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+
+       tty_set_operations(hvcs_tty_driver, &hvcs_ops);
+
+       /*
+        * The following call will result in sysfs entries that denote the
+        * dynamically assigned major and minor numbers for our devices.
+        */
+       if (tty_register_driver(hvcs_tty_driver)) {
+               printk(KERN_ERR "HVCS: registration "
+                       " as a tty driver failed.\n");
+               put_tty_driver(hvcs_tty_driver);
+               return rc;
+       }
+
+       hvcs_structs_lock = SPIN_LOCK_UNLOCKED;
+
+       hvcs_pi_lock = SPIN_LOCK_UNLOCKED;
+       hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+       hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
+       if (IS_ERR(hvcs_task)) {
+               printk("khvcsd creation failed.  Driver not loaded.\n");
+               kfree(hvcs_pi_buff);
+               put_tty_driver(hvcs_tty_driver);
+               return -EIO;
+       }
+
+       rc = vio_register_driver(&hvcs_vio_driver);
+
+       /*
+        * This needs to be done AFTER the vio_register_driver() call or else
+        * the kobjects won't be initialized properly.
+        */
+       hvcs_create_driver_attrs();
+
+       printk(KERN_INFO "HVCS: driver module inserted.\n");
+
+       return rc;
+}
+
+static void __exit hvcs_module_exit(void)
+{
+       unsigned long flags;
+
+       /*
+        * This driver receives hvcs_remove callbacks for each device upon
+        * module removal.
+        */
+
+       /*
+        * This synchronous operation  will wake the khvcsd kthread if it is
+        * asleep and will return when khvcsd has terminated.
+        */
+       kthread_stop(hvcs_task);
+
+       spin_lock_irqsave(&hvcs_pi_lock, flags);
+       kfree(hvcs_pi_buff);
+       hvcs_pi_buff = NULL;
+       spin_unlock_irqrestore(&hvcs_pi_lock, flags);
+
+       hvcs_remove_driver_attrs();
+
+       vio_unregister_driver(&hvcs_vio_driver);
+
+       tty_unregister_driver(hvcs_tty_driver);
+
+       put_tty_driver(hvcs_tty_driver);
+
+       printk(KERN_INFO "HVCS: driver module removed.\n");
+}
+
+module_init(hvcs_module_init);
+module_exit(hvcs_module_exit);
+
+static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
+{
+       return viod->dev.driver_data;
+}
+/* The sysfs interface for the driver and devices */
+
+static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%X\n", hvcsd->p_unit_address);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);
+
+static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);
+
+static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf,
+               size_t count)
+{
+       /*
+        * Don't need this feature at the present time because firmware doesn't
+        * yet support multiple partners.
+        */
+       printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n");
+       return -EPERM;
+}
+
+static ssize_t hvcs_current_vty_show(struct device *dev, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+
+static DEVICE_ATTR(current_vty,
+       S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);
+
+static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+
+       /* writing a '0' to this sysfs entry will result in the disconnect. */
+       if (simple_strtol(buf, NULL, 0) != 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+
+       if (hvcsd->open_count > 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               printk(KERN_INFO "HVCS: vterm state unchanged.  "
+                               "The hvcs device node is still in use.\n");
+               return -EPERM;
+       }
+
+       if (hvcsd->connected == 0) {
+               spin_unlock_irqrestore(&hvcsd->lock, flags);
+               printk(KERN_INFO "HVCS: vterm state unchanged. The"
+                               " vty-server is not connected to a vty.\n");
+               return -EPERM;
+       }
+
+       hvcs_partner_free(hvcsd);
+       printk(KERN_INFO "HVCS: Closed vty-server@%X and"
+                       " partner vty@%X:%d connection.\n",
+                       hvcsd->vdev->unit_address,
+                       hvcsd->p_unit_address,
+                       (unsigned int)hvcsd->p_partition_ID);
+
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return count;
+}
+
+static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf)
+{
+       struct vio_dev *viod = to_vio_dev(dev);
+       struct hvcs_struct *hvcsd = from_vio_dev(viod);
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       retval = sprintf(buf, "%d\n", hvcsd->connected);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       return retval;
+}
+static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR,
+               hvcs_vterm_state_show, hvcs_vterm_state_store);
+
+static struct attribute *hvcs_attrs[] = {
+       &dev_attr_partner_vtys.attr,
+       &dev_attr_partner_clcs.attr,
+       &dev_attr_current_vty.attr,
+       &dev_attr_vterm_state.attr,
+       NULL,
+};
+
+static struct attribute_group hvcs_attr_group = {
+       .attrs = hvcs_attrs,
+};
+
+static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd)
+{
+       struct vio_dev *vdev = hvcsd->vdev;
+       sysfs_create_group(&vdev->dev.kobj, &hvcs_attr_group);
+}
+
+static void hvcs_remove_device_attrs(struct vio_dev *vdev)
+{
+       sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
+}
+
+static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf)
+{
+       /* A 1 means it is updating, a 0 means it is done updating */
+       return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
+}
+
+static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf,
+               size_t count)
+{
+       if ((simple_strtol(buf, NULL, 0) != 1)
+               && (hvcs_rescan_status != 0))
+               return -EINVAL;
+
+       hvcs_rescan_status = 1;
+       printk(KERN_INFO "HVCS: rescanning partner info for all"
+               " vty-servers.\n");
+       hvcs_rescan_devices_list();
+       hvcs_rescan_status = 0;
+       return count;
+}
+static DRIVER_ATTR(rescan,
+       S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store);
+
+static void hvcs_create_driver_attrs(void)
+{
+       struct device_driver *driverfs = &(hvcs_vio_driver.driver);
+       driver_create_file(driverfs, &driver_attr_rescan);
+}
+
+static void hvcs_remove_driver_attrs(void)
+{
+       struct device_driver *driverfs = &(hvcs_vio_driver.driver);
+       driver_remove_file(driverfs, &driver_attr_rescan);
+}
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
new file mode 100644 (file)
index 0000000..ebcaf79
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * drivers/watchdog/ixp2000_wdt.c
+ *
+ * Watchdog driver for Intel IXP2000 network processors
+ *
+ * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
+ * The original version carries these notices:
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+static unsigned int heartbeat = 60;    /* (secs) Default is 1 minute */
+static unsigned long wdt_status;
+
+#define        WDT_IN_USE              0
+#define        WDT_OK_TO_CLOSE         1
+
+static unsigned long wdt_tick_rate;
+
+static void
+wdt_enable(void)
+{
+       ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
+       ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
+       ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
+       ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
+}
+
+static void
+wdt_disable(void)
+{
+       ixp2000_reg_write(IXP2000_T4_CTL, 0);
+}
+
+static void
+wdt_keepalive(void)
+{
+       ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
+}
+
+static int
+ixp2000_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       wdt_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t
+ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_keepalive();
+       }
+
+       return len;
+}
+
+
+static struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                               WDIOF_KEEPALIVEPING,
+       .identity       = "IXP2000 Watchdog",
+};
+
+static int
+ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                       unsigned long arg)
+{
+       int ret = -ENOIOCTLCMD;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > 60) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               heartbeat = time;
+               wdt_keepalive();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_enable();
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
+static int
+ixp2000_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+               wdt_disable();
+       } else {
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+                                       "timer will not stop\n");
+       }
+
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static struct file_operations ixp2000_wdt_fops =
+{
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = ixp2000_wdt_write,
+       .ioctl          = ixp2000_wdt_ioctl,
+       .open           = ixp2000_wdt_open,
+       .release        = ixp2000_wdt_release,
+};
+
+static struct miscdevice ixp2000_wdt_miscdev =
+{
+       .minor          = WATCHDOG_MINOR,
+       .name           = "IXP2000 Watchdog",
+       .fops           = &ixp2000_wdt_fops,
+};
+
+static int __init ixp2000_wdt_init(void)
+{
+       wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;;
+
+       return misc_register(&ixp2000_wdt_miscdev);
+}
+
+static void __exit ixp2000_wdt_exit(void)
+{
+       misc_deregister(&ixp2000_wdt_miscdev);
+}
+
+module_init(ixp2000_wdt_init);
+module_exit(ixp2000_wdt_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
+MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
new file mode 100644 (file)
index 0000000..b8e3d91
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * drivers/watchdog/ixp4xx_wdt.c
+ *
+ * Watchdog driver for Intel IXP4xx network processors
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+static int heartbeat = 60;     /* (secs) Default is 1 minute */
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
+
+#define        WDT_IN_USE              0
+#define        WDT_OK_TO_CLOSE         1
+
+static void
+wdt_enable(void)
+{
+       *IXP4XX_OSWK = IXP4XX_WDT_KEY;
+       *IXP4XX_OSWE = 0;
+       *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
+       *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
+       *IXP4XX_OSWK = 0;
+}
+
+static void
+wdt_disable(void)
+{
+       *IXP4XX_OSWK = IXP4XX_WDT_KEY;
+       *IXP4XX_OSWE = 0;
+       *IXP4XX_OSWK = 0;
+}
+
+static int
+ixp4xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       wdt_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t
+ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_enable();
+       }
+
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options        = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
+                         WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity       = "IXP4xx Watchdog",
+};
+
+
+static int
+ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                       unsigned long arg)
+{
+       int ret = -ENOIOCTLCMD;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(boot_status, (int *)arg);
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > 60) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               heartbeat = time;
+               wdt_enable();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_enable();
+               ret = 0;
+               break;
+       }
+       return ret;
+}
+
+static int
+ixp4xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+               wdt_disable();
+       } else {
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+                                       "timer will not stop\n");
+       }
+
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static struct file_operations ixp4xx_wdt_fops =
+{
+       .owner          = THIS_MODULE,
+       .write          = ixp4xx_wdt_write,
+       .ioctl          = ixp4xx_wdt_ioctl,
+       .open           = ixp4xx_wdt_open,
+       .release        = ixp4xx_wdt_release,
+};
+
+static struct miscdevice ixp4xx_wdt_miscdev =
+{
+       .minor          = WATCHDOG_MINOR,
+       .name           = "IXP4xx Watchdog",
+       .fops           = &ixp4xx_wdt_fops,
+};
+
+static int __init ixp4xx_wdt_init(void)
+{
+       int ret;
+       unsigned long processor_id;
+
+       asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
+       if (!(processor_id & 0xf)) {
+               printk("IXP4XXX Watchdog: Rev. A0 CPU detected - "
+                       "watchdog disabled\n");
+
+               return -ENODEV;
+       }
+
+       ret = misc_register(&ixp4xx_wdt_miscdev);
+       if (ret == 0)
+               printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+       boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
+                       WDIOF_CARDRESET : 0;
+
+       return ret;
+}
+
+static void __exit ixp4xx_wdt_exit(void)
+{
+       misc_deregister(&ixp4xx_wdt_miscdev);
+}
+
+
+module_init(ixp4xx_wdt_init);
+module_exit(ixp4xx_wdt_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
+MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
new file mode 100644 (file)
index 0000000..09e4f68
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Parse the EFI PCDP table to locate the console device.
+ *
+ * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
+ *     Khalid Aziz <khalid.aziz@hp.com>
+ *     Alex Williamson <alex.williamson@hp.com>
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/console.h>
+#include <linux/efi.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+#include "pcdp.h"
+
+static inline int
+uart_irq_supported(int rev, struct pcdp_uart *uart)
+{
+       if (rev < 3)
+               return uart->pci_func & PCDP_UART_IRQ;
+       return uart->flags & PCDP_UART_IRQ;
+}
+
+static inline int
+uart_pci(int rev, struct pcdp_uart *uart)
+{
+       if (rev < 3)
+               return uart->pci_func & PCDP_UART_PCI;
+       return uart->flags & PCDP_UART_PCI;
+}
+
+static inline int
+uart_active_high_low(int rev, struct pcdp_uart *uart)
+{
+       if (uart_pci(rev, uart) || uart->flags & PCDP_UART_ACTIVE_LOW)
+               return ACPI_ACTIVE_LOW;
+       return ACPI_ACTIVE_HIGH;
+}
+
+static inline int
+uart_edge_level(int rev, struct pcdp_uart *uart)
+{
+       if (uart_pci(rev, uart))
+               return ACPI_LEVEL_SENSITIVE;
+       if (rev < 3 || uart->flags & PCDP_UART_EDGE_SENSITIVE)
+               return ACPI_EDGE_SENSITIVE;
+       return ACPI_LEVEL_SENSITIVE;
+}
+
+static void __init
+setup_serial_console(int rev, struct pcdp_uart *uart)
+{
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       struct uart_port port;
+       static char options[16];
+       int mapsize = 64;
+
+       memset(&port, 0, sizeof(port));
+       port.uartclk = uart->clock_rate;
+       if (!port.uartclk)      /* some FW doesn't supply this */
+               port.uartclk = BASE_BAUD * 16;
+
+       if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+               port.mapbase = uart->addr.address;
+               port.membase = ioremap(port.mapbase, mapsize);
+               if (!port.membase) {
+                       printk(KERN_ERR "%s: couldn't ioremap 0x%lx-0x%lx\n",
+                               __FUNCTION__, port.mapbase, port.mapbase + mapsize);
+                       return;
+               }
+               port.iotype = UPIO_MEM;
+       } else if (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+               port.iobase = uart->addr.address;
+               port.iotype = UPIO_PORT;
+       } else
+               return;
+
+       switch (uart->pci_prog_intfc) {
+               case 0x0: port.type = PORT_8250;    break;
+               case 0x1: port.type = PORT_16450;   break;
+               case 0x2: port.type = PORT_16550;   break;
+               case 0x3: port.type = PORT_16650;   break;
+               case 0x4: port.type = PORT_16750;   break;
+               case 0x5: port.type = PORT_16850;   break;
+               case 0x6: port.type = PORT_16C950;  break;
+               default:  port.type = PORT_UNKNOWN; break;
+       }
+
+       port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+
+       if (uart_irq_supported(rev, uart)) {
+               port.irq = acpi_register_gsi(uart->gsi,
+                       uart_active_high_low(rev, uart),
+                       uart_edge_level(rev, uart));
+               port.flags |= UPF_AUTO_IRQ;  /* some FW reported wrong GSI */
+               if (uart_pci(rev, uart))
+                       port.flags |= UPF_SHARE_IRQ;
+       }
+
+       if (early_serial_setup(&port) < 0)
+               return;
+
+       snprintf(options, sizeof(options), "%lun%d", uart->baud,
+               uart->bits ? uart->bits : 8);
+       add_preferred_console("ttyS", port.line, options);
+
+       printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n",
+               port.iotype == UPIO_MEM ? "MMIO" : "I/O",
+               uart->addr.address, port.line, options);
+#endif
+}
+
+static void __init
+setup_vga_console(struct pcdp_vga *vga)
+{
+#ifdef CONFIG_VT
+#ifdef CONFIG_VGA_CONSOLE
+       if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
+               printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
+               return;
+       }
+
+       conswitchp = &vga_con;
+       printk(KERN_INFO "PCDP: VGA console\n");
+#endif
+#endif
+}
+
+void __init
+efi_setup_pcdp_console(char *cmdline)
+{
+       struct pcdp *pcdp;
+       struct pcdp_uart *uart;
+       struct pcdp_device *dev, *end;
+       int i, serial = 0;
+
+       pcdp = efi.hcdp;
+       if (!pcdp)
+               return;
+
+       printk(KERN_INFO "PCDP: v%d at 0x%p\n", pcdp->rev, pcdp);
+
+       if (pcdp->rev < 3) {
+               if (strstr(cmdline, "console=ttyS0") || efi_uart_console_only())
+                       serial = 1;
+       }
+
+       for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
+               if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
+                       if (uart->type == PCDP_CONSOLE_UART) {
+                               setup_serial_console(pcdp->rev, uart);
+                               return;
+                       }
+               }
+       }
+
+       end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
+       for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
+            dev < end;
+            dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
+               if (dev->flags & PCDP_PRIMARY_CONSOLE) {
+                       if (dev->type == PCDP_CONSOLE_VGA) {
+                               setup_vga_console((struct pcdp_vga *) dev);
+                               return;
+                       }
+               }
+       }
+}
+
+#ifdef CONFIG_IA64_EARLY_PRINTK_UART
+unsigned long
+hcdp_early_uart (void)
+{
+       efi_system_table_t *systab;
+       efi_config_table_t *config_tables;
+       unsigned long addr = 0;
+       struct pcdp *pcdp = 0;
+       struct pcdp_uart *uart;
+       int i;
+
+       systab = (efi_system_table_t *) ia64_boot_param->efi_systab;
+       if (!systab)
+               return 0;
+       systab = __va(systab);
+
+       config_tables = (efi_config_table_t *) systab->tables;
+       if (!config_tables)
+               return 0;
+       config_tables = __va(config_tables);
+
+       for (i = 0; i < systab->nr_tables; i++) {
+               if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
+                       pcdp = (struct pcdp *) config_tables[i].table;
+                       break;
+               }
+       }
+       if (!pcdp)
+               return 0;
+       pcdp = __va(pcdp);
+
+       for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
+               if (uart->type == PCDP_CONSOLE_UART) {
+                       addr = uart->addr.address;
+                       break;
+               }
+       }
+       return addr;
+}
+#endif /* CONFIG_IA64_EARLY_PRINTK_UART */
diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h
new file mode 100644 (file)
index 0000000..863bb6f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Definitions for PCDP-defined console devices
+ *
+ * v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf
+ * v2.0:  http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf
+ *
+ * (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
+ *     Khalid Aziz <khalid.aziz@hp.com>
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define PCDP_CONSOLE                   0
+#define PCDP_DEBUG                     1
+#define PCDP_CONSOLE_OUTPUT            2
+#define PCDP_CONSOLE_INPUT             3
+
+#define PCDP_UART                      (0 << 3)
+#define PCDP_VGA                       (1 << 3)
+#define PCDP_USB                       (2 << 3)
+
+/* pcdp_uart.type and pcdp_device.type */
+#define PCDP_CONSOLE_UART              (PCDP_UART | PCDP_CONSOLE)
+#define PCDP_DEBUG_UART                        (PCDP_UART | PCDP_DEBUG)
+#define PCDP_CONSOLE_VGA               (PCDP_VGA  | PCDP_CONSOLE_OUTPUT)
+#define PCDP_CONSOLE_USB               (PCDP_USB  | PCDP_CONSOLE_INPUT)
+
+/* pcdp_uart.flags */
+#define PCDP_UART_EDGE_SENSITIVE       (1 << 0)
+#define PCDP_UART_ACTIVE_LOW           (1 << 1)
+#define PCDP_UART_PRIMARY_CONSOLE      (1 << 2)
+#define PCDP_UART_IRQ                  (1 << 6) /* in pci_func for rev < 3 */
+#define PCDP_UART_PCI                  (1 << 7) /* in pci_func for rev < 3 */
+
+struct pcdp_uart {
+       u8                              type;
+       u8                              bits;
+       u8                              parity;
+       u8                              stop_bits;
+       u8                              pci_seg;
+       u8                              pci_bus;
+       u8                              pci_dev;
+       u8                              pci_func;
+       u64                             baud;
+       struct acpi_generic_address     addr;
+       u16                             pci_dev_id;
+       u16                             pci_vendor_id;
+       u32                             gsi;
+       u32                             clock_rate;
+       u8                              pci_prog_intfc;
+       u8                              flags;
+};
+
+struct pcdp_vga {
+       u8                      count;          /* address space descriptors */
+};
+
+/* pcdp_device.flags */
+#define PCDP_PRIMARY_CONSOLE   1
+
+struct pcdp_device {
+       u8                      type;
+       u8                      flags;
+       u16                     length;
+       u16                     efi_index;
+};
+
+struct pcdp {
+       u8                      signature[4];
+       u32                     length;
+       u8                      rev;            /* PCDP v2.0 is rev 3 */
+       u8                      chksum;
+       u8                      oemid[6];
+       u8                      oem_tabid[8];
+       u32                     oem_rev;
+       u8                      creator_id[4];
+       u32                     creator_rev;
+       u32                     num_uarts;
+       struct pcdp_uart        uart[0];        /* actual size is num_uarts */
+       /* remainder of table is pcdp_device structures */
+};
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
new file mode 100644 (file)
index 0000000..03a955c
--- /dev/null
@@ -0,0 +1,359 @@
+/**
+ *
+ * $Id: phram.c,v 1.2 2004/08/09 13:19:44 dwmw2 Exp $
+ *
+ * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
+ * 07/2003     rewritten by Joern Engel <joern@wh.fh-wedel.de>
+ *
+ * DISCLAIMER:  This driver makes use of Rusty's excellent module code,
+ * so it will not work for 2.4 without changes and it wont work for 2.4
+ * as a module without major changes.  Oh well!
+ *
+ * Usage:
+ *
+ * one commend line parameter per device, each in the form:
+ *   phram=<name>,<start>,<len>
+ * <name> may be up to 63 characters.
+ * <start> and <len> can be octal, decimal or hexadecimal.  If followed
+ * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
+ * gigabytes.
+ *
+ */
+
+#include <asm/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mtd/mtd.h>
+
+#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
+
+struct phram_mtd_list {
+       struct list_head list;
+       struct mtd_info *mtdinfo;
+};
+
+static LIST_HEAD(phram_list);
+
+
+
+int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (instr->addr + instr->len > mtd->size)
+               return -EINVAL;
+       
+       memset(start + instr->addr, 0xff, instr->len);
+
+       /* This'll catch a few races. Free the thing before returning :) 
+        * I don't feel at all ashamed. This kind of thing is possible anyway
+        * with flash, but unlikely.
+        */
+
+       instr->state = MTD_ERASE_DONE;
+
+       mtd_erase_callback(instr);
+
+       return 0;
+}
+
+int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char **mtdbuf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (from + len > mtd->size)
+               return -EINVAL;
+       
+       *mtdbuf = start + from;
+       *retlen = len;
+       return 0;
+}
+
+void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+}
+
+int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char *buf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (from + len > mtd->size)
+               return -EINVAL;
+       
+       memcpy(buf, start + from, len);
+
+       *retlen = len;
+       return 0;
+}
+
+int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
+               size_t *retlen, const u_char *buf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (to + len > mtd->size)
+               return -EINVAL;
+       
+       memcpy(start + to, buf, len);
+
+       *retlen = len;
+       return 0;
+}
+
+
+
+static void unregister_devices(void)
+{
+       struct phram_mtd_list *this;
+
+       list_for_each_entry(this, &phram_list, list) {
+               del_mtd_device(this->mtdinfo);
+               iounmap(this->mtdinfo->priv);
+               kfree(this->mtdinfo);
+               kfree(this);
+       }
+}
+
+static int register_device(char *name, unsigned long start, unsigned long len)
+{
+       struct phram_mtd_list *new;
+       int ret = -ENOMEM;
+
+       new = kmalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               goto out0;
+
+       new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+       if (!new->mtdinfo)
+               goto out1;
+       
+       memset(new->mtdinfo, 0, sizeof(struct mtd_info));
+
+       ret = -EIO;
+       new->mtdinfo->priv = ioremap(start, len);
+       if (!new->mtdinfo->priv) {
+               ERROR("ioremap failed\n");
+               goto out2;
+       }
+
+
+       new->mtdinfo->name = name;
+       new->mtdinfo->size = len;
+       new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
+        new->mtdinfo->erase = phram_erase;
+       new->mtdinfo->point = phram_point;
+       new->mtdinfo->unpoint = phram_unpoint;
+       new->mtdinfo->read = phram_read;
+       new->mtdinfo->write = phram_write;
+       new->mtdinfo->owner = THIS_MODULE;
+       new->mtdinfo->type = MTD_RAM;
+       new->mtdinfo->erasesize = 0x0;
+
+       ret = -EAGAIN;
+       if (add_mtd_device(new->mtdinfo)) {
+               ERROR("Failed to register new device\n");
+               goto out3;
+       }
+
+       list_add_tail(&new->list, &phram_list);
+       return 0;       
+
+out3:
+       iounmap(new->mtdinfo->priv);
+out2:
+       kfree(new->mtdinfo);
+out1:
+       kfree(new);
+out0:
+       return ret;
+}
+
+static int ustrtoul(const char *cp, char **endp, unsigned int base)
+{
+       unsigned long result = simple_strtoul(cp, endp, base);
+
+       switch (**endp) {
+       case 'G':
+               result *= 1024;
+       case 'M':
+               result *= 1024;
+       case 'k':
+               result *= 1024;
+               endp++;
+       }
+       return result;
+}
+
+static int parse_num32(uint32_t *num32, const char *token)
+{
+       char *endp;
+       unsigned long n;
+
+       n = ustrtoul(token, &endp, 0);
+       if (*endp)
+               return -EINVAL;
+
+       *num32 = n;
+       return 0;
+}
+
+static int parse_name(char **pname, const char *token)
+{
+       size_t len;
+       char *name;
+
+       len = strlen(token) + 1;
+       if (len > 64)
+               return -ENOSPC;
+
+       name = kmalloc(len, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       strcpy(name, token);
+
+       *pname = name;
+       return 0;
+}
+
+#define parse_err(fmt, args...) do {   \
+       ERROR(fmt , ## args);   \
+       return 0;               \
+} while (0)
+
+static int phram_setup(const char *val, struct kernel_param *kp)
+{
+       char buf[64+12+12], *str = buf;
+       char *token[3];
+       char *name;
+       uint32_t start;
+       uint32_t len;
+       int i, ret;
+
+       if (strnlen(val, sizeof(str)) >= sizeof(str))
+               parse_err("parameter too long\n");
+
+       strcpy(str, val);
+
+       for (i=0; i<3; i++)
+               token[i] = strsep(&str, ",");
+
+       if (str)
+               parse_err("too many arguments\n");
+
+       if (!token[2])
+               parse_err("not enough arguments\n");
+
+       ret = parse_name(&name, token[0]);
+       if (ret == -ENOMEM)
+               parse_err("out of memory\n");
+       if (ret == -ENOSPC)
+               parse_err("name too long\n");
+       if (ret)
+               return 0;
+
+       ret = parse_num32(&start, token[1]);
+       if (ret)
+               parse_err("illegal start address\n");
+
+       ret = parse_num32(&len, token[2]);
+       if (ret)
+               parse_err("illegal device length\n");
+
+       register_device(name, start, len);
+
+       return 0;
+}
+
+module_param_call(phram, phram_setup, NULL, NULL, 000);
+MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\"");
+
+/*
+ * Just for compatibility with slram, this is horrible and should go someday.
+ */
+static int __init slram_setup(const char *val, struct kernel_param *kp)
+{
+       char buf[256], *str = buf;
+
+       if (!val || !val[0])
+               parse_err("no arguments to \"slram=\"\n");
+
+       if (strnlen(val, sizeof(str)) >= sizeof(str))
+               parse_err("parameter too long\n");
+
+       strcpy(str, val);
+
+       while (str) {
+               char *token[3];
+               char *name;
+               uint32_t start;
+               uint32_t len;
+               int i, ret;
+
+               for (i=0; i<3; i++) {
+                       token[i] = strsep(&str, ",");
+                       if (token[i])
+                               continue;
+                       parse_err("wrong number of arguments to \"slram=\"\n");
+               }
+
+               /* name */
+               ret = parse_name(&name, token[0]);
+               if (ret == -ENOMEM)
+                       parse_err("of memory\n");
+               if (ret == -ENOSPC)
+                       parse_err("too long\n");
+               if (ret)
+                       return 1;
+
+               /* start */
+               ret = parse_num32(&start, token[1]);
+               if (ret)
+                       parse_err("illegal start address\n");
+
+               /* len */
+               if (token[2][0] == '+')
+                       ret = parse_num32(&len, token[2] + 1);
+               else
+                       ret = parse_num32(&len, token[2]);
+
+               if (ret)
+                       parse_err("illegal device length\n");
+
+               if (token[2][0] != '+') {
+                       if (len < start)
+                               parse_err("end < start\n");
+                       len -= start;
+               }
+
+               register_device(name, start, len);
+       }
+       return 1;
+}
+
+module_param_call(slram, slram_setup, NULL, NULL, 000);
+MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
+
+
+int __init init_phram(void)
+{
+       printk(KERN_ERR "phram loaded\n");
+       return 0;
+}
+
+static void __exit cleanup_phram(void)
+{
+       unregister_devices();
+}
+
+module_init(init_phram);
+module_exit(cleanup_phram);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_DESCRIPTION("MTD driver for physical RAM");
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
new file mode 100644 (file)
index 0000000..a26cc3a
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * ichxrom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: ichxrom.c,v 1.8 2004/07/16 17:43:11 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/mtd/cfi.h>
+
+#define xstr(s) str(s)
+#define str(s) #s
+#define MOD_NAME xstr(KBUILD_BASENAME)
+
+#define MTD_DEV_NAME_LENGTH 16
+
+#define RESERVE_MEM_REGION 0
+
+
+#define MANUFACTURER_INTEL     0x0089
+#define I82802AB       0x00ad
+#define I82802AC       0x00ac
+
+#define ICHX_FWH_REGION_START  0xFF000000UL
+#define ICHX_FWH_REGION_SIZE   0x01000000UL
+#define BIOS_CNTL      0x4e
+#define FWH_DEC_EN1    0xE3
+#define FWH_DEC_EN2    0xF0
+#define FWH_SEL1       0xE8
+#define FWH_SEL2       0xEE
+
+struct ichxrom_map_info {
+       struct map_info map;
+       struct mtd_info *mtd;
+       unsigned long window_addr;
+       struct pci_dev *pdev;
+       struct resource window_rsrc;
+       struct resource rom_rsrc;
+       char mtd_name[MTD_DEV_NAME_LENGTH];
+};
+
+static inline unsigned long addr(struct map_info *map, unsigned long ofs)
+{
+       unsigned long offset;
+       offset = ((8*1024*1024) - map->size) + ofs;
+       if (offset >= (4*1024*1024)) {
+               offset += 0x400000;
+       }
+       return map->map_priv_1 + 0x400000 + offset;
+}
+
+static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
+{
+       return addr - map->map_priv_1 + ICHX_FWH_REGION_START;
+}
+       
+static map_word ichxrom_read(struct map_info *map, unsigned long ofs)
+{
+       map_word val;
+       int i;
+       switch(map->bankwidth) {
+       case 1:  val.x[0] = __raw_readb(addr(map, ofs)); break;
+       case 2:  val.x[0] = __raw_readw(addr(map, ofs)); break;
+       case 4:  val.x[0] = __raw_readl(addr(map, ofs)); break;
+#if BITS_PER_LONG >= 64
+       case 8:  val.x[0] = __raw_readq(addr(map, ofs)); break;
+#endif
+       default: val.x[0] = 0; break;
+       }
+       for(i = 1; i < map_words(map); i++) {
+               val.x[i] = 0;
+       }
+       return val;
+}
+
+static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+       memcpy_fromio(to, addr(map, from), len);
+}
+
+static void ichxrom_write(struct map_info *map, map_word d, unsigned long ofs)
+{
+       switch(map->bankwidth) {
+       case 1: __raw_writeb(d.x[0], addr(map,ofs)); break;
+       case 2: __raw_writew(d.x[0], addr(map,ofs)); break;
+       case 4: __raw_writel(d.x[0], addr(map,ofs)); break;
+#if BITS_PER_LONG >= 64
+       case 8: __raw_writeq(d.x[0], addr(map,ofs)); break;
+#endif
+       }
+       mb();
+}
+
+static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+       memcpy_toio(addr(map, to), from, len);
+}
+
+static struct ichxrom_map_info ichxrom_map = {
+       .map = {
+               .name = MOD_NAME,
+               .phys = NO_XIP,
+               .size = 0,
+               .bankwidth = 1,
+               .read = ichxrom_read,
+               .copy_from = ichxrom_copy_from,
+               .write = ichxrom_write,
+               .copy_to = ichxrom_copy_to,
+               /* Firmware hubs only use vpp when being programmed
+                * in a factory setting.  So in-place programming
+                * needs to use a different method.
+                */
+       },
+       /* remaining fields of structure are initialized to 0 */
+};
+
+enum fwh_lock_state {
+       FWH_DENY_WRITE = 1,
+       FWH_IMMUTABLE  = 2,
+       FWH_DENY_READ  = 4,
+};
+
+static void ichxrom_cleanup(struct ichxrom_map_info *info)
+{
+       u16 word;
+
+       /* Disable writes through the rom window */
+       pci_read_config_word(info->pdev, BIOS_CNTL, &word);
+       pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1);
+
+       if (info->mtd) {
+               del_mtd_device(info->mtd);
+               map_destroy(info->mtd);
+               info->mtd = NULL;
+               info->map.virt = 0;
+       }
+       if (info->rom_rsrc.parent)
+               release_resource(&info->rom_rsrc);
+       if (info->window_rsrc.parent)
+               release_resource(&info->window_rsrc);
+
+       if (info->window_addr) {
+               iounmap((void *)(info->window_addr));
+               info->window_addr = 0;
+       }
+}
+
+
+static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
+       enum fwh_lock_state state)
+{
+       struct map_info *map = mtd->priv;
+       unsigned long start = ofs;
+       unsigned long end = start + len -1;
+
+       /* FIXME do I need to guard against concurrency here? */
+       /* round down to 64K boundaries */
+       start = start & ~0xFFFF;
+       end = end & ~0xFFFF;
+       while (start <= end) {
+               unsigned long ctrl_addr;
+               ctrl_addr = addr(map, start) - 0x400000 + 2;
+               writeb(state, ctrl_addr);
+               start = start + 0x10000;
+       }
+       return 0;
+}
+
+static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
+}
+
+static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       return ichxrom_set_lock_state(mtd, ofs, len, 0);
+}
+
+static int __devinit ichxrom_init_one (struct pci_dev *pdev,
+       const struct pci_device_id *ent)
+{
+       u16 word;
+       struct ichxrom_map_info *info = &ichxrom_map;
+       unsigned long map_size;
+       static char *probes[] = { "cfi_probe", "jedec_probe" };
+       struct cfi_private *cfi;
+
+       /* For now I just handle the ichx and I assume there
+        * are not a lot of resources up at the top of the address
+        * space.  It is possible to handle other devices in the
+        * top 16MB but it is very painful.  Also since
+        * you can only really attach a FWH to an ICHX there
+        * a number of simplifications you can make.
+        *
+        * Also you can page firmware hubs if an 8MB window isn't enough 
+        * but don't currently handle that case either.
+        */
+
+       info->pdev = pdev;
+
+       /*
+        * Try to reserve the window mem region.  If this fails then
+        * it is likely due to the window being "reseved" by the BIOS.
+        */
+       info->window_rsrc.name = MOD_NAME;
+       info->window_rsrc.start = ICHX_FWH_REGION_START;
+       info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1;
+       info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       if (request_resource(&iomem_resource, &info->window_rsrc)) {
+               info->window_rsrc.parent = NULL;
+               printk(KERN_ERR MOD_NAME
+                      " %s(): Unable to register resource"
+                      " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                      __func__,
+                      info->window_rsrc.start, info->window_rsrc.end);
+       }
+       
+       /* Enable writes through the rom window */
+       pci_read_config_word(pdev, BIOS_CNTL, &word);
+       if (!(word & 1)  && (word & (1<<1))) {
+               /* The BIOS will generate an error if I enable
+                * this device, so don't even try.
+                */
+               printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
+               goto failed;
+       }
+       pci_write_config_word(pdev, BIOS_CNTL, word | 1);
+
+
+       /* Map the firmware hub into my address space. */
+       /* Does this use too much virtual address space? */
+       info->window_addr = (unsigned long)ioremap(
+               ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
+       if (!info->window_addr) {
+               printk(KERN_ERR "Failed to ioremap\n");
+               goto failed;
+       }
+
+       /* For now assume the firmware has setup all relevant firmware
+        * windows.  We don't have enough information to handle this case
+        * intelligently.
+        */
+
+       /* FIXME select the firmware hub and enable a window to it. */
+
+       info->mtd = NULL;
+       info->map.map_priv_1 = info->window_addr;
+
+       /* Loop through the possible bankwidths */
+       for(ichxrom_map.map.bankwidth = 4; ichxrom_map.map.bankwidth; ichxrom_map.map.bankwidth >>= 1) {
+               map_size = ICHX_FWH_REGION_SIZE;
+               while(!info->mtd && (map_size > 0)) {
+                       int i;
+                       info->map.size = map_size;
+                       for(i = 0; i < sizeof(probes)/sizeof(char *); i++) {
+                               info->mtd = do_map_probe(probes[i], &ichxrom_map.map);
+                               if (info->mtd)
+                                       break;
+                       }
+                       map_size -= 512*1024;
+               }
+               if (info->mtd)
+                       break;
+       }
+       if (!info->mtd) {
+               goto failed;
+       }
+       cfi = ichxrom_map.map.fldrv_priv;
+       if ((cfi->mfr == MANUFACTURER_INTEL) && (
+                   (cfi->id == I82802AB) ||
+                   (cfi->id == I82802AC))) 
+       {
+               /* If it is a firmware hub put in the special lock
+                * and unlock routines.
+                */
+               info->mtd->lock = ichxrom_lock;
+               info->mtd->unlock = ichxrom_unlock;
+       }
+       if (info->mtd->size > info->map.size) {
+               printk(KERN_WARNING MOD_NAME " rom(%u) larger than window(%lu). fixing...\n",
+                      info->mtd->size, info->map.size);
+               info->mtd->size = info->map.size;
+       }
+               
+       info->mtd->owner = THIS_MODULE;
+       add_mtd_device(info->mtd);
+
+       if (info->window_rsrc.parent) {
+               /*
+                * Registering the MTD device in iomem may not be possible
+                * if there is a BIOS "reserved" and BUSY range.  If this
+                * fails then continue anyway.
+                */
+               snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
+                        "mtd%d", info->mtd->index);
+
+               info->rom_rsrc.name = info->mtd_name;
+               info->rom_rsrc.start = ICHX_FWH_REGION_START
+                       + ICHX_FWH_REGION_SIZE - map_size;
+               info->rom_rsrc.end = ICHX_FWH_REGION_START
+                       + ICHX_FWH_REGION_SIZE;
+               info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
+                       printk(KERN_ERR MOD_NAME
+                              ": cannot reserve MTD resource\n");
+                       info->rom_rsrc.parent = NULL;
+               }
+       }
+
+       return 0;
+
+ failed:
+       ichxrom_cleanup(info);
+       return -ENODEV;
+}
+
+
+static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
+{
+       struct ichxrom_map_info *info = &ichxrom_map;
+       u16 word;
+
+       del_mtd_device(info->mtd);
+       map_destroy(info->mtd);
+       info->mtd = NULL;
+       info->map.map_priv_1 = 0;
+
+       iounmap((void *)(info->window_addr));
+       info->window_addr = 0;
+
+       /* Disable writes through the rom window */
+       pci_read_config_word(pdev, BIOS_CNTL, &word);
+       pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
+
+#if RESERVE_MEM_REGION 
+       release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE);
+#endif
+}
+
+static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
+
+#if 0
+static struct pci_driver ichxrom_driver = {
+       .name =         MOD_NAME,
+       .id_table =     ichxrom_pci_tbl,
+       .probe =        ichxrom_init_one,
+       .remove =       ichxrom_remove_one,
+};
+#endif
+
+static struct pci_dev *mydev;
+int __init init_ichxrom(void)
+{
+       struct pci_dev *pdev;
+       struct pci_device_id *id;
+
+       pdev = NULL;
+       for (id = ichxrom_pci_tbl; id->vendor; id++) {
+               pdev = pci_find_device(id->vendor, id->device, NULL);
+               if (pdev) {
+                       break;
+               }
+       }
+       if (pdev) {
+               mydev = pdev;
+               return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
+       }
+       return -ENXIO;
+#if 0
+       return pci_module_init(&ichxrom_driver);
+#endif
+}
+
+static void __exit cleanup_ichxrom(void)
+{
+       ichxrom_remove_one(mydev);
+}
+
+module_init(init_ichxrom);
+module_exit(cleanup_ichxrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
new file mode 100644 (file)
index 0000000..0f7dedd
--- /dev/null
@@ -0,0 +1,1635 @@
+/* 
+ * drivers/mtd/nand/diskonchip.c
+ *
+ * (C) 2003 Red Hat, Inc.
+ * (C) 2004 Dan Brown <dan_brown@ieee.org>
+ * (C) 2004 Kalev Lember <kalev@smartlink.ee>
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
+ * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
+ *
+ * Interface to generic NAND code for M-Systems DiskOnChip devices
+ *
+ * $Id: diskonchip.c,v 1.34 2004/08/09 19:41:12 dbrown Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/inftl.h>
+
+/* Where to look for the devices? */
+#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#endif
+
+static unsigned long __initdata doc_locations[] = {
+#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
+#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
+       0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
+       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
+       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
+       0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
+#else /*  CONFIG_MTD_DOCPROBE_HIGH */
+       0xc8000, 0xca000, 0xcc000, 0xce000, 
+       0xd0000, 0xd2000, 0xd4000, 0xd6000,
+       0xd8000, 0xda000, 0xdc000, 0xde000, 
+       0xe0000, 0xe2000, 0xe4000, 0xe6000, 
+       0xe8000, 0xea000, 0xec000, 0xee000,
+#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
+#elif defined(__PPC__)
+       0xe4000000,
+#elif defined(CONFIG_MOMENCO_OCELOT)
+       0x2f000000,
+        0xff000000,
+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+        0xff000000,
+##else
+#warning Unknown architecture for DiskOnChip. No default probe locations defined
+#endif
+       0xffffffff };
+
+static struct mtd_info *doclist = NULL;
+
+struct doc_priv {
+       unsigned long virtadr;
+       unsigned long physadr;
+       u_char ChipID;
+       u_char CDSNControl;
+       int chips_per_floor; /* The number of chips detected on each floor */
+       int curfloor;
+       int curchip;
+       int mh0_page;
+       int mh1_page;
+       struct mtd_info *nextdoc;
+};
+
+/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
+   MediaHeader.  The spec says to just keep going, I think, but that's just
+   silly. */
+#define MAX_MEDIAHEADER_SCAN 8
+
+/* This is the syndrome computed by the HW ecc generator upon reading an empty
+   page, one with all 0xff for data and stored ecc code. */
+static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
+/* This is the ecc value computed by the HW ecc generator upon writing an empty
+   page, one with all 0xff for data. */
+static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
+
+#define INFTL_BBT_RESERVED_BLOCKS 4
+
+#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
+#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
+#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
+
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
+static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+
+static int debug=0;
+MODULE_PARM(debug, "i");
+
+static int try_dword=1;
+MODULE_PARM(try_dword, "i");
+
+static int no_ecc_failures=0;
+MODULE_PARM(no_ecc_failures, "i");
+
+static int no_autopart=0;
+MODULE_PARM(no_autopart, "i");
+
+#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
+static int inftl_bbt_write=1;
+#else
+static int inftl_bbt_write=0;
+#endif
+MODULE_PARM(inftl_bbt_write, "i");
+
+static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+MODULE_PARM(doc_config_location, "l");
+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
+
+static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
+{
+       volatile char dummy;
+       int i;
+       
+       for (i = 0; i < cycles; i++) {
+               if (DoC_is_Millennium(doc))
+                       dummy = ReadDOC(doc->virtadr, NOP);
+               else if (DoC_is_MillenniumPlus(doc))
+                       dummy = ReadDOC(doc->virtadr, Mplus_NOP);
+               else
+                       dummy = ReadDOC(doc->virtadr, DOCStatus);
+       }
+       
+}
+
+#define CDSN_CTRL_FR_B_MASK    (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct doc_priv *doc)
+{
+       unsigned long docptr = doc->virtadr;
+       unsigned long timeo = jiffies + (HZ * 10);
+
+       if(debug) printk("_DoC_WaitReady...\n");
+       /* Out-of-line routine to wait for chip response */
+       if (DoC_is_MillenniumPlus(doc)) {
+               while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+                       if (time_after(jiffies, timeo)) {
+                               printk("_DoC_WaitReady timed out.\n");
+                               return -EIO;
+                       }
+                       udelay(1);
+                       cond_resched();
+               }
+       } else {
+               while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+                       if (time_after(jiffies, timeo)) {
+                               printk("_DoC_WaitReady timed out.\n");
+                               return -EIO;
+                       }
+                       udelay(1);
+                       cond_resched();
+               }
+       }
+
+       return 0;
+}
+
+static inline int DoC_WaitReady(struct doc_priv *doc)
+{
+       unsigned long docptr = doc->virtadr;
+       int ret = 0;
+
+       if (DoC_is_MillenniumPlus(doc)) {
+               DoC_Delay(doc, 4);
+
+               if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
+                       /* Call the out-of-line routine to wait */
+                       ret = _DoC_WaitReady(doc);
+       } else {
+               DoC_Delay(doc, 4);
+
+               if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+                       /* Call the out-of-line routine to wait */
+                       ret = _DoC_WaitReady(doc);
+               DoC_Delay(doc, 2);
+       }
+
+       if(debug) printk("DoC_WaitReady OK\n");
+       return ret;
+}
+
+static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       if(debug)printk("write_byte %02x\n", datum);
+       WriteDOC(datum, docptr, CDSNSlowIO);
+       WriteDOC(datum, docptr, 2k_CDSN_IO);
+}
+
+static u_char doc2000_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       u_char ret;
+
+       ReadDOC(docptr, CDSNSlowIO);
+       DoC_Delay(doc, 2);
+       ret = ReadDOC(docptr, 2k_CDSN_IO);
+       if (debug) printk("read_byte returns %02x\n", ret);
+       return ret;
+}
+
+static void doc2000_writebuf(struct mtd_info *mtd, 
+                            const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+       if (debug)printk("writebuf of %d bytes: ", len);
+       for (i=0; i < len; i++) {
+               WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
+               if (debug && i < 16)
+                       printk("%02x ", buf[i]);
+       }
+       if (debug) printk("\n");
+}
+
+static void doc2000_readbuf(struct mtd_info *mtd, 
+                           u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       if (debug)printk("readbuf of %d bytes: ", len);
+
+       for (i=0; i < len; i++) {
+               buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
+       }
+}
+
+static void doc2000_readbuf_dword(struct mtd_info *mtd, 
+                           u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       if (debug) printk("readbuf_dword of %d bytes: ", len);
+
+       if (unlikely((((unsigned long)buf)|len) & 3)) {
+               for (i=0; i < len; i++) {
+                       *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
+               }
+       } else {
+               for (i=0; i < len; i+=4) {
+                       *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
+               }
+       }
+}
+
+static int doc2000_verifybuf(struct mtd_info *mtd, 
+                             const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       for (i=0; i < len; i++)
+               if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))
+                       return -EFAULT;
+       return 0;
+}
+
+static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       uint16_t ret;
+
+       doc200x_select_chip(mtd, nr);
+       doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
+       this->write_byte(mtd, NAND_CMD_READID);
+       doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
+       doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
+       this->write_byte(mtd, 0);
+       doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+
+       ret = this->read_byte(mtd) << 8;
+       ret |= this->read_byte(mtd);
+
+       if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
+               /* First chip probe. See if we get same results by 32-bit access */
+               union {
+                       uint32_t dword;
+                       uint8_t byte[4];
+               } ident;
+               unsigned long docptr = doc->virtadr;
+
+               doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
+               doc2000_write_byte(mtd, NAND_CMD_READID);
+               doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
+               doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
+               doc2000_write_byte(mtd, 0);
+               doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+
+               ident.dword = readl(docptr + DoC_2k_CDSN_IO);
+               if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
+                       printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
+                       this->read_buf = &doc2000_readbuf_dword;
+               }
+       }
+               
+       return ret;
+}
+
+static void __init doc2000_count_chips(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       uint16_t mfrid;
+       int i;
+
+       /* Max 4 chips per floor on DiskOnChip 2000 */
+       doc->chips_per_floor = 4;
+
+       /* Find out what the first chip is */
+       mfrid = doc200x_ident_chip(mtd, 0);
+
+       /* Find how many chips in each floor. */
+       for (i = 1; i < 4; i++) {
+               if (doc200x_ident_chip(mtd, i) != mfrid)
+                       break;
+       }
+       doc->chips_per_floor = i;
+       printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
+}
+
+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+       struct doc_priv *doc = (void *)this->priv;
+
+       int status;
+       
+       DoC_WaitReady(doc);
+       this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+       DoC_WaitReady(doc);
+       status = (int)this->read_byte(mtd);
+
+       return status;
+}
+
+static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       WriteDOC(datum, docptr, CDSNSlowIO);
+       WriteDOC(datum, docptr, Mil_CDSN_IO);
+       WriteDOC(datum, docptr, WritePipeTerm);
+}
+
+static u_char doc2001_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       //ReadDOC(docptr, CDSNSlowIO);
+       /* 11.4.5 -- delay twice to allow extended length cycle */
+       DoC_Delay(doc, 2);
+       ReadDOC(docptr, ReadPipeInit);
+       //return ReadDOC(docptr, Mil_CDSN_IO);
+       return ReadDOC(docptr, LastDataRead);
+}
+
+static void doc2001_writebuf(struct mtd_info *mtd, 
+                            const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       for (i=0; i < len; i++)
+               WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+       /* Terminate write pipeline */
+       WriteDOC(0x00, docptr, WritePipeTerm);
+}
+
+static void doc2001_readbuf(struct mtd_info *mtd, 
+                           u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       /* Start read pipeline */
+       ReadDOC(docptr, ReadPipeInit);
+
+       for (i=0; i < len-1; i++)
+               buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
+
+       /* Terminate read pipeline */
+       buf[i] = ReadDOC(docptr, LastDataRead);
+}
+
+static int doc2001_verifybuf(struct mtd_info *mtd, 
+                            const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       /* Start read pipeline */
+       ReadDOC(docptr, ReadPipeInit);
+
+       for (i=0; i < len-1; i++)
+               if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
+                       ReadDOC(docptr, LastDataRead);
+                       return i;
+               }
+       if (buf[i] != ReadDOC(docptr, LastDataRead))
+               return i;
+       return 0;
+}
+
+static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       u_char ret;
+
+        ReadDOC(docptr, Mplus_ReadPipeInit);
+        ReadDOC(docptr, Mplus_ReadPipeInit);
+        ret = ReadDOC(docptr, Mplus_LastDataRead);
+       if (debug) printk("read_byte returns %02x\n", ret);
+       return ret;
+}
+
+static void doc2001plus_writebuf(struct mtd_info *mtd, 
+                            const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       if (debug)printk("writebuf of %d bytes: ", len);
+       for (i=0; i < len; i++) {
+               WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+               if (debug && i < 16)
+                       printk("%02x ", buf[i]);
+       }
+       if (debug) printk("\n");
+}
+
+static void doc2001plus_readbuf(struct mtd_info *mtd, 
+                           u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       if (debug)printk("readbuf of %d bytes: ", len);
+
+       /* Start read pipeline */
+       ReadDOC(docptr, Mplus_ReadPipeInit);
+       ReadDOC(docptr, Mplus_ReadPipeInit);
+
+       for (i=0; i < len-2; i++) {
+               buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+               if (debug && i < 16)
+                       printk("%02x ", buf[i]);
+       }
+
+       /* Terminate read pipeline */
+       buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
+       if (debug && i < 16)
+               printk("%02x ", buf[len-2]);
+       buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
+       if (debug && i < 16)
+               printk("%02x ", buf[len-1]);
+       if (debug) printk("\n");
+}
+
+static int doc2001plus_verifybuf(struct mtd_info *mtd, 
+                            const u_char *buf, int len)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+
+       if (debug)printk("verifybuf of %d bytes: ", len);
+
+       /* Start read pipeline */
+       ReadDOC(docptr, Mplus_ReadPipeInit);
+       ReadDOC(docptr, Mplus_ReadPipeInit);
+
+       for (i=0; i < len-2; i++)
+               if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
+                       ReadDOC(docptr, Mplus_LastDataRead);
+                       ReadDOC(docptr, Mplus_LastDataRead);
+                       return i;
+               }
+       if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead))
+               return len-2;
+       if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead))
+               return len-1;
+       return 0;
+}
+
+static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int floor = 0;
+
+       if(debug)printk("select chip (%d)\n", chip);
+
+       if (chip == -1) {
+               /* Disable flash internally */
+               WriteDOC(0, docptr, Mplus_FlashSelect);
+               return;
+       }
+
+       floor = chip / doc->chips_per_floor;
+       chip -= (floor *  doc->chips_per_floor);
+
+       /* Assert ChipEnable and deassert WriteProtect */
+       WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
+       this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+       doc->curchip = chip;
+       doc->curfloor = floor;
+}
+
+static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int floor = 0;
+
+       if(debug)printk("select chip (%d)\n", chip);
+
+       if (chip == -1)
+               return;
+
+       floor = chip / doc->chips_per_floor;
+       chip -= (floor *  doc->chips_per_floor);
+
+       /* 11.4.4 -- deassert CE before changing chip */
+       doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
+
+       WriteDOC(floor, docptr, FloorSelect);
+       WriteDOC(chip, docptr, CDSNDeviceSelect);
+
+       doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
+
+       doc->curchip = chip;
+       doc->curfloor = floor;
+}
+
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       switch(cmd) {
+       case NAND_CTL_SETNCE:
+               doc->CDSNControl |= CDSN_CTRL_CE;
+               break;
+       case NAND_CTL_CLRNCE:
+               doc->CDSNControl &= ~CDSN_CTRL_CE;
+               break;
+       case NAND_CTL_SETCLE:
+               doc->CDSNControl |= CDSN_CTRL_CLE;
+               break;
+       case NAND_CTL_CLRCLE:
+               doc->CDSNControl &= ~CDSN_CTRL_CLE;
+               break;
+       case NAND_CTL_SETALE:
+               doc->CDSNControl |= CDSN_CTRL_ALE;
+               break;
+       case NAND_CTL_CLRALE:
+               doc->CDSNControl &= ~CDSN_CTRL_ALE;
+               break;
+       case NAND_CTL_SETWP:
+               doc->CDSNControl |= CDSN_CTRL_WP;
+               break;
+       case NAND_CTL_CLRWP:
+               doc->CDSNControl &= ~CDSN_CTRL_WP;
+               break;
+       }
+       if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
+       WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+       /* 11.4.3 -- 4 NOPs after CSDNControl write */
+       DoC_Delay(doc, 4);
+}
+
+static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       /*
+        * Must terminate write pipeline before sending any commands
+        * to the device.
+        */
+       if (command == NAND_CMD_PAGEPROG) {
+               WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+               WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+       }
+
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->oobblock) {
+                       /* OOB area */
+                       column -= mtd->oobblock;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               WriteDOC(readcmd, docptr, Mplus_FlashCmd);
+       }
+       WriteDOC(command, docptr, Mplus_FlashCmd);
+       WriteDOC(0, docptr, Mplus_WritePipeTerm);
+       WriteDOC(0, docptr, Mplus_WritePipeTerm);
+
+       if (column != -1 || page_addr != -1) {
+               /* Serially input address */
+               if (column != -1) {
+                       /* Adjust columns for 16 bit buswidth */
+                       if (this->options & NAND_BUSWIDTH_16)
+                               column >>= 1;
+                       WriteDOC(column, docptr, Mplus_FlashAddress);
+               }
+               if (page_addr != -1) {
+                       WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress);
+                       WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
+                       /* One more address cycle for higher density devices */
+                       if (this->chipsize & 0x0c000000) {
+                               WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
+                               printk("high density\n");
+                       }
+               }
+               WriteDOC(0, docptr, Mplus_WritePipeTerm);
+               WriteDOC(0, docptr, Mplus_WritePipeTerm);
+               /* deassert ALE */
+               if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID)
+                       WriteDOC(0, docptr, Mplus_FlashControl);
+       }
+
+       /* 
+        * program and erase have their own busy handlers
+        * status and sequential in needs no delay
+       */
+       switch (command) {
+
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+               return;
+
+       case NAND_CMD_RESET:
+               if (this->dev_ready)
+                       break;
+               udelay(this->chip_delay);
+               WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
+               WriteDOC(0, docptr, Mplus_WritePipeTerm);
+               WriteDOC(0, docptr, Mplus_WritePipeTerm);
+               while ( !(this->read_byte(mtd) & 0x40));
+               return;
+
+       /* This applies to read commands */
+       default:
+               /* 
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+               */
+               if (!this->dev_ready) {
+                       udelay (this->chip_delay);
+                       return;
+               }
+       }
+
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay (100);
+       /* wait until command is processed */
+       while (!this->dev_ready(mtd));
+}
+
+static int doc200x_dev_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       if (DoC_is_MillenniumPlus(doc)) {
+               /* 11.4.2 -- must NOP four times before checking FR/B# */
+               DoC_Delay(doc, 4);
+               if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+                       if(debug)
+                               printk("not ready\n");
+                       return 0;
+               }
+               if (debug)printk("was ready\n");
+               return 1;
+       } else {
+               /* 11.4.2 -- must NOP four times before checking FR/B# */
+               DoC_Delay(doc, 4);
+               if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+                       if(debug)
+                               printk("not ready\n");
+                       return 0;
+               }
+               /* 11.4.2 -- Must NOP twice if it's ready */
+               DoC_Delay(doc, 2);
+               if (debug)printk("was ready\n");
+               return 1;
+       }
+}
+
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+       /* This is our last resort if we couldn't find or create a BBT.  Just
+          pretend all blocks are good. */
+       return 0;
+}
+
+static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       /* Prime the ECC engine */
+       switch(mode) {
+       case NAND_ECC_READ:
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+               break;
+       case NAND_ECC_WRITE:
+               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+               break;
+       }
+}
+
+static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+
+       /* Prime the ECC engine */
+       switch(mode) {
+       case NAND_ECC_READ:
+               WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+               WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
+               break;
+       case NAND_ECC_WRITE:
+               WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+               break;
+       }
+}
+
+/* This code is only called on write */
+static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+                                unsigned char *ecc_code)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       int i;
+       int emptymatch = 1;
+
+       /* flush the pipeline */
+       if (DoC_is_2000(doc)) {
+               WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
+               WriteDOC(0, docptr, 2k_CDSN_IO);
+               WriteDOC(0, docptr, 2k_CDSN_IO);
+               WriteDOC(0, docptr, 2k_CDSN_IO);
+               WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+       } else if (DoC_is_MillenniumPlus(doc)) {
+               WriteDOC(0, docptr, Mplus_NOP);
+               WriteDOC(0, docptr, Mplus_NOP);
+               WriteDOC(0, docptr, Mplus_NOP);
+       } else {
+               WriteDOC(0, docptr, NOP);
+               WriteDOC(0, docptr, NOP);
+               WriteDOC(0, docptr, NOP);
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (DoC_is_MillenniumPlus(doc))
+                       ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+               else 
+                       ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+               if (ecc_code[i] != empty_write_ecc[i])
+                       emptymatch = 0;
+       }
+       if (DoC_is_MillenniumPlus(doc))
+               WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+       else
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+#if 0
+       /* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
+       if (emptymatch) {
+               /* Note: this somewhat expensive test should not be triggered
+                  often.  It could be optimized away by examining the data in
+                  the writebuf routine, and remembering the result. */
+               for (i = 0; i < 512; i++) {
+                       if (dat[i] == 0xff) continue;
+                       emptymatch = 0;
+                       break;
+               }
+       }
+       /* If emptymatch still =1, we do have an all-0xff data buffer.
+          Return all-0xff ecc value instead of the computed one, so
+          it'll look just like a freshly-erased page. */
+       if (emptymatch) memset(ecc_code, 0xff, 6);
+#endif
+       return 0;
+}
+
+static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+       int i, ret = 0;
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned long docptr = doc->virtadr;
+       volatile u_char dummy;
+       int emptymatch = 1;
+       
+       /* flush the pipeline */
+       if (DoC_is_2000(doc)) {
+               dummy = ReadDOC(docptr, 2k_ECCStatus);
+               dummy = ReadDOC(docptr, 2k_ECCStatus);
+               dummy = ReadDOC(docptr, 2k_ECCStatus);
+       } else if (DoC_is_MillenniumPlus(doc)) {
+               dummy = ReadDOC(docptr, Mplus_ECCConf);
+               dummy = ReadDOC(docptr, Mplus_ECCConf);
+               dummy = ReadDOC(docptr, Mplus_ECCConf);
+       } else {
+               dummy = ReadDOC(docptr, ECCConf);
+               dummy = ReadDOC(docptr, ECCConf);
+               dummy = ReadDOC(docptr, ECCConf);
+       }
+       
+       /* Error occured ? */
+       if (dummy & 0x80) {
+               for (i = 0; i < 6; i++) {
+                       if (DoC_is_MillenniumPlus(doc))
+                               calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+                       else
+                               calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+                       if (calc_ecc[i] != empty_read_syndrome[i])
+                               emptymatch = 0;
+               }
+               /* If emptymatch=1, the read syndrome is consistent with an
+                  all-0xff data and stored ecc block.  Check the stored ecc. */
+               if (emptymatch) {
+                       for (i = 0; i < 6; i++) {
+                               if (read_ecc[i] == 0xff) continue;
+                               emptymatch = 0;
+                               break;
+                       }
+               }
+               /* If emptymatch still =1, check the data block. */
+               if (emptymatch) {
+               /* Note: this somewhat expensive test should not be triggered
+                  often.  It could be optimized away by examining the data in
+                  the readbuf routine, and remembering the result. */
+                       for (i = 0; i < 512; i++) {
+                               if (dat[i] == 0xff) continue;
+                               emptymatch = 0;
+                               break;
+                       }
+               }
+               /* If emptymatch still =1, this is almost certainly a freshly-
+                  erased block, in which case the ECC will not come out right.
+                  We'll suppress the error and tell the caller everything's
+                  OK.  Because it is. */
+               if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc);
+               if (ret > 0)
+                       printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
+       }       
+       if (DoC_is_MillenniumPlus(doc))
+               WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+       else
+               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+       if (no_ecc_failures && (ret == -1)) {
+               printk(KERN_ERR "suppressing ECC failure\n");
+               ret = 0;
+       }
+       return ret;
+}
+               
+//u_char mydatabuf[528];
+
+static struct nand_oobinfo doc200x_oobinfo = {
+        .useecc = MTD_NANDECC_AUTOPLACE,
+        .eccbytes = 6,
+        .eccpos = {0, 1, 2, 3, 4, 5},
+        .oobfree = { {8, 8} }
+};
+/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
+   On sucessful return, buf will contain a copy of the media header for
+   further processing.  id is the string to scan for, and will presumably be
+   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
+   header.  The page #s of the found media headers are placed in mh0_page and
+   mh1_page in the DOC private structure. */
+static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
+                                    const char *id, int findmirror)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+       int ret;
+       size_t retlen;
+
+       end = min(end, mtd->size); // paranoia
+       for (offs = 0; offs < end; offs += mtd->erasesize) {
+               ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
+               if (retlen != mtd->oobblock) continue;
+               if (ret) {
+                       printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n",
+                               offs);
+               }
+               if (memcmp(buf, id, 6)) continue;
+               printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
+               if (doc->mh0_page == -1) {
+                       doc->mh0_page = offs >> this->page_shift;
+                       if (!findmirror) return 1;
+                       continue;
+               }
+               doc->mh1_page = offs >> this->page_shift;
+               return 2;
+       }
+       if (doc->mh0_page == -1) {
+               printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
+               return 0;
+       }
+       /* Only one mediaheader was found.  We want buf to contain a
+          mediaheader on return, so we'll have to re-read the one we found. */
+       offs = doc->mh0_page << this->page_shift;
+       ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
+       if (retlen != mtd->oobblock) {
+               /* Insanity.  Give up. */
+               printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
+               return 0;
+       }
+       return 1;
+}
+
+static inline int __init nftl_partscan(struct mtd_info *mtd,
+                               struct mtd_partition *parts)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       int ret = 0;
+       u_char *buf;
+       struct NFTLMediaHeader *mh;
+       const unsigned psize = 1 << this->page_shift;
+       unsigned blocks, maxblocks;
+       int offs, numheaders;
+
+       buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+       if (!buf) {
+               printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
+               return 0;
+       }
+       if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
+       mh = (struct NFTLMediaHeader *) buf;
+
+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
+//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+       printk(KERN_INFO "    DataOrgID        = %s\n"
+                        "    NumEraseUnits    = %d\n"
+                        "    FirstPhysicalEUN = %d\n"
+                        "    FormattedSize    = %d\n"
+                        "    UnitSizeFactor   = %d\n",
+               mh->DataOrgID, mh->NumEraseUnits,
+               mh->FirstPhysicalEUN, mh->FormattedSize,
+               mh->UnitSizeFactor);
+//#endif
+
+       blocks = mtd->size >> this->phys_erase_shift;
+       maxblocks = min(32768U, mtd->erasesize - psize);
+
+       if (mh->UnitSizeFactor == 0x00) {
+               /* Auto-determine UnitSizeFactor.  The constraints are:
+                  - There can be at most 32768 virtual blocks.
+                  - There can be at most (virtual block size - page size)
+                    virtual blocks (because MediaHeader+BBT must fit in 1).
+               */
+               mh->UnitSizeFactor = 0xff;
+               while (blocks > maxblocks) {
+                       blocks >>= 1;
+                       maxblocks = min(32768U, (maxblocks << 1) + psize);
+                       mh->UnitSizeFactor--;
+               }
+               printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
+       }
+
+       /* NOTE: The lines below modify internal variables of the NAND and MTD
+          layers; variables with have already been configured by nand_scan.
+          Unfortunately, we didn't know before this point what these values
+          should be.  Thus, this code is somewhat dependant on the exact
+          implementation of the NAND layer.  */
+       if (mh->UnitSizeFactor != 0xff) {
+               this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
+               mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
+               printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
+               blocks = mtd->size >> this->bbt_erase_shift;
+               maxblocks = min(32768U, mtd->erasesize - psize);
+       }
+
+       if (blocks > maxblocks) {
+               printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
+               goto out;
+       }
+
+       /* Skip past the media headers. */
+       offs = max(doc->mh0_page, doc->mh1_page);
+       offs <<= this->page_shift;
+       offs += mtd->erasesize;
+
+       //parts[0].name = " DiskOnChip Boot / Media Header partition";
+       //parts[0].offset = 0;
+       //parts[0].size = offs;
+
+       parts[0].name = " DiskOnChip BDTL partition";
+       parts[0].offset = offs;
+       parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+       offs += parts[0].size;
+       if (offs < mtd->size) {
+               parts[1].name = " DiskOnChip Remainder partition";
+               parts[1].offset = offs;
+               parts[1].size = mtd->size - offs;
+               ret = 2;
+               goto out;
+       }
+       ret = 1;
+out:
+       kfree(buf);
+       return ret;
+}
+
+/* This is a stripped-down copy of the code in inftlmount.c */
+static inline int __init inftl_partscan(struct mtd_info *mtd,
+                                struct mtd_partition *parts)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       int ret = 0;
+       u_char *buf;
+       struct INFTLMediaHeader *mh;
+       struct INFTLPartition *ip;
+       int numparts = 0;
+       int blocks;
+       int vshift, lastvunit = 0;
+       int i;
+       int end = mtd->size;
+
+       if (inftl_bbt_write)
+               end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
+
+       buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+       if (!buf) {
+               printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
+               return 0;
+       }
+
+       if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out;
+       doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
+       mh = (struct INFTLMediaHeader *) buf;
+
+       mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
+       mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
+       mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
+       mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
+       mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
+       mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
+//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+       printk(KERN_INFO "    bootRecordID          = %s\n"
+                        "    NoOfBootImageBlocks   = %d\n"
+                        "    NoOfBinaryPartitions  = %d\n"
+                        "    NoOfBDTLPartitions    = %d\n"
+                        "    BlockMultiplerBits    = %d\n"
+                        "    FormatFlgs            = %d\n"
+                        "    OsakVersion           = %d.%d.%d.%d\n"
+                        "    PercentUsed           = %d\n",
+               mh->bootRecordID, mh->NoOfBootImageBlocks,
+               mh->NoOfBinaryPartitions,
+               mh->NoOfBDTLPartitions,
+               mh->BlockMultiplierBits, mh->FormatFlags,
+               ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+               ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+               ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+               ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+               mh->PercentUsed);
+//#endif
+
+       vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
+
+       blocks = mtd->size >> vshift;
+       if (blocks > 32768) {
+               printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
+               goto out;
+       }
+
+       blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
+       if (inftl_bbt_write && (blocks > mtd->erasesize)) {
+               printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
+               goto out;
+       }
+
+       /* Scan the partitions */
+       for (i = 0; (i < 4); i++) {
+               ip = &(mh->Partitions[i]);
+               ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
+               ip->firstUnit = le32_to_cpu(ip->firstUnit);
+               ip->lastUnit = le32_to_cpu(ip->lastUnit);
+               ip->flags = le32_to_cpu(ip->flags);
+               ip->spareUnits = le32_to_cpu(ip->spareUnits);
+               ip->Reserved0 = le32_to_cpu(ip->Reserved0);
+
+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
+//             if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+               printk(KERN_INFO        "    PARTITION[%d] ->\n"
+                       "        virtualUnits    = %d\n"
+                       "        firstUnit       = %d\n"
+                       "        lastUnit        = %d\n"
+                       "        flags           = 0x%x\n"
+                       "        spareUnits      = %d\n",
+                       i, ip->virtualUnits, ip->firstUnit,
+                       ip->lastUnit, ip->flags,
+                       ip->spareUnits);
+//#endif
+
+/*
+               if ((i == 0) && (ip->firstUnit > 0)) {
+                       parts[0].name = " DiskOnChip IPL / Media Header partition";
+                       parts[0].offset = 0;
+                       parts[0].size = mtd->erasesize * ip->firstUnit;
+                       numparts = 1;
+               }
+*/
+
+               if (ip->flags & INFTL_BINARY)
+                       parts[numparts].name = " DiskOnChip BDK partition";
+               else
+                       parts[numparts].name = " DiskOnChip BDTL partition";
+               parts[numparts].offset = ip->firstUnit << vshift;
+               parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
+               numparts++;
+               if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit;
+               if (ip->flags & INFTL_LAST) break;
+       }
+       lastvunit++;
+       if ((lastvunit << vshift) < end) {
+               parts[numparts].name = " DiskOnChip Remainder partition";
+               parts[numparts].offset = lastvunit << vshift;
+               parts[numparts].size = end - parts[numparts].offset;
+               numparts++;
+       }
+       ret = numparts;
+out:
+       kfree(buf);
+       return ret;
+}
+
+static int __init nftl_scan_bbt(struct mtd_info *mtd)
+{
+       int ret, numparts;
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       struct mtd_partition parts[2];
+
+       memset((char *) parts, 0, sizeof(parts));
+       /* On NFTL, we have to find the media headers before we can read the
+          BBTs, since they're stored in the media header eraseblocks. */
+       numparts = nftl_partscan(mtd, parts);
+       if (!numparts) return -EIO;
+       this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+                               NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+                               NAND_BBT_VERSION;
+       this->bbt_td->veroffs = 7;
+       this->bbt_td->pages[0] = doc->mh0_page + 1;
+       if (doc->mh1_page != -1) {
+               this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+                                       NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+                                       NAND_BBT_VERSION;
+               this->bbt_md->veroffs = 7;
+               this->bbt_md->pages[0] = doc->mh1_page + 1;
+       } else {
+               this->bbt_md = NULL;
+       }
+
+       /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
+          At least as nand_bbt.c is currently written. */
+       if ((ret = nand_scan_bbt(mtd, NULL)))
+               return ret;
+       add_mtd_device(mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+       if (!no_autopart)
+               add_mtd_partitions(mtd, parts, numparts);
+#endif
+       return 0;
+}
+
+static int __init inftl_scan_bbt(struct mtd_info *mtd)
+{
+       int ret, numparts;
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+       struct mtd_partition parts[5];
+
+       if (this->numchips > doc->chips_per_floor) {
+               printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
+               return -EIO;
+       }
+
+       if (DoC_is_MillenniumPlus(doc)) {
+               this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
+               if (inftl_bbt_write)
+                       this->bbt_td->options |= NAND_BBT_WRITE;
+               this->bbt_td->pages[0] = 2;
+               this->bbt_md = NULL;
+       } else {
+               this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
+                                       NAND_BBT_VERSION;
+               if (inftl_bbt_write)
+                       this->bbt_td->options |= NAND_BBT_WRITE;
+               this->bbt_td->offs = 8;
+               this->bbt_td->len = 8;
+               this->bbt_td->veroffs = 7;
+               this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+               this->bbt_td->reserved_block_code = 0x01;
+               this->bbt_td->pattern = "MSYS_BBT";
+
+               this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
+                                       NAND_BBT_VERSION;
+               if (inftl_bbt_write)
+                       this->bbt_md->options |= NAND_BBT_WRITE;
+               this->bbt_md->offs = 8;
+               this->bbt_md->len = 8;
+               this->bbt_md->veroffs = 7;
+               this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+               this->bbt_md->reserved_block_code = 0x01;
+               this->bbt_md->pattern = "TBB_SYSM";
+       }
+
+       /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
+          At least as nand_bbt.c is currently written. */
+       if ((ret = nand_scan_bbt(mtd, NULL)))
+               return ret;
+       memset((char *) parts, 0, sizeof(parts));
+       numparts = inftl_partscan(mtd, parts);
+       /* At least for now, require the INFTL Media Header.  We could probably
+          do without it for non-INFTL use, since all it gives us is
+          autopartitioning, but I want to give it more thought. */
+       if (!numparts) return -EIO;
+       add_mtd_device(mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+       if (!no_autopart)
+               add_mtd_partitions(mtd, parts, numparts);
+#endif
+       return 0;
+}
+
+static inline int __init doc2000_init(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+
+       this->write_byte = doc2000_write_byte;
+       this->read_byte = doc2000_read_byte;
+       this->write_buf = doc2000_writebuf;
+       this->read_buf = doc2000_readbuf;
+       this->verify_buf = doc2000_verifybuf;
+       this->scan_bbt = nftl_scan_bbt;
+
+       doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
+       doc2000_count_chips(mtd);
+       mtd->name = "DiskOnChip 2000 (NFTL Model)";
+       return (4 * doc->chips_per_floor);
+}
+
+static inline int __init doc2001_init(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+
+       this->write_byte = doc2001_write_byte;
+       this->read_byte = doc2001_read_byte;
+       this->write_buf = doc2001_writebuf;
+       this->read_buf = doc2001_readbuf;
+       this->verify_buf = doc2001_verifybuf;
+
+       ReadDOC(doc->virtadr, ChipID);
+       ReadDOC(doc->virtadr, ChipID);
+       ReadDOC(doc->virtadr, ChipID);
+       if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
+               /* It's not a Millennium; it's one of the newer
+                  DiskOnChip 2000 units with a similar ASIC. 
+                  Treat it like a Millennium, except that it
+                  can have multiple chips. */
+               doc2000_count_chips(mtd);
+               mtd->name = "DiskOnChip 2000 (INFTL Model)";
+               this->scan_bbt = inftl_scan_bbt;
+               return (4 * doc->chips_per_floor);
+       } else {
+               /* Bog-standard Millennium */
+               doc->chips_per_floor = 1;
+               mtd->name = "DiskOnChip Millennium";
+               this->scan_bbt = nftl_scan_bbt;
+               return 1;
+       }
+}
+
+static inline int __init doc2001plus_init(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct doc_priv *doc = (void *)this->priv;
+
+       this->write_byte = NULL;
+       this->read_byte = doc2001plus_read_byte;
+       this->write_buf = doc2001plus_writebuf;
+       this->read_buf = doc2001plus_readbuf;
+       this->verify_buf = doc2001plus_verifybuf;
+       this->scan_bbt = inftl_scan_bbt;
+       this->hwcontrol = NULL;
+       this->select_chip = doc2001plus_select_chip;
+       this->cmdfunc = doc2001plus_command;
+       this->enable_hwecc = doc2001plus_enable_hwecc;
+
+       doc->chips_per_floor = 1;
+       mtd->name = "DiskOnChip Millennium Plus";
+
+       return 1;
+}
+
+static inline int __init doc_probe(unsigned long physadr)
+{
+       unsigned char ChipID;
+       struct mtd_info *mtd;
+       struct nand_chip *nand;
+       struct doc_priv *doc;
+       unsigned long virtadr;
+       unsigned char save_control;
+       unsigned char tmp, tmpb, tmpc;
+       int reg, len, numchips;
+       int ret = 0;
+
+       virtadr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+       if (!virtadr) {
+               printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
+               return -EIO;
+       }
+
+       /* It's not possible to cleanly detect the DiskOnChip - the
+        * bootup procedure will put the device into reset mode, and
+        * it's not possible to talk to it without actually writing
+        * to the DOCControl register. So we store the current contents
+        * of the DOCControl register's location, in case we later decide
+        * that it's not a DiskOnChip, and want to put it back how we
+        * found it. 
+        */
+       save_control = ReadDOC(virtadr, DOCControl);
+
+       /* Reset the DiskOnChip ASIC */
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+                virtadr, DOCControl);
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+                virtadr, DOCControl);
+
+       /* Enable the DiskOnChip ASIC */
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+                virtadr, DOCControl);
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+                virtadr, DOCControl);
+
+       ChipID = ReadDOC(virtadr, ChipID);
+
+       switch(ChipID) {
+       case DOC_ChipID_Doc2k:
+               reg = DoC_2k_ECCStatus;
+               break;
+       case DOC_ChipID_DocMil:
+               reg = DoC_ECCConf;
+               break;
+       case DOC_ChipID_DocMilPlus16:
+       case DOC_ChipID_DocMilPlus32:
+       case 0:
+               /* Possible Millennium Plus, need to do more checks */
+               /* Possibly release from power down mode */
+               for (tmp = 0; (tmp < 4); tmp++)
+                       ReadDOC(virtadr, Mplus_Power);
+
+               /* Reset the Millennium Plus ASIC */
+               tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
+                       DOC_MODE_BDECT;
+               WriteDOC(tmp, virtadr, Mplus_DOCControl);
+               WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+
+               mdelay(1);
+               /* Enable the Millennium Plus ASIC */
+               tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
+                       DOC_MODE_BDECT;
+               WriteDOC(tmp, virtadr, Mplus_DOCControl);
+               WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+               mdelay(1);
+
+               ChipID = ReadDOC(virtadr, ChipID);
+
+               switch (ChipID) {
+               case DOC_ChipID_DocMilPlus16:
+                       reg = DoC_Mplus_Toggle;
+                       break;
+               case DOC_ChipID_DocMilPlus32:
+                       printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
+               default:
+                       ret = -ENODEV;
+                       goto notfound;
+               }
+               break;
+
+       default:
+               ret = -ENODEV;
+               goto notfound;
+       }
+       /* Check the TOGGLE bit in the ECC register */
+       tmp  = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+       tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+       tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+       if ((tmp == tmpb) || (tmp != tmpc)) {
+               printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
+               ret = -ENODEV;
+               goto notfound;
+       }
+
+       for (mtd = doclist; mtd; mtd = doc->nextdoc) {
+               unsigned char oldval;
+               unsigned char newval;
+               nand = mtd->priv;
+               doc = (void *)nand->priv;
+               /* Use the alias resolution register to determine if this is
+                  in fact the same DOC aliased to a new address.  If writes
+                  to one chip's alias resolution register change the value on
+                  the other chip, they're the same chip. */
+               if (ChipID == DOC_ChipID_DocMilPlus16) {
+                       oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+                       newval = ReadDOC(virtadr, Mplus_AliasResolution);
+               } else {
+                       oldval = ReadDOC(doc->virtadr, AliasResolution);
+                       newval = ReadDOC(virtadr, AliasResolution);
+               }
+               if (oldval != newval)
+                       continue;
+               if (ChipID == DOC_ChipID_DocMilPlus16) {
+                       WriteDOC(~newval, virtadr, Mplus_AliasResolution);
+                       oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+                       WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
+               } else {
+                       WriteDOC(~newval, virtadr, AliasResolution);
+                       oldval = ReadDOC(doc->virtadr, AliasResolution);
+                       WriteDOC(newval, virtadr, AliasResolution); // restore it
+               }
+               newval = ~newval;
+               if (oldval == newval) {
+                       printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
+                       goto notfound;
+               }
+       }
+
+       printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
+
+       len = sizeof(struct mtd_info) +
+             sizeof(struct nand_chip) +
+             sizeof(struct doc_priv) +
+             (2 * sizeof(struct nand_bbt_descr));
+       mtd = kmalloc(len, GFP_KERNEL);
+       if (!mtd) {
+               printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
+               ret = -ENOMEM;
+               goto fail;
+       }
+       memset(mtd, 0, len);
+
+       nand                    = (struct nand_chip *) (mtd + 1);
+       doc                     = (struct doc_priv *) (nand + 1);
+       nand->bbt_td            = (struct nand_bbt_descr *) (doc + 1);
+       nand->bbt_md            = nand->bbt_td + 1;
+
+       mtd->priv               = (void *) nand;
+       mtd->owner              = THIS_MODULE;
+
+       nand->priv              = (void *) doc;
+       nand->select_chip       = doc200x_select_chip;
+       nand->hwcontrol         = doc200x_hwcontrol;
+       nand->dev_ready         = doc200x_dev_ready;
+       nand->waitfunc          = doc200x_wait;
+       nand->block_bad         = doc200x_block_bad;
+       nand->enable_hwecc      = doc200x_enable_hwecc;
+       nand->calculate_ecc     = doc200x_calculate_ecc;
+       nand->correct_data      = doc200x_correct_data;
+       //nand->data_buf
+       nand->autooob           = &doc200x_oobinfo;
+       nand->eccmode           = NAND_ECC_HW6_512;
+       nand->options           = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
+
+       doc->physadr            = physadr;
+       doc->virtadr            = virtadr;
+       doc->ChipID             = ChipID;
+       doc->curfloor           = -1;
+       doc->curchip            = -1;
+       doc->mh0_page           = -1;
+       doc->mh1_page           = -1;
+       doc->nextdoc            = doclist;
+
+       if (ChipID == DOC_ChipID_Doc2k)
+               numchips = doc2000_init(mtd);
+       else if (ChipID == DOC_ChipID_DocMilPlus16)
+               numchips = doc2001plus_init(mtd);
+       else
+               numchips = doc2001_init(mtd);
+
+       if ((ret = nand_scan(mtd, numchips))) {
+               /* DBB note: i believe nand_release is necessary here, as
+                  buffers may have been allocated in nand_base.  Check with
+                  Thomas. FIX ME! */
+               /* nand_release will call del_mtd_device, but we haven't yet
+                  added it.  This is handled without incident by
+                  del_mtd_device, as far as I can tell. */
+               nand_release(mtd);
+               kfree(mtd);
+               goto fail;
+       }
+
+       /* Success! */
+       doclist = mtd;
+       return 0;
+
+notfound:
+       /* Put back the contents of the DOCControl register, in case it's not
+          actually a DiskOnChip.  */
+       WriteDOC(save_control, virtadr, DOCControl);
+fail:
+       iounmap((void *)virtadr);
+       return ret;
+}
+
+int __init init_nanddoc(void)
+{
+       int i;
+
+       if (doc_config_location) {
+               printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
+               return doc_probe(doc_config_location);
+       } else {
+               for (i=0; (doc_locations[i] != 0xffffffff); i++) {
+                       doc_probe(doc_locations[i]);
+               }
+       }
+       /* No banner message any more. Print a message if no DiskOnChip
+          found, so the user knows we at least tried. */
+       if (!doclist) {
+               printk(KERN_INFO "No valid DiskOnChip devices found\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+void __exit cleanup_nanddoc(void)
+{
+       struct mtd_info *mtd, *nextmtd;
+       struct nand_chip *nand;
+       struct doc_priv *doc;
+
+       for (mtd = doclist; mtd; mtd = nextmtd) {
+               nand = mtd->priv;
+               doc = (void *)nand->priv;
+
+               nextmtd = doc->nextdoc;
+               nand_release(mtd);
+               iounmap((void *)doc->virtadr);
+               kfree(mtd);
+       }
+}
+
+module_init(init_nanddoc);
+module_exit(cleanup_nanddoc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
new file mode 100644 (file)
index 0000000..ff6adf4
--- /dev/null
@@ -0,0 +1,2581 @@
+/*
+ *  drivers/mtd/nand.c
+ *
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ *   Basic support for AG-AND chips is provided.
+ *   
+ *     Additional technical information is available on
+ *     http://www.linux-mtd.infradead.org/tech/nand.html
+ *     
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *               2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  02-08-2004  tglx: support for strange chips, which cannot auto increment 
+ *             pages on read / read_oob
+ *
+ *  03-17-2004  tglx: Check ready before auto increment check. Simon Bayes
+ *             pointed this out, as he marked an auto increment capable chip
+ *             as NOAUTOINCR in the board driver.
+ *             Make reads over block boundaries work too
+ *
+ *  04-14-2004 tglx: first working version for 2k page size chips
+ *  
+ *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
+ *
+ * Credits:
+ *     David Woodhouse for adding multichip support  
+ *     
+ *     Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ *     rework for 2K page size chips
+ *
+ * TODO:
+ *     Enable cached programming for 2k page size chips
+ *     Check, if mtd->ecctype should be set to MTD_ECC_HW
+ *     if we have HW ecc support.
+ *     The AG-AND chips have nice features for speed improvement,
+ *     which are not supported yet. Read / program 4 pages in one go.
+ *
+ * $Id: nand_base.c,v 1.115 2004/08/09 13:19:45 dwmw2 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+/* Define default oob placement schemes for large and small page devices */
+static struct nand_oobinfo nand_oob_8 = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 3,
+       .eccpos = {0, 1, 2},
+       .oobfree = { {3, 2}, {6, 2} }
+};
+
+static struct nand_oobinfo nand_oob_16 = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 6,
+       .eccpos = {0, 1, 2, 3, 6, 7},
+       .oobfree = { {8, 8} }
+};
+
+static struct nand_oobinfo nand_oob_64 = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 24,
+       .eccpos = {
+               40, 41, 42, 43, 44, 45, 46, 47, 
+               48, 49, 50, 51, 52, 53, 54, 55, 
+               56, 57, 58, 59, 60, 61, 62, 63},
+       .oobfree = { {2, 38} }
+};
+
+/* This is used for padding purposes in nand_write_oob */
+static u_char ffchars[] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+/*
+ * NAND low-level MTD interface functions
+ */
+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
+
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
+static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                         size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
+static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+                          size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
+static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
+                       unsigned long count, loff_t to, size_t * retlen);
+static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
+                       unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
+static void nand_sync (struct mtd_info *mtd);
+
+/* Some internal functions */
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,
+               struct nand_oobinfo *oobsel, int mode);
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+       u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
+#else
+#define nand_verify_pages(...) (0)
+#endif
+               
+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+
+/**
+ * nand_release_chip - [GENERIC] release chip
+ * @mtd:       MTD device structure
+ * 
+ * Deselect, release chip lock and wake up anyone waiting on the device 
+ */
+static void nand_release_chip (struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+
+       /* De-select the NAND device */
+       this->select_chip(mtd, -1);
+       /* Release the chip */
+       spin_lock_bh (&this->chip_lock);
+       this->state = FL_READY;
+       wake_up (&this->wq);
+       spin_unlock_bh (&this->chip_lock);
+}
+
+/**
+ * nand_read_byte - [DEFAULT] read one byte from the chip
+ * @mtd:       MTD device structure
+ *
+ * Default read function for 8bit buswith
+ */
+static u_char nand_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       return readb(this->IO_ADDR_R);
+}
+
+/**
+ * nand_write_byte - [DEFAULT] write one byte to the chip
+ * @mtd:       MTD device structure
+ * @byte:      pointer to data byte to write
+ *
+ * Default write function for 8it buswith
+ */
+static void nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+       struct nand_chip *this = mtd->priv;
+       writeb(byte, this->IO_ADDR_W);
+}
+
+/**
+ * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
+ * @mtd:       MTD device structure
+ *
+ * Default read function for 16bit buswith with 
+ * endianess conversion
+ */
+static u_char nand_read_byte16(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
+ * @mtd:       MTD device structure
+ * @byte:      pointer to data byte to write
+ *
+ * Default write function for 16bit buswith with
+ * endianess conversion
+ */
+static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
+{
+       struct nand_chip *this = mtd->priv;
+       writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+}
+
+/**
+ * nand_read_word - [DEFAULT] read one word from the chip
+ * @mtd:       MTD device structure
+ *
+ * Default read function for 16bit buswith without 
+ * endianess conversion
+ */
+static u16 nand_read_word(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       return readw(this->IO_ADDR_R);
+}
+
+/**
+ * nand_write_word - [DEFAULT] write one word to the chip
+ * @mtd:       MTD device structure
+ * @word:      data word to write
+ *
+ * Default write function for 16bit buswith without 
+ * endianess conversion
+ */
+static void nand_write_word(struct mtd_info *mtd, u16 word)
+{
+       struct nand_chip *this = mtd->priv;
+       writew(word, this->IO_ADDR_W);
+}
+
+/**
+ * nand_select_chip - [DEFAULT] control CE line
+ * @mtd:       MTD device structure
+ * @chip:      chipnumber to select, -1 for deselect
+ *
+ * Default select function for 1 chip devices.
+ */
+static void nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *this = mtd->priv;
+       switch(chip) {
+       case -1:
+               this->hwcontrol(mtd, NAND_CTL_CLRNCE);  
+               break;
+       case 0:
+               this->hwcontrol(mtd, NAND_CTL_SETNCE);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @mtd:       MTD device structure
+ * @buf:       data buffer
+ * @len:       number of bytes to write
+ *
+ * Default write function for 8bit buswith
+ */
+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               writeb(buf[i], this->IO_ADDR_W);
+}
+
+/**
+ * nand_read_buf - [DEFAULT] read chip data into buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer to store date
+ * @len:       number of bytes to read
+ *
+ * Default read function for 8bit buswith
+ */
+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               buf[i] = readb(this->IO_ADDR_R);
+}
+
+/**
+ * nand_verify_buf - [DEFAULT] Verify chip data against buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer containing the data to compare
+ * @len:       number of bytes to compare
+ *
+ * Default verify function for 8bit buswith
+ */
+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               if (buf[i] != readb(this->IO_ADDR_R))
+                       return -EFAULT;
+
+       return 0;
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @mtd:       MTD device structure
+ * @buf:       data buffer
+ * @len:       number of bytes to write
+ *
+ * Default write function for 16bit buswith
+ */
+static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+       
+       for (i=0; i<len; i++)
+               writew(p[i], this->IO_ADDR_W);
+               
+}
+
+/**
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer to store date
+ * @len:       number of bytes to read
+ *
+ * Default read function for 16bit buswith
+ */
+static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+
+       for (i=0; i<len; i++)
+               p[i] = readw(this->IO_ADDR_R);
+}
+
+/**
+ * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer 
+ * @mtd:       MTD device structure
+ * @buf:       buffer containing the data to compare
+ * @len:       number of bytes to compare
+ *
+ * Default verify function for 16bit buswith
+ */
+static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+       u16 *p = (u16 *) buf;
+       len >>= 1;
+
+       for (i=0; i<len; i++)
+               if (p[i] != readw(this->IO_ADDR_R))
+                       return -EFAULT;
+
+       return 0;
+}
+
+/**
+ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
+ * @mtd:       MTD device structure
+ * @ofs:       offset from device start
+ * @getchip:   0, if the chip is already selected
+ *
+ * Check, if the block is bad. 
+ */
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+       int page, chipnr, res = 0;
+       struct nand_chip *this = mtd->priv;
+       u16 bad;
+
+       if (getchip) {
+               page = (int)(ofs >> this->page_shift);
+               chipnr = (int)(ofs >> this->chip_shift);
+
+               /* Grab the lock and see if the device is available */
+               nand_get_chip (this, mtd, FL_READING);
+
+               /* Select the NAND device */
+               this->select_chip(mtd, chipnr);
+       } else 
+               page = (int) ofs;       
+
+       if (this->options & NAND_BUSWIDTH_16) {
+               this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
+               bad = cpu_to_le16(this->read_word(mtd));
+               if (this->badblockpos & 0x1)
+                       bad >>= 1;
+               if ((bad & 0xFF) != 0xff)
+                       res = 1;
+       } else {
+               this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
+               if (this->read_byte(mtd) != 0xff)
+                       res = 1;
+       }
+               
+       if (getchip) {
+               /* Deselect and wake up anyone waiting on the device */
+               nand_release_chip(mtd);
+       }       
+       
+       return res;
+}
+
+/**
+ * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * @mtd:       MTD device structure
+ * @ofs:       offset from device start
+ *
+ * This is the default implementation, which can be overridden by
+ * a hardware specific driver.
+*/
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_chip *this = mtd->priv;
+       u_char buf[2] = {0, 0};
+       size_t  retlen;
+       int block;
+       
+       /* Get block number */
+       block = ((int) ofs) >> this->bbt_erase_shift;
+       this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+
+       /* Do we have a flash based bad block table ? */
+       if (this->options & NAND_USE_FLASH_BBT)
+               return nand_update_bbt (mtd, ofs);
+               
+       /* We write two bytes, so we dont have to mess with 16 bit access */
+       ofs += mtd->oobsize + (this->badblockpos & ~0x01);
+       return nand_write_oob (mtd, ofs , 2, &retlen, buf);
+}
+
+/** 
+ * nand_check_wp - [GENERIC] check if the chip is write protected
+ * @mtd:       MTD device structure
+ * Check, if the device is write protected 
+ *
+ * The function expects, that the device is already selected 
+ */
+static int nand_check_wp (struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       /* Check the WP bit */
+       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+       return (this->read_byte(mtd) & 0x80) ? 0 : 1; 
+}
+
+/**
+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * @mtd:       MTD device structure
+ * @ofs:       offset from device start
+ * @getchip:   0, if the chip is already selected
+ * @allowbbt:  1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad. Either by reading the bad block table or
+ * calling of the scan function.
+ */
+static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+{
+       struct nand_chip *this = mtd->priv;
+       
+       if (!this->bbt)
+               return this->block_bad(mtd, ofs, getchip);
+       
+       /* Return info from the table */
+       return nand_isbad_bbt (mtd, ofs, allowbbt);
+}
+
+/**
+ * nand_command - [DEFAULT] Send command to NAND device
+ * @mtd:       MTD device structure
+ * @command:   the command to be sent
+ * @column:    the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This function is used for small page
+ * devices (256/512 Bytes per page)
+ */
+static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       register struct nand_chip *this = mtd->priv;
+
+       /* Begin command latch cycle */
+       this->hwcontrol(mtd, NAND_CTL_SETCLE);
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->oobblock) {
+                       /* OOB area */
+                       column -= mtd->oobblock;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               this->write_byte(mtd, readcmd);
+       }
+       this->write_byte(mtd, command);
+
+       /* Set ALE and clear CLE to start address cycle */
+       this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+       if (column != -1 || page_addr != -1) {
+               this->hwcontrol(mtd, NAND_CTL_SETALE);
+
+               /* Serially input address */
+               if (column != -1) {
+                       /* Adjust columns for 16 bit buswidth */
+                       if (this->options & NAND_BUSWIDTH_16)
+                               column >>= 1;
+                       this->write_byte(mtd, column);
+               }
+               if (page_addr != -1) {
+                       this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
+                       this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+                       /* One more address cycle for higher density devices */
+                       if (this->chipsize & 0x0c000000) 
+                               this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
+               }
+               /* Latch in address */
+               this->hwcontrol(mtd, NAND_CTL_CLRALE);
+       }
+       
+       /* 
+        * program and erase have their own busy handlers 
+        * status and sequential in needs no delay
+       */
+       switch (command) {
+                       
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+               return;
+
+       case NAND_CMD_RESET:
+               if (this->dev_ready)    
+                       break;
+               udelay(this->chip_delay);
+               this->hwcontrol(mtd, NAND_CTL_SETCLE);
+               this->write_byte(mtd, NAND_CMD_STATUS);
+               this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+               while ( !(this->read_byte(mtd) & 0x40));
+               return;
+
+       /* This applies to read commands */     
+       default:
+               /* 
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+               */
+               if (!this->dev_ready) {
+                       udelay (this->chip_delay);
+                       return;
+               }       
+       }
+       
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay (100);
+       /* wait until command is processed */
+       while (!this->dev_ready(mtd));
+}
+
+/**
+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
+ * @mtd:       MTD device structure
+ * @command:   the command to be sent
+ * @column:    the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page devices
+ * We dont have the seperate regions as we have in the small page devices.
+ * We must emulate NAND_CMD_READOOB to keep the code compatible.
+ *
+ */
+static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       register struct nand_chip *this = mtd->priv;
+
+       /* Emulate NAND_CMD_READOOB */
+       if (command == NAND_CMD_READOOB) {
+               column += mtd->oobblock;
+               command = NAND_CMD_READ0;
+       }
+       
+               
+       /* Begin command latch cycle */
+       this->hwcontrol(mtd, NAND_CTL_SETCLE);
+       /* Write out the command to the device. */
+       this->write_byte(mtd, command);
+       /* End command latch cycle */
+       this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+       if (column != -1 || page_addr != -1) {
+               this->hwcontrol(mtd, NAND_CTL_SETALE);
+
+               /* Serially input address */
+               if (column != -1) {
+                       /* Adjust columns for 16 bit buswidth */
+                       if (this->options & NAND_BUSWIDTH_16)
+                               column >>= 1;
+                       this->write_byte(mtd, column & 0xff);
+                       this->write_byte(mtd, column >> 8);
+               }       
+               if (page_addr != -1) {
+                       this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
+                       this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+                       /* One more address cycle for devices > 128MiB */
+                       if (this->chipsize > (128 << 20))
+                               this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff));
+               }
+               /* Latch in address */
+               this->hwcontrol(mtd, NAND_CTL_CLRALE);
+       }
+       
+       /* 
+        * program and erase have their own busy handlers 
+        * status and sequential in needs no delay
+       */
+       switch (command) {
+                       
+       case NAND_CMD_CACHEDPROG:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+               return;
+
+
+       case NAND_CMD_RESET:
+               if (this->dev_ready)    
+                       break;
+               udelay(this->chip_delay);
+               this->hwcontrol(mtd, NAND_CTL_SETCLE);
+               this->write_byte(mtd, NAND_CMD_STATUS);
+               this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+               while ( !(this->read_byte(mtd) & 0x40));
+               return;
+
+       case NAND_CMD_READ0:
+               /* Begin command latch cycle */
+               this->hwcontrol(mtd, NAND_CTL_SETCLE);
+               /* Write out the start read command */
+               this->write_byte(mtd, NAND_CMD_READSTART);
+               /* End command latch cycle */
+               this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+               /* Fall through into ready check */
+               
+       /* This applies to read commands */     
+       default:
+               /* 
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+               */
+               if (!this->dev_ready) {
+                       udelay (this->chip_delay);
+                       return;
+               }       
+       }
+       
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay (100);
+       /* wait until command is processed */
+       while (!this->dev_ready(mtd));
+}
+
+/**
+ * nand_get_chip - [GENERIC] Get chip for selected access
+ * @this:      the nand chip descriptor
+ * @mtd:       MTD device structure
+ * @new_state: the state which is requested 
+ *
+ * Get the device and lock it for exclusive access
+ */
+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+{
+
+       DECLARE_WAITQUEUE (wait, current);
+
+       /* 
+        * Grab the lock and see if the device is available 
+       */
+retry:
+       spin_lock_bh (&this->chip_lock);
+
+       if (this->state == FL_READY) {
+               this->state = new_state;
+               spin_unlock_bh (&this->chip_lock);
+               return;
+       }
+
+       set_current_state (TASK_UNINTERRUPTIBLE);
+       add_wait_queue (&this->wq, &wait);
+       spin_unlock_bh (&this->chip_lock);
+       schedule ();
+       remove_wait_queue (&this->wq, &wait);
+       goto retry;
+}
+
+/**
+ * nand_wait - [DEFAULT]  wait until the command is done
+ * @mtd:       MTD device structure
+ * @this:      NAND chip structure
+ * @state:     state to select the max. timeout value
+ *
+ * Wait for command done. This applies to erase and program only
+ * Erase can take up to 400ms and program up to 20ms according to 
+ * general NAND and SmartMedia specs
+ *
+*/
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+
+       unsigned long   timeo = jiffies;
+       int     status;
+       
+       if (state == FL_ERASING)
+                timeo += (HZ * 400) / 1000;
+       else
+                timeo += (HZ * 20) / 1000;
+
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay (100);
+
+       spin_lock_bh (&this->chip_lock);
+       if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
+               this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
+       else    
+               this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+
+       while (time_before(jiffies, timeo)) {           
+               /* Check, if we were interrupted */
+               if (this->state != state) {
+                       spin_unlock_bh (&this->chip_lock);
+                       return 0;
+               }
+               if (this->dev_ready) {
+                       if (this->dev_ready(mtd))
+                               break;
+               }
+               if (this->read_byte(mtd) & NAND_STATUS_READY)
+                       break;
+                                               
+               spin_unlock_bh (&this->chip_lock);
+               yield ();
+               spin_lock_bh (&this->chip_lock);
+       }
+       status = (int) this->read_byte(mtd);
+       spin_unlock_bh (&this->chip_lock);
+
+       return status;
+}
+
+/**
+ * nand_write_page - [GENERIC] write one page
+ * @mtd:       MTD device structure
+ * @this:      NAND chip structure
+ * @page:      startpage inside the chip, must be called with (page & this->pagemask)
+ * @oob_buf:   out of band data buffer
+ * @oobsel:    out of band selecttion structre
+ * @cached:    1 = enable cached programming if supported by chip
+ *
+ * Nand_page_program function is used for write and writev !
+ * This function will always program a full page of data
+ * If you call it with a non page aligned buffer, you're lost :)
+ *
+ * Cached programming is not supported yet.
+ */
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, 
+       u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
+{
+       int     i, status;
+       u_char  ecc_code[8];
+       int     eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+       int     *oob_config = oobsel->eccpos;
+       int     datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
+       int     eccbytes = 0;
+       
+       /* FIXME: Enable cached programming */
+       cached = 0;
+       
+       /* Send command to begin auto page programming */
+       this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+       /* Write out complete page of data, take care of eccmode */
+       switch (eccmode) {
+       /* No ecc, write all */
+       case NAND_ECC_NONE:
+               printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
+               this->write_buf(mtd, this->data_poi, mtd->oobblock);
+               break;
+               
+       /* Software ecc 3/256, write all */
+       case NAND_ECC_SOFT:
+               for (; eccsteps; eccsteps--) {
+                       this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
+                       for (i = 0; i < 3; i++, eccidx++)
+                               oob_buf[oob_config[eccidx]] = ecc_code[i];
+                       datidx += this->eccsize;
+               }
+               this->write_buf(mtd, this->data_poi, mtd->oobblock);
+               break;
+               
+       /* Hardware ecc 8 byte / 512 byte data */       
+       case NAND_ECC_HW8_512:  
+               eccbytes += 2;
+       /* Hardware ecc 6 byte / 512 byte data */       
+       case NAND_ECC_HW6_512:  
+               eccbytes += 3;
+       /* Hardware ecc 3 byte / 256 data */    
+       /* Hardware ecc 3 byte / 512 byte data */       
+       case NAND_ECC_HW3_256:          
+       case NAND_ECC_HW3_512:
+               eccbytes += 3;
+               for (; eccsteps; eccsteps--) {
+                       /* enable hardware ecc logic for write */
+                       this->enable_hwecc(mtd, NAND_ECC_WRITE);
+                       this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
+                       this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
+                       for (i = 0; i < eccbytes; i++, eccidx++)
+                               oob_buf[oob_config[eccidx]] = ecc_code[i];
+                       /* If the hardware ecc provides syndromes then
+                        * the ecc code must be written immidiately after
+                        * the data bytes (words) */
+                       if (this->options & NAND_HWECC_SYNDROME)
+                               this->write_buf(mtd, ecc_code, eccbytes);
+
+                       datidx += this->eccsize;
+               }
+               break;
+
+       default:
+               printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+               BUG();  
+       }
+                                                                               
+       /* Write out OOB data */
+       if (this->options & NAND_HWECC_SYNDROME)
+               this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
+       else 
+               this->write_buf(mtd, oob_buf, mtd->oobsize);
+
+       /* Send command to actually program the data */
+       this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
+
+       if (!cached) {
+               /* call wait ready function */
+               status = this->waitfunc (mtd, this, FL_WRITING);
+               /* See if device thinks it succeeded */
+               if (status & 0x01) {
+                       DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
+                       return -EIO;
+               }
+       } else {
+               /* FIXME: Implement cached programming ! */
+               /* wait until cache is ready*/
+               // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
+       }
+       return 0;       
+}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+/**
+ * nand_verify_pages - [GENERIC] verify the chip contents after a write
+ * @mtd:       MTD device structure
+ * @this:      NAND chip structure
+ * @page:      startpage inside the chip, must be called with (page & this->pagemask)
+ * @numpages:  number of pages to verify
+ * @oob_buf:   out of band data buffer
+ * @oobsel:    out of band selecttion structre
+ * @chipnr:    number of the current chip
+ * @oobmode:   1 = full buffer verify, 0 = ecc only
+ *
+ * The NAND device assumes that it is always writing to a cleanly erased page.
+ * Hence, it performs its internal write verification only on bits that 
+ * transitioned from 1 to 0. The device does NOT verify the whole page on a
+ * byte by byte basis. It is possible that the page was not completely erased 
+ * or the page is becoming unusable due to wear. The read with ECC would catch 
+ * the error later when the ECC page check fails, but we would rather catch 
+ * it early in the page write stage. Better to write no data than invalid data.
+ */
+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+       u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
+{
+       int     i, j, datidx = 0, oobofs = 0, res = -EIO;
+       int     eccsteps = this->eccsteps;
+       int     hweccbytes; 
+       u_char  oobdata[64];
+
+       hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
+
+       /* Send command to read back the first page */
+       this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
+
+       for(;;) {
+               for (j = 0; j < eccsteps; j++) {
+                       /* Loop through and verify the data */
+                       if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
+                               DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+                               goto out;
+                       }
+                       datidx += mtd->eccsize;
+                       /* Have we a hw generator layout ? */
+                       if (!hweccbytes)
+                               continue;
+                       if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
+                               DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+                               goto out;
+                       }
+                       oobofs += hweccbytes;
+               }
+
+               /* check, if we must compare all data or if we just have to
+                * compare the ecc bytes
+                */
+               if (oobmode) {
+                       if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
+                               DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+                               goto out;
+                       }
+               } else {
+                       /* Read always, else autoincrement fails */
+                       this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
+
+                       if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
+                               int ecccnt = oobsel->eccbytes;
+               
+                               for (i = 0; i < ecccnt; i++) {
+                                       int idx = oobsel->eccpos[i];
+                                       if (oobdata[idx] != oob_buf[oobofs + idx] ) {
+                                               DEBUG (MTD_DEBUG_LEVEL0,
+                                               "%s: Failed ECC write "
+                                               "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
+                                               goto out;
+                                       }
+                               }
+                       }       
+               }
+               oobofs += mtd->oobsize - hweccbytes * eccsteps;
+               page++;
+               numpages--;
+
+               /* Apply delay or wait for ready/busy pin 
+                * Do this before the AUTOINCR check, so no problems
+                * arise if a chip which does auto increment
+                * is marked as NOAUTOINCR by the board driver.
+                * Do this also before returning, so the chip is
+                * ready for the next command.
+               */
+               if (!this->dev_ready) 
+                       udelay (this->chip_delay);
+               else
+                       while (!this->dev_ready(mtd));  
+
+               /* All done, return happy */
+               if (!numpages)
+                       return 0;
+               
+                       
+               /* Check, if the chip supports auto page increment */ 
+               if (!NAND_CANAUTOINCR(this))
+                       this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+       }
+       /* 
+        * Terminate the read command. We come here in case of an error
+        * So we must issue a reset command.
+        */
+out:    
+       this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
+       return res;
+}
+#endif
+
+/**
+ * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * @mtd:       MTD device structure
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @retlen:    pointer to variable to store the number of read bytes
+ * @buf:       the databuffer to put data
+ *
+ * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
+*/
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+{
+       return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
+}                         
+
+
+/**
+ * nand_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd:       MTD device structure
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @retlen:    pointer to variable to store the number of read bytes
+ * @buf:       the databuffer to put data
+ * @oob_buf:   filesystem supplied oob data buffer
+ * @oobsel:    oob selection structure
+ *
+ * NAND read with ECC
+ */
+static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                         size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
+{
+       int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
+       int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
+       struct nand_chip *this = mtd->priv;
+       u_char *data_poi, *oob_data = oob_buf;
+       u_char ecc_calc[32];
+       u_char ecc_code[32];
+        int eccmode, eccsteps;
+       int     *oob_config, datidx;
+       int     blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+       int     eccbytes = 3;
+       int     compareecc = 1;
+       int     oobreadlen;
+
+
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd ,FL_READING);
+
+       /* use userspace supplied oobinfo, if zero */
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       
+       /* Autoplace of oob data ? Use the default placement scheme */
+       if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+               oobsel = this->autooob;
+               
+       eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+       oob_config = oobsel->eccpos;
+
+       /* Select the NAND device */
+       chipnr = (int)(from >> this->chip_shift);
+       this->select_chip(mtd, chipnr);
+
+       /* First we calculate the starting page */
+       realpage = (int) (from >> this->page_shift);
+       page = realpage & this->pagemask;
+
+       /* Get raw starting column */
+       col = from & (mtd->oobblock - 1);
+
+       end = mtd->oobblock;
+       ecc = this->eccsize;
+       switch (eccmode) {
+       case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
+               eccbytes = 6;
+               break;                                          
+       case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
+               eccbytes = 8;
+               break;
+       case NAND_ECC_NONE:
+               compareecc = 0;
+               break;                                          
+       }        
+
+       if (this->options & NAND_HWECC_SYNDROME)
+               compareecc = 0;
+
+       oobreadlen = mtd->oobsize;
+       if (this->options & NAND_HWECC_SYNDROME) 
+               oobreadlen -= oobsel->eccbytes;
+
+       /* Loop until all data read */
+       while (read < len) {
+               
+               int aligned = (!col && (len - read) >= end);
+               /* 
+                * If the read is not page aligned, we have to read into data buffer
+                * due to ecc, else we read into return buffer direct
+                */
+               if (aligned)
+                       data_poi = &buf[read];
+               else 
+                       data_poi = this->data_buf;
+               
+               /* Check, if we have this page in the buffer 
+                *
+                * FIXME: Make it work when we must provide oob data too,
+                * check the usage of data_buf oob field
+                */
+               if (realpage == this->pagebuf && !oob_buf) {
+                       /* aligned read ? */
+                       if (aligned)
+                               memcpy (data_poi, this->data_buf, end);
+                       goto readdata;
+               }
+
+               /* Check, if we must send the read command */
+               if (sndcmd) {
+                       this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+                       sndcmd = 0;
+               }       
+
+               /* get oob area, if we have no oob buffer from fs-driver */
+               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+                       oob_data = &this->data_buf[end];
+
+               eccsteps = this->eccsteps;
+               
+               switch (eccmode) {
+               case NAND_ECC_NONE: {   /* No ECC, Read in a page */
+                       static unsigned long lastwhinge = 0;
+                       if ((lastwhinge / HZ) != (jiffies / HZ)) {
+                               printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
+                               lastwhinge = jiffies;
+                       }
+                       this->read_buf(mtd, data_poi, end);
+                       break;
+               }
+                       
+               case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
+                       this->read_buf(mtd, data_poi, end);
+                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 
+                               this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
+                       break;  
+                       
+               case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */
+               case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */ 
+               case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
+               case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
+                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
+                               this->enable_hwecc(mtd, NAND_ECC_READ); 
+                               this->read_buf(mtd, &data_poi[datidx], ecc);
+
+                               /* HW ecc with syndrome calculation must read the
+                                * syndrome from flash immidiately after the data */
+                               if (!compareecc) {
+                                       /* Some hw ecc generators need to know when the
+                                        * syndrome is read from flash */
+                                       this->enable_hwecc(mtd, NAND_ECC_READSYN);
+                                       this->read_buf(mtd, &oob_data[i], eccbytes);
+                                       /* We calc error correction directly, it checks the hw
+                                        * generator for an error, reads back the syndrome and
+                                        * does the error correction on the fly */
+                                       if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+                                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 
+                                                       "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
+                                               ecc_failed++;
+                                       }
+                               } else {
+                                       this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
+                               }       
+                       }
+                       break;                                          
+
+               default:
+                       printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+                       BUG();  
+               }
+
+               /* read oobdata */
+               this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
+
+               /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
+               if (!compareecc)
+                       goto readoob;   
+               
+               /* Pick the ECC bytes out of the oob data */
+               for (j = 0; j < oobsel->eccbytes; j++)
+                       ecc_code[j] = oob_data[oob_config[j]];
+
+               /* correct data, if neccecary */
+               for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
+                       ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
+                       
+                       /* Get next chunk of ecc bytes */
+                       j += eccbytes;
+                       
+                       /* Check, if we have a fs supplied oob-buffer, 
+                        * This is the legacy mode. Used by YAFFS1
+                        * Should go away some day
+                        */
+                       if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 
+                               int *p = (int *)(&oob_data[mtd->oobsize]);
+                               p[i] = ecc_status;
+                       }
+                       
+                       if (ecc_status == -1) { 
+                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+                               ecc_failed++;
+                       }
+               }               
+
+       readoob:
+               /* check, if we have a fs supplied oob-buffer */
+               if (oob_buf) {
+                       /* without autoplace. Legacy mode used by YAFFS1 */
+                       switch(oobsel->useecc) {
+                       case MTD_NANDECC_AUTOPLACE:
+                               /* Walk through the autoplace chunks */
+                               for (i = 0, j = 0; j < mtd->oobavail; i++) {
+                                       int from = oobsel->oobfree[i][0];
+                                       int num = oobsel->oobfree[i][1];
+                                       memcpy(&oob_buf[oob], &oob_data[from], num);
+                                       j+= num;
+                               }
+                               oob += mtd->oobavail;
+                               break;
+                       case MTD_NANDECC_PLACE:
+                               /* YAFFS1 legacy mode */
+                               oob_data += this->eccsteps * sizeof (int);
+                       default:
+                               oob_data += mtd->oobsize;
+                       }
+               }
+       readdata:
+               /* Partial page read, transfer data into fs buffer */
+               if (!aligned) { 
+                       for (j = col; j < end && read < len; j++)
+                               buf[read++] = data_poi[j];
+                       this->pagebuf = realpage;       
+               } else          
+                       read += mtd->oobblock;
+
+               /* Apply delay or wait for ready/busy pin 
+                * Do this before the AUTOINCR check, so no problems
+                * arise if a chip which does auto increment
+                * is marked as NOAUTOINCR by the board driver.
+               */
+               if (!this->dev_ready) 
+                       udelay (this->chip_delay);
+               else
+                       while (!this->dev_ready(mtd));  
+                       
+               if (read == len)
+                       break;  
+
+               /* For subsequent reads align to page boundary. */
+               col = 0;
+               /* Increment page address */
+               realpage++;
+
+               page = realpage & this->pagemask;
+               /* Check, if we cross a chip boundary */
+               if (!page) {
+                       chipnr++;
+                       this->select_chip(mtd, -1);
+                       this->select_chip(mtd, chipnr);
+               }
+               /* Check, if the chip supports auto page increment 
+                * or if we have hit a block boundary. 
+               */ 
+               if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
+                       sndcmd = 1;                             
+       }
+
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       /*
+        * Return success, if no ECC failures, else -EBADMSG
+        * fs driver will take care of that, because
+        * retlen == desired len and result == -EBADMSG
+        */
+       *retlen = read;
+       return ecc_failed ? -EBADMSG : 0;
+}
+
+/**
+ * nand_read_oob - [MTD Interface] NAND read out-of-band
+ * @mtd:       MTD device structure
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @retlen:    pointer to variable to store the number of read bytes
+ * @buf:       the databuffer to put data
+ *
+ * NAND read out-of-band data from the spare area
+ */
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+{
+       int i, col, page, chipnr;
+       struct nand_chip *this = mtd->priv;
+       int     blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+       /* Shift to get page */
+       page = (int)(from >> this->page_shift);
+       chipnr = (int)(from >> this->chip_shift);
+       
+       /* Mask to get column */
+       col = from & (mtd->oobsize - 1);
+
+       /* Initialize return length value */
+       *retlen = 0;
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd , FL_READING);
+
+       /* Select the NAND device */
+       this->select_chip(mtd, chipnr);
+
+       /* Send the read command */
+       this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
+       /* 
+        * Read the data, if we read more than one page
+        * oob data, let the device transfer the data !
+        */
+       i = 0;
+       while (i < len) {
+               int thislen = mtd->oobsize - col;
+               thislen = min_t(int, thislen, len);
+               this->read_buf(mtd, &buf[i], thislen);
+               i += thislen;
+               
+               /* Apply delay or wait for ready/busy pin 
+                * Do this before the AUTOINCR check, so no problems
+                * arise if a chip which does auto increment
+                * is marked as NOAUTOINCR by the board driver.
+               */
+               if (!this->dev_ready) 
+                       udelay (this->chip_delay);
+               else
+                       while (!this->dev_ready(mtd));  
+
+               /* Read more ? */
+               if (i < len) {
+                       page++;
+                       col = 0;
+
+                       /* Check, if we cross a chip boundary */
+                       if (!(page & this->pagemask)) {
+                               chipnr++;
+                               this->select_chip(mtd, -1);
+                               this->select_chip(mtd, chipnr);
+                       }
+                               
+                       /* Check, if the chip supports auto page increment 
+                        * or if we have hit a block boundary. 
+                       */ 
+                       if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
+                               /* For subsequent page reads set offset to 0 */
+                               this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
+                       }
+               }
+       }
+
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       /* Return happy */
+       *retlen = len;
+       return 0;
+}
+
+/**
+ * nand_read_raw - [GENERIC] Read raw data including oob into buffer
+ * @mtd:       MTD device structure
+ * @buf:       temporary buffer
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @ooblen:    number of oob data bytes to read
+ *
+ * Read raw data including oob into buffer
+ */
+int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
+{
+       struct nand_chip *this = mtd->priv;
+       int page = (int) (from >> this->page_shift);
+       int chip = (int) (from >> this->chip_shift);
+       int sndcmd = 1;
+       int cnt = 0;
+       int pagesize = mtd->oobblock + mtd->oobsize;
+       int     blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd , FL_READING);
+
+       this->select_chip (mtd, chip);
+       
+       /* Add requested oob length */
+       len += ooblen;
+       
+       while (len) {
+               if (sndcmd)
+                       this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
+               sndcmd = 0;     
+
+               this->read_buf (mtd, &buf[cnt], pagesize);
+
+               len -= pagesize;
+               cnt += pagesize;
+               page++;
+               
+               if (!this->dev_ready) 
+                       udelay (this->chip_delay);
+               else
+                       while (!this->dev_ready(mtd));  
+                       
+               /* Check, if the chip supports auto page increment */ 
+               if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
+                       sndcmd = 1;
+       }
+
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+       return 0;
+}
+
+
+/** 
+ * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer 
+ * @mtd:       MTD device structure
+ * @fsbuf:     buffer given by fs driver
+ * @oobsel:    out of band selection structre
+ * @autoplace: 1 = place given buffer into the oob bytes
+ * @numpages:  number of pages to prepare
+ *
+ * Return:
+ * 1. Filesystem buffer available and autoplacement is off,
+ *    return filesystem buffer
+ * 2. No filesystem buffer or autoplace is off, return internal
+ *    buffer
+ * 3. Filesystem buffer is given and autoplace selected
+ *    put data from fs buffer into internal buffer and
+ *    retrun internal buffer
+ *
+ * Note: The internal buffer is filled with 0xff. This must
+ * be done only once, when no autoplacement happens
+ * Autoplacement sets the buffer dirty flag, which
+ * forces the 0xff fill before using the buffer again.
+ *
+*/
+static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
+               int autoplace, int numpages)
+{
+       struct nand_chip *this = mtd->priv;
+       int i, len, ofs;
+
+       /* Zero copy fs supplied buffer */
+       if (fsbuf && !autoplace) 
+               return fsbuf;
+
+       /* Check, if the buffer must be filled with ff again */
+       if (this->oobdirty) {   
+               memset (this->oob_buf, 0xff, 
+                       mtd->oobsize << (this->phys_erase_shift - this->page_shift));
+               this->oobdirty = 0;
+       }       
+       
+       /* If we have no autoplacement or no fs buffer use the internal one */
+       if (!autoplace || !fsbuf)
+               return this->oob_buf;
+       
+       /* Walk through the pages and place the data */
+       this->oobdirty = 1;
+       ofs = 0;
+       while (numpages--) {
+               for (i = 0, len = 0; len < mtd->oobavail; i++) {
+                       int to = ofs + oobsel->oobfree[i][0];
+                       int num = oobsel->oobfree[i][1];
+                       memcpy (&this->oob_buf[to], fsbuf, num);
+                       len += num;
+                       fsbuf += num;
+               }
+               ofs += mtd->oobavail;
+       }
+       return this->oob_buf;
+}
+
+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
+
+/**
+ * nand_write - [MTD Interface] compability function for nand_write_ecc
+ * @mtd:       MTD device structure
+ * @to:                offset to write to
+ * @len:       number of bytes to write
+ * @retlen:    pointer to variable to store the number of written bytes
+ * @buf:       the data to write
+ *
+ * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
+ *
+*/
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
+{
+       return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
+}
+                          
+/**
+ * nand_write_ecc - [MTD Interface] NAND write with ECC
+ * @mtd:       MTD device structure
+ * @to:                offset to write to
+ * @len:       number of bytes to write
+ * @retlen:    pointer to variable to store the number of written bytes
+ * @buf:       the data to write
+ * @eccbuf:    filesystem supplied oob data buffer
+ * @oobsel:    oob selection structure
+ *
+ * NAND write with ECC
+ */
+static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+                          size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
+{
+       int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
+       int autoplace = 0, numpages, totalpages;
+       struct nand_chip *this = mtd->priv;
+       u_char *oobbuf, *bufstart;
+       int     ppblock = (1 << (this->phys_erase_shift - this->page_shift));
+
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+
+       /* Initialize retlen, in case of early exit */
+       *retlen = 0;
+
+       /* Do not allow write past end of device */
+       if ((to + len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
+               return -EINVAL;
+       }
+
+       /* reject writes, which are not page aligned */ 
+       if (NOTALIGNED (to) || NOTALIGNED(len)) {
+               printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd, FL_WRITING);
+
+       /* Calculate chipnr */
+       chipnr = (int)(to >> this->chip_shift);
+       /* Select the NAND device */
+       this->select_chip(mtd, chipnr);
+
+       /* Check, if it is write protected */
+       if (nand_check_wp(mtd))
+               goto out;
+
+       /* if oobsel is NULL, use chip defaults */
+       if (oobsel == NULL) 
+               oobsel = &mtd->oobinfo;         
+               
+       /* Autoplace of oob data ? Use the default placement scheme */
+       if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
+               oobsel = this->autooob;
+               autoplace = 1;
+       }       
+
+       /* Setup variables and oob buffer */
+       totalpages = len >> this->page_shift;
+       page = (int) (to >> this->page_shift);
+       /* Invalidate the page cache, if we write to the cached page */
+       if (page <= this->pagebuf && this->pagebuf < (page + totalpages))  
+               this->pagebuf = -1;
+       
+       /* Set it relative to chip */
+       page &= this->pagemask;
+       startpage = page;
+       /* Calc number of pages we can write in one go */
+       numpages = min (ppblock - (startpage  & (ppblock - 1)), totalpages);
+       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages);
+       bufstart = (u_char *)buf;
+
+       /* Loop until all data is written */
+       while (written < len) {
+
+               this->data_poi = (u_char*) &buf[written];
+               /* Write one page. If this is the last page to write
+                * or the last page in this block, then use the
+                * real pageprogram command, else select cached programming
+                * if supported by the chip.
+                */
+               ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
+               if (ret) {
+                       DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
+                       goto out;
+               }       
+               /* Next oob page */
+               oob += mtd->oobsize;
+               /* Update written bytes count */
+               written += mtd->oobblock;
+               if (written == len) 
+                       goto cmp;
+               
+               /* Increment page address */
+               page++;
+
+               /* Have we hit a block boundary ? Then we have to verify and
+                * if verify is ok, we have to setup the oob buffer for
+                * the next pages.
+               */
+               if (!(page & (ppblock - 1))){
+                       int ofs;
+                       this->data_poi = bufstart;
+                       ret = nand_verify_pages (mtd, this, startpage, 
+                               page - startpage,
+                               oobbuf, oobsel, chipnr, (eccbuf != NULL));
+                       if (ret) {
+                               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
+                               goto out;
+                       }       
+                       *retlen = written;
+
+                       ofs = autoplace ? mtd->oobavail : mtd->oobsize;
+                       if (eccbuf)
+                               eccbuf += (page - startpage) * ofs;
+                       totalpages -= page - startpage;
+                       numpages = min (totalpages, ppblock);
+                       page &= this->pagemask;
+                       startpage = page;
+                       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, 
+                                       autoplace, numpages);
+                       /* Check, if we cross a chip boundary */
+                       if (!page) {
+                               chipnr++;
+                               this->select_chip(mtd, -1);
+                               this->select_chip(mtd, chipnr);
+                       }
+               }
+       }
+       /* Verify the remaining pages */
+cmp:
+       this->data_poi = bufstart;
+       ret = nand_verify_pages (mtd, this, startpage, totalpages,
+               oobbuf, oobsel, chipnr, (eccbuf != NULL));
+       if (!ret)
+               *retlen = written;
+       else    
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
+
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       return ret;
+}
+
+
+/**
+ * nand_write_oob - [MTD Interface] NAND write out-of-band
+ * @mtd:       MTD device structure
+ * @to:                offset to write to
+ * @len:       number of bytes to write
+ * @retlen:    pointer to variable to store the number of written bytes
+ * @buf:       the data to write
+ *
+ * NAND write out-of-band
+ */
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
+{
+       int column, page, status, ret = -EIO, chipnr;
+       struct nand_chip *this = mtd->priv;
+
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+
+       /* Shift to get page */
+       page = (int) (to >> this->page_shift);
+       chipnr = (int) (to >> this->chip_shift);
+
+       /* Mask to get column */
+       column = to & (mtd->oobsize - 1);
+
+       /* Initialize return length value */
+       *retlen = 0;
+
+       /* Do not allow write past end of page */
+       if ((column + len) > mtd->oobsize) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd, FL_WRITING);
+
+       /* Select the NAND device */
+       this->select_chip(mtd, chipnr);
+
+       /* Reset the chip. Some chips (like the Toshiba TC5832DC found
+          in one of my DiskOnChip 2000 test units) will clear the whole
+          data page too if we don't do this. I have no clue why, but
+          I seem to have 'fixed' it in the doc2000 driver in
+          August 1999.  dwmw2. */
+       this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+       /* Check, if it is write protected */
+       if (nand_check_wp(mtd))
+               goto out;
+       
+       /* Invalidate the page cache, if we write to the cached page */
+       if (page == this->pagebuf)
+               this->pagebuf = -1;
+
+       if (NAND_MUST_PAD(this)) {
+               /* Write out desired data */
+               this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
+               /* prepad 0xff for partial programming */
+               this->write_buf(mtd, ffchars, column);
+               /* write data */
+               this->write_buf(mtd, buf, len);
+               /* postpad 0xff for partial programming */
+               this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
+       } else {
+               /* Write out desired data */
+               this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
+               /* write data */
+               this->write_buf(mtd, buf, len);
+       }
+       /* Send command to program the OOB data */
+       this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+       status = this->waitfunc (mtd, this, FL_WRITING);
+
+       /* See if device thinks it succeeded */
+       if (status & 0x01) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
+               ret = -EIO;
+               goto out;
+       }
+       /* Return happy */
+       *retlen = len;
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+       /* Send command to read back the data */
+       this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask);
+
+       if (this->verify_buf(mtd, buf, len)) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
+               ret = -EIO;
+               goto out;
+       }
+#endif
+       ret = 0;
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       return ret;
+}
+
+
+/**
+ * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
+ * @mtd:       MTD device structure
+ * @vecs:      the iovectors to write
+ * @count:     number of vectors
+ * @to:                offset to write to
+ * @retlen:    pointer to variable to store the number of written bytes
+ *
+ * NAND write with kvec. This just calls the ecc function
+ */
+static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+               loff_t to, size_t * retlen)
+{
+       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));    
+}
+
+/**
+ * nand_writev_ecc - [MTD Interface] write with iovec with ecc
+ * @mtd:       MTD device structure
+ * @vecs:      the iovectors to write
+ * @count:     number of vectors
+ * @to:                offset to write to
+ * @retlen:    pointer to variable to store the number of written bytes
+ * @eccbuf:    filesystem supplied oob data buffer
+ * @oobsel:    oob selection structure
+ *
+ * NAND write with iovec with ecc
+ */
+static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+               loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+       int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
+       int oob, numpages, autoplace = 0, startpage;
+       struct nand_chip *this = mtd->priv;
+       int     ppblock = (1 << (this->phys_erase_shift - this->page_shift));
+       u_char *oobbuf, *bufstart;
+
+       /* Preset written len for early exit */
+       *retlen = 0;
+
+       /* Calculate total length of data */
+       total_len = 0;
+       for (i = 0; i < count; i++)
+               total_len += (int) vecs[i].iov_len;
+
+       DEBUG (MTD_DEBUG_LEVEL3,
+              "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
+
+       /* Do not allow write past end of page */
+       if ((to + total_len) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
+               return -EINVAL;
+       }
+
+       /* reject writes, which are not page aligned */ 
+       if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
+               printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd, FL_WRITING);
+
+       /* Get the current chip-nr */
+       chipnr = (int) (to >> this->chip_shift);
+       /* Select the NAND device */
+       this->select_chip(mtd, chipnr);
+
+       /* Check, if it is write protected */
+       if (nand_check_wp(mtd))
+               goto out;
+
+       /* if oobsel is NULL, use chip defaults */
+       if (oobsel == NULL) 
+               oobsel = &mtd->oobinfo;         
+
+       /* Autoplace of oob data ? Use the default placement scheme */
+       if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
+               oobsel = this->autooob;
+               autoplace = 1;
+       }       
+
+       /* Setup start page */
+       page = (int) (to >> this->page_shift);
+       /* Invalidate the page cache, if we write to the cached page */
+       if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))  
+               this->pagebuf = -1;
+
+       startpage = page & this->pagemask;
+
+       /* Loop until all kvec' data has been written */
+       len = 0;
+       while (count) {
+               /* If the given tuple is >= pagesize then
+                * write it out from the iov
+                */
+               if ((vecs->iov_len - len) >= mtd->oobblock) {
+                       /* Calc number of pages we can write
+                        * out of this iov in one go */
+                       numpages = (vecs->iov_len - len) >> this->page_shift;
+                       /* Do not cross block boundaries */
+                       numpages = min (ppblock - (startpage & (ppblock - 1)), numpages);
+                       oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
+                       bufstart = (u_char *)vecs->iov_base;
+                       bufstart += len;
+                       this->data_poi = bufstart;
+                       oob = 0;
+                       for (i = 1; i <= numpages; i++) {
+                               /* Write one page. If this is the last page to write
+                                * then use the real pageprogram command, else select 
+                                * cached programming if supported by the chip.
+                                */
+                               ret = nand_write_page (mtd, this, page & this->pagemask, 
+                                       &oobbuf[oob], oobsel, i != numpages);
+                               if (ret)
+                                       goto out;
+                               this->data_poi += mtd->oobblock;
+                               len += mtd->oobblock;
+                               oob += mtd->oobsize;
+                               page++;
+                       }
+                       /* Check, if we have to switch to the next tuple */
+                       if (len >= (int) vecs->iov_len) {
+                               vecs++;
+                               len = 0;
+                               count--;
+                       }
+               } else {
+                       /* We must use the internal buffer, read data out of each 
+                        * tuple until we have a full page to write
+                        */
+                       int cnt = 0;
+                       while (cnt < mtd->oobblock) {
+                               if (vecs->iov_base != NULL && vecs->iov_len) 
+                                       this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
+                               /* Check, if we have to switch to the next tuple */
+                               if (len >= (int) vecs->iov_len) {
+                                       vecs++;
+                                       len = 0;
+                                       count--;
+                               }
+                       }
+                       this->pagebuf = page;   
+                       this->data_poi = this->data_buf;        
+                       bufstart = this->data_poi;
+                       numpages = 1;           
+                       oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
+                       ret = nand_write_page (mtd, this, page & this->pagemask,
+                               oobbuf, oobsel, 0);
+                       if (ret)
+                               goto out;
+                       page++;
+               }
+
+               this->data_poi = bufstart;
+               ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
+               if (ret)
+                       goto out;
+                       
+               written += mtd->oobblock * numpages;
+               /* All done ? */
+               if (!count)
+                       break;
+
+               startpage = page & this->pagemask;
+               /* Check, if we cross a chip boundary */
+               if (!startpage) {
+                       chipnr++;
+                       this->select_chip(mtd, -1);
+                       this->select_chip(mtd, chipnr);
+               }
+       }
+       ret = 0;
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       *retlen = written;
+       return ret;
+}
+
+/**
+ * single_erease_cmd - [GENERIC] NAND standard block erase command function
+ * @mtd:       MTD device structure
+ * @page:      the page address of the block which will be erased
+ *
+ * Standard erase command for NAND chips
+ */
+static void single_erase_cmd (struct mtd_info *mtd, int page)
+{
+       struct nand_chip *this = mtd->priv;
+       /* Send commands to erase a block */
+       this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+       this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
+}
+
+/**
+ * multi_erease_cmd - [GENERIC] AND specific block erase command function
+ * @mtd:       MTD device structure
+ * @page:      the page address of the block which will be erased
+ *
+ * AND multi block erase command function
+ * Erase 4 consecutive blocks
+ */
+static void multi_erase_cmd (struct mtd_info *mtd, int page)
+{
+       struct nand_chip *this = mtd->priv;
+       /* Send commands to erase a block */
+       this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
+       this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
+       this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
+       this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+       this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
+}
+
+/**
+ * nand_erase - [MTD Interface] erase block(s)
+ * @mtd:       MTD device structure
+ * @instr:     erase instruction
+ *
+ * Erase one ore more blocks
+ */
+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+       return nand_erase_nand (mtd, instr, 0);
+}
+/**
+ * nand_erase_intern - [NAND Interface] erase block(s)
+ * @mtd:       MTD device structure
+ * @instr:     erase instruction
+ * @allowbbt:  allow erasing the bbt area
+ *
+ * Erase one ore more blocks
+ */
+int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
+{
+       int page, len, status, pages_per_block, ret, chipnr;
+       struct nand_chip *this = mtd->priv;
+
+       DEBUG (MTD_DEBUG_LEVEL3,
+              "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
+
+       /* Start address must align on block boundary */
+       if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
+               return -EINVAL;
+       }
+
+       /* Length must align on block boundary */
+       if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
+               return -EINVAL;
+       }
+
+       /* Do not allow erase past end of device */
+       if ((instr->len + instr->addr) > mtd->size) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
+               return -EINVAL;
+       }
+
+       instr->fail_addr = 0xffffffff;
+
+       /* Grab the lock and see if the device is available */
+       nand_get_chip (this, mtd, FL_ERASING);
+
+       /* Shift to get first page */
+       page = (int) (instr->addr >> this->page_shift);
+       chipnr = (int) (instr->addr >> this->chip_shift);
+
+       /* Calculate pages in each block */
+       pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
+
+       /* Select the NAND device */
+       this->select_chip(mtd, chipnr);
+
+       /* Check the WP bit */
+       /* Check, if it is write protected */
+       if (nand_check_wp(mtd)) {
+               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+               instr->state = MTD_ERASE_FAILED;
+               goto erase_exit;
+       }
+
+       /* Loop through the pages */
+       len = instr->len;
+
+       instr->state = MTD_ERASING;
+
+       while (len) {
+               /* Check if we have a bad block, we do not erase bad blocks ! */
+               if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
+                       printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
+                       instr->state = MTD_ERASE_FAILED;
+                       goto erase_exit;
+               }
+               
+               /* Invalidate the page cache, if we erase the block which contains 
+                  the current cached page */
+               if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
+                       this->pagebuf = -1;
+
+               this->erase_cmd (mtd, page & this->pagemask);
+               
+               status = this->waitfunc (mtd, this, FL_ERASING);
+
+               /* See if block erase succeeded */
+               if (status & 0x01) {
+                       DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
+                       instr->state = MTD_ERASE_FAILED;
+                       instr->fail_addr = (page << this->page_shift);
+                       goto erase_exit;
+               }
+               
+               /* Increment page address and decrement length */
+               len -= (1 << this->phys_erase_shift);
+               page += pages_per_block;
+
+               /* Check, if we cross a chip boundary */
+               if (len && !(page & this->pagemask)) {
+                       chipnr++;
+                       this->select_chip(mtd, -1);
+                       this->select_chip(mtd, chipnr);
+               }
+       }
+       instr->state = MTD_ERASE_DONE;
+
+erase_exit:
+
+       ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+       /* Do call back function */
+       if (!ret)
+               mtd_erase_callback(instr);
+
+       /* Deselect and wake up anyone waiting on the device */
+       nand_release_chip(mtd);
+
+       /* Return more or less happy */
+       return ret;
+}
+
+/**
+ * nand_sync - [MTD Interface] sync
+ * @mtd:       MTD device structure
+ *
+ * Sync is actually a wait for chip ready function
+ */
+static void nand_sync (struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       DECLARE_WAITQUEUE (wait, current);
+
+       DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+
+retry:
+       /* Grab the spinlock */
+       spin_lock_bh (&this->chip_lock);
+
+       /* See what's going on */
+       switch (this->state) {
+       case FL_READY:
+       case FL_SYNCING:
+               this->state = FL_SYNCING;
+               spin_unlock_bh (&this->chip_lock);
+               break;
+
+       default:
+               /* Not an idle state */
+               add_wait_queue (&this->wq, &wait);
+               spin_unlock_bh (&this->chip_lock);
+               schedule ();
+
+               remove_wait_queue (&this->wq, &wait);
+               goto retry;
+       }
+
+       /* Lock the device */
+       spin_lock_bh (&this->chip_lock);
+
+       /* Set the device to be ready again */
+       if (this->state == FL_SYNCING) {
+               this->state = FL_READY;
+               wake_up (&this->wq);
+       }
+
+       /* Unlock the device */
+       spin_unlock_bh (&this->chip_lock);
+}
+
+
+/**
+ * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
+ * @mtd:       MTD device structure
+ * @ofs:       offset relative to mtd start
+ */
+static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
+{
+       /* Check for invalid offset */
+       if (ofs > mtd->size) 
+               return -EINVAL;
+       
+       return nand_block_checkbad (mtd, ofs, 1, 0);
+}
+
+/**
+ * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
+ * @mtd:       MTD device structure
+ * @ofs:       offset relative to mtd start
+ */
+static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_chip *this = mtd->priv;
+       int ret;
+
+        if ((ret = nand_block_isbad(mtd, ofs))) {
+               /* If it was bad already, return success and do nothing. */
+               if (ret > 0)
+                       return 0;
+               return ret;
+        }
+
+       return this->block_markbad(mtd, ofs);
+}
+
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd:       MTD device structure
+ * @maxchips:  Number of chips to scan for
+ *
+ * This fills out all the not initialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values. Buffers are allocated if
+ * they are not provided by the board driver
+ *
+ */
+int nand_scan (struct mtd_info *mtd, int maxchips)
+{
+       int i, j, nand_maf_id, nand_dev_id, busw;
+       struct nand_chip *this = mtd->priv;
+
+       /* Get buswidth to select the correct functions*/
+       busw = this->options & NAND_BUSWIDTH_16;
+
+       /* check for proper chip_delay setup, set 20us if not */
+       if (!this->chip_delay)
+               this->chip_delay = 20;
+
+       /* check, if a user supplied command function given */
+       if (this->cmdfunc == NULL)
+               this->cmdfunc = nand_command;
+
+       /* check, if a user supplied wait function given */
+       if (this->waitfunc == NULL)
+               this->waitfunc = nand_wait;
+
+       if (!this->select_chip)
+               this->select_chip = nand_select_chip;
+       if (!this->write_byte)
+               this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
+       if (!this->read_byte)
+               this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
+       if (!this->write_word)
+               this->write_word = nand_write_word;
+       if (!this->read_word)
+               this->read_word = nand_read_word;
+       if (!this->block_bad)
+               this->block_bad = nand_block_bad;
+       if (!this->block_markbad)
+               this->block_markbad = nand_default_block_markbad;
+       if (!this->write_buf)
+               this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+       if (!this->read_buf)
+               this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+       if (!this->verify_buf)
+               this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
+       if (!this->scan_bbt)
+               this->scan_bbt = nand_default_bbt;
+
+       /* Select the device */
+       this->select_chip(mtd, 0);
+
+       /* Send the command for reading device ID */
+       this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
+
+       /* Read manufacturer and device IDs */
+       nand_maf_id = this->read_byte(mtd);
+       nand_dev_id = this->read_byte(mtd);
+
+       /* Print and store flash device information */
+       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+                               
+               if (nand_dev_id != nand_flash_ids[i].id) 
+                       continue;
+
+               if (!mtd->name) mtd->name = nand_flash_ids[i].name;
+               this->chipsize = nand_flash_ids[i].chipsize << 20;
+               
+               /* New devices have all the information in additional id bytes */
+               if (!nand_flash_ids[i].pagesize) {
+                       int extid;
+                       /* The 3rd id byte contains non relevant data ATM */
+                       extid = this->read_byte(mtd);
+                       /* The 4th id byte is the important one */
+                       extid = this->read_byte(mtd);
+                       /* Calc pagesize */
+                       mtd->oobblock = 1024 << (extid & 0x3);
+                       extid >>= 2;
+                       /* Calc oobsize */
+                       mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
+                       extid >>= 2;
+                       /* Calc blocksize. Blocksize is multiples of 64KiB */
+                       mtd->erasesize = (64 * 1024)  << (extid & 0x03);
+                       extid >>= 2;
+                       /* Get buswidth information */
+                       busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+               
+               } else {
+                       /* Old devices have this data hardcoded in the
+                        * device id table */
+                       mtd->erasesize = nand_flash_ids[i].erasesize;
+                       mtd->oobblock = nand_flash_ids[i].pagesize;
+                       mtd->oobsize = mtd->oobblock / 32;
+                       busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
+               }
+
+               /* Check, if buswidth is correct. Hardware drivers should set
+                * this correct ! */
+               if (busw != (this->options & NAND_BUSWIDTH_16)) {
+                       printk (KERN_INFO "NAND device: Manufacturer ID:"
+                               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+                               nand_manuf_ids[i].name , mtd->name);
+                       printk (KERN_WARNING 
+                               "NAND bus width %d instead %d bit\n", 
+                                       (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
+                                       busw ? 16 : 8);
+                       this->select_chip(mtd, -1);
+                       return 1;       
+               }
+               
+               /* Calculate the address shift from the page size */    
+               this->page_shift = ffs(mtd->oobblock) - 1;
+               this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
+               this->chip_shift = ffs(this->chipsize) - 1;
+
+               /* Set the bad block position */
+               this->badblockpos = mtd->oobblock > 512 ? 
+                       NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
+
+               /* Get chip options, preserve non chip based options */
+               this->options &= ~NAND_CHIPOPTIONS_MSK;
+               this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
+               /* Set this as a default. Board drivers can override it, if neccecary */
+               this->options |= NAND_NO_AUTOINCR;
+               /* Check if this is a not a samsung device. Do not clear the options
+                * for chips which are not having an extended id.
+                */     
+               if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
+                       this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+               
+               /* Check for AND chips with 4 page planes */
+               if (this->options & NAND_4PAGE_ARRAY)
+                       this->erase_cmd = multi_erase_cmd;
+               else
+                       this->erase_cmd = single_erase_cmd;
+
+               /* Do not replace user supplied command function ! */
+               if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
+                       this->cmdfunc = nand_command_lp;
+                               
+               /* Try to identify manufacturer */
+               for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+                       if (nand_manuf_ids[j].id == nand_maf_id)
+                               break;
+               }
+               printk (KERN_INFO "NAND device: Manufacturer ID:"
+                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+                       nand_manuf_ids[j].name , nand_flash_ids[i].name);
+               break;
+       }
+
+       if (!nand_flash_ids[i].name) {
+               printk (KERN_WARNING "No NAND device found!!!\n");
+               this->select_chip(mtd, -1);
+               return 1;
+       }
+
+       for (i=1; i < maxchips; i++) {
+               this->select_chip(mtd, i);
+
+               /* Send the command for reading device ID */
+               this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
+
+               /* Read manufacturer and device IDs */
+               if (nand_maf_id != this->read_byte(mtd) ||
+                   nand_dev_id != this->read_byte(mtd))
+                       break;
+       }
+       if (i > 1)
+               printk(KERN_INFO "%d NAND chips detected\n", i);
+       
+       /* Allocate buffers, if neccecary */
+       if (!this->oob_buf) {
+               size_t len;
+               len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
+               this->oob_buf = kmalloc (len, GFP_KERNEL);
+               if (!this->oob_buf) {
+                       printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
+                       return -ENOMEM;
+               }
+               this->options |= NAND_OOBBUF_ALLOC;
+       }
+       
+       if (!this->data_buf) {
+               size_t len;
+               len = mtd->oobblock + mtd->oobsize;
+               this->data_buf = kmalloc (len, GFP_KERNEL);
+               if (!this->data_buf) {
+                       if (this->options & NAND_OOBBUF_ALLOC)
+                               kfree (this->oob_buf);
+                       printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
+                       return -ENOMEM;
+               }
+               this->options |= NAND_DATABUF_ALLOC;
+       }
+
+       /* Store the number of chips and calc total size for mtd */
+       this->numchips = i;
+       mtd->size = i * this->chipsize;
+       /* Convert chipsize to number of pages per chip -1. */
+       this->pagemask = (this->chipsize >> this->page_shift) - 1;
+       /* Preset the internal oob buffer */
+       memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
+
+       /* If no default placement scheme is given, select an
+        * appropriate one */
+       if (!this->autooob) {
+               /* Select the appropriate default oob placement scheme for
+                * placement agnostic filesystems */
+               switch (mtd->oobsize) { 
+               case 8:
+                       this->autooob = &nand_oob_8;
+                       break;
+               case 16:
+                       this->autooob = &nand_oob_16;
+                       break;
+               case 64:
+                       this->autooob = &nand_oob_64;
+                       break;
+               default:
+                       printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
+                               mtd->oobsize);
+                       BUG();
+               }
+       }
+       
+       /* The number of bytes available for the filesystem to place fs dependend
+        * oob data */
+       if (this->options & NAND_BUSWIDTH_16) {
+               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
+               if (this->autooob->eccbytes & 0x01)
+                       mtd->oobavail--;
+       } else
+               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+
+       /* 
+        * check ECC mode, default to software
+        * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
+        * fallback to software ECC 
+       */
+       this->eccsize = 256;    /* set default eccsize */       
+
+       switch (this->eccmode) {
+
+       case NAND_ECC_HW3_512: 
+       case NAND_ECC_HW6_512: 
+       case NAND_ECC_HW8_512: 
+               if (mtd->oobblock == 256) {
+                       printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
+                       this->eccmode = NAND_ECC_SOFT;
+                       this->calculate_ecc = nand_calculate_ecc;
+                       this->correct_data = nand_correct_data;
+                       break;          
+               } else 
+                       this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
+
+       case NAND_ECC_HW3_256:
+               if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+                       break;
+               printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+               BUG();  
+
+       case NAND_ECC_NONE: 
+               printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
+               this->eccmode = NAND_ECC_NONE;
+               break;
+
+       case NAND_ECC_SOFT:     
+               this->calculate_ecc = nand_calculate_ecc;
+               this->correct_data = nand_correct_data;
+               break;
+
+       default:
+               printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+               BUG();  
+       }       
+       
+       mtd->eccsize = this->eccsize;
+       
+       /* Set the number of read / write steps for one page to ensure ECC generation */
+       switch (this->eccmode) {
+       case NAND_ECC_HW3_512:
+       case NAND_ECC_HW6_512:
+       case NAND_ECC_HW8_512:
+               this->eccsteps = mtd->oobblock / 512;
+               break;
+       case NAND_ECC_HW3_256:
+       case NAND_ECC_SOFT:     
+               this->eccsteps = mtd->oobblock / 256;
+               break;
+               
+       case NAND_ECC_NONE: 
+               this->eccsteps = 1;
+               break;
+       }
+       
+       /* Initialize state, waitqueue and spinlock */
+       this->state = FL_READY;
+       init_waitqueue_head (&this->wq);
+       spin_lock_init (&this->chip_lock);
+
+       /* De-select the device */
+       this->select_chip(mtd, -1);
+
+       /* Invalidate the pagebuffer reference */
+       this->pagebuf = -1;
+
+       /* Fill in remaining MTD driver data */
+       mtd->type = MTD_NANDFLASH;
+       mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+       mtd->ecctype = MTD_ECC_SW;
+       mtd->erase = nand_erase;
+       mtd->point = NULL;
+       mtd->unpoint = NULL;
+       mtd->read = nand_read;
+       mtd->write = nand_write;
+       mtd->read_ecc = nand_read_ecc;
+       mtd->write_ecc = nand_write_ecc;
+       mtd->read_oob = nand_read_oob;
+       mtd->write_oob = nand_write_oob;
+       mtd->readv = NULL;
+       mtd->writev = nand_writev;
+       mtd->writev_ecc = nand_writev_ecc;
+       mtd->sync = nand_sync;
+       mtd->lock = NULL;
+       mtd->unlock = NULL;
+       mtd->suspend = NULL;
+       mtd->resume = NULL;
+       mtd->block_isbad = nand_block_isbad;
+       mtd->block_markbad = nand_block_markbad;
+
+       /* and make the autooob the default one */
+       memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
+
+       mtd->owner = THIS_MODULE;
+
+       /* Build bad block table */
+       return this->scan_bbt (mtd);
+}
+
+/**
+ * nand_release - [NAND Interface] Free resources held by the NAND device 
+ * @mtd:       MTD device structure
+*/
+void nand_release (struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       /* Deregister partitions */
+       del_mtd_partitions (mtd);
+#endif
+       /* Deregister the device */
+       del_mtd_device (mtd);
+
+       /* Free bad block table memory, if allocated */
+       if (this->bbt)
+               kfree (this->bbt);
+       /* Buffer allocated by nand_scan ? */
+       if (this->options & NAND_OOBBUF_ALLOC)
+               kfree (this->oob_buf);
+       /* Buffer allocated by nand_scan ? */
+       if (this->options & NAND_DATABUF_ALLOC)
+               kfree (this->data_buf);
+}
+
+EXPORT_SYMBOL (nand_scan);
+EXPORT_SYMBOL (nand_release);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff --git a/drivers/mtd/nand/tx4925ndfmc.c b/drivers/mtd/nand/tx4925ndfmc.c
new file mode 100644 (file)
index 0000000..5f6a2f5
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  drivers/mtd/tx4925ndfmc.c
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports 
+ *   16MiB, 32MiB and 64MiB cards.
+ *
+ * Author: MontaVista Software, Inc.  source@mvista.com
+ *
+ * Derived from drivers/mtd/autcpu12.c
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: tx4925ndfmc.c,v 1.3 2004/07/20 02:44:26 dwmw2 Exp $
+ *
+ * Copyright (C) 2001 Toshiba Corporation 
+ * 
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/tx4925/tx4925_nand.h>
+
+extern struct nand_oobinfo jffs2_oobinfo;
+
+/*
+ * MTD structure for RBTX4925 board
+ */
+static struct mtd_info *tx4925ndfmc_mtd = NULL;
+
+/*
+ * Define partitions for flash devices
+ */
+
+static struct mtd_partition partition_info16k[] = {
+       { .name = "RBTX4925 flash partition 1",
+         .offset =  0,
+         .size =    8 * 0x00100000 },
+       { .name = "RBTX4925 flash partition 2",
+         .offset =  8 * 0x00100000,
+         .size =    8 * 0x00100000 },
+};
+
+static struct mtd_partition partition_info32k[] = {
+       { .name = "RBTX4925 flash partition 1",
+         .offset =  0,
+         .size =    8 * 0x00100000 },
+       { .name = "RBTX4925 flash partition 2",
+         .offset = 8 * 0x00100000,
+         .size =  24 * 0x00100000 },
+};
+
+static struct mtd_partition partition_info64k[] = {
+       { .name = "User FS",
+         .offset =  0,
+         .size =   16 * 0x00100000 },
+       { .name = "RBTX4925 flash partition 2",
+         .offset = 16 * 0x00100000,
+         .size =   48 * 0x00100000},
+};
+
+static struct mtd_partition partition_info128k[] = {
+       { .name = "Skip bad section",
+         .offset =  0,
+         .size =   16 * 0x00100000 },
+       { .name = "User FS",
+         .offset = 16 * 0x00100000,
+         .size =   112 * 0x00100000 },
+};
+#define NUM_PARTITIONS16K  2
+#define NUM_PARTITIONS32K  2
+#define NUM_PARTITIONS64K  2
+#define NUM_PARTITIONS128K 2
+
+/* 
+ *     hardware specific access to control-lines
+*/
+static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+
+       switch(cmd){
+
+               case NAND_CTL_SETCLE: 
+                       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE;
+                       break;
+               case NAND_CTL_CLRCLE:
+                       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE;
+                       break;
+               case NAND_CTL_SETALE:
+                       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE;
+                       break;
+               case NAND_CTL_CLRALE: 
+                       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE;
+                       break;
+               case NAND_CTL_SETNCE:
+                       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE;
+                       break;
+               case NAND_CTL_CLRNCE:
+                       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE;
+                       break;
+               case NAND_CTL_SETWP:
+                       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE;
+                       break;
+               case NAND_CTL_CLRWP:
+                       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE;
+                       break;
+       }
+}
+
+/*
+*      read device ready pin
+*/
+static int tx4925ndfmc_device_ready(struct mtd_info *mtd)
+{
+       int ready;
+       ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1;
+       return ready;
+}
+void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       /* reset first */
+       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK;
+       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
+       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB;
+}
+static void tx4925ndfmc_disable_ecc(void)
+{
+       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
+}
+static void tx4925ndfmc_enable_read_ecc(void)
+{
+       tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
+       tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ;
+}
+void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){
+       int i;
+       u_char *ecc = ecc_code;
+        tx4925ndfmc_enable_read_ecc();
+       for (i = 0;i < 6;i++,ecc++)
+               *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr));
+        tx4925ndfmc_disable_ecc();
+}
+void tx4925ndfmc_device_setup(void)
+{
+
+       *(unsigned char *)0xbb005000 &= ~0x08;
+
+        /* reset NDFMC */
+        tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST;
+       while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST);       
+
+       /* setup BusSeparete, Hold Time, Strobe Pulse Width */
+       tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0;
+       tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW;             
+}
+static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd)
+{
+        struct nand_chip *this = mtd->priv;
+        return tx4925_read_nfmc(this->IO_ADDR_R);
+}
+
+static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+        struct nand_chip *this = mtd->priv;
+        tx4925_write_nfmc(byte, this->IO_ADDR_W);
+}
+
+static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               tx4925_write_nfmc(buf[i], this->IO_ADDR_W);
+}
+
+static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               buf[i] = tx4925_read_nfmc(this->IO_ADDR_R);
+}
+
+static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+       struct nand_chip *this = mtd->priv;
+
+       for (i=0; i<len; i++)
+               if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R))
+                       return -EFAULT;
+
+       return 0;
+}
+
+/*
+ * Send command to NAND device
+ */
+static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       register struct nand_chip *this = mtd->priv;
+
+       /* Begin command latch cycle */
+       this->hwcontrol(mtd, NAND_CTL_SETCLE);
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->oobblock) {
+                       /* OOB area */
+                       column -= mtd->oobblock;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               this->write_byte(mtd, readcmd);
+       }
+       this->write_byte(mtd, command);
+
+       /* Set ALE and clear CLE to start address cycle */
+       this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+       if (column != -1 || page_addr != -1) {
+               this->hwcontrol(mtd, NAND_CTL_SETALE);
+
+               /* Serially input address */
+               if (column != -1)
+                       this->write_byte(mtd, column);
+               if (page_addr != -1) {
+                       this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
+                       this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+                       /* One more address cycle for higher density devices */
+                       if (mtd->size & 0x0c000000) 
+                               this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
+               }
+               /* Latch in address */
+               this->hwcontrol(mtd, NAND_CTL_CLRALE);
+       }
+       
+       /* 
+        * program and erase have their own busy handlers 
+        * status and sequential in needs no delay
+       */
+       switch (command) {
+                       
+       case NAND_CMD_PAGEPROG:
+               /* Turn off WE */
+               this->hwcontrol (mtd, NAND_CTL_CLRWP);
+                return;
+
+       case NAND_CMD_SEQIN:
+               /* Turn on WE */
+               this->hwcontrol (mtd, NAND_CTL_SETWP);
+                return;
+
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_STATUS:
+               return;
+
+       case NAND_CMD_RESET:
+               if (this->dev_ready)    
+                       break;
+               this->hwcontrol(mtd, NAND_CTL_SETCLE);
+               this->write_byte(mtd, NAND_CMD_STATUS);
+               this->hwcontrol(mtd, NAND_CTL_CLRCLE);
+               while ( !(this->read_byte(mtd) & 0x40));
+               return;
+
+       /* This applies to read commands */     
+       default:
+               /* 
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+               */
+               if (!this->dev_ready) {
+                       udelay (this->chip_delay);
+                       return;
+               }       
+       }
+       
+       /* wait until command is processed */
+       while (!this->dev_ready(mtd));
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio
+n **pparts, char *);
+#endif
+
+/*
+ * Main initialization routine
+ */
+extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+int __init tx4925ndfmc_init (void)
+{
+       struct nand_chip *this;
+       int err = 0;
+
+       /* Allocate memory for MTD device structure and private data */
+       tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+                               GFP_KERNEL);
+       if (!tx4925ndfmc_mtd) {
+               printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+        tx4925ndfmc_device_setup();
+
+       /* io is indirect via a register so don't need to ioremap address */
+
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]);
+
+       /* Initialize structures */
+       memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       tx4925ndfmc_mtd->priv = this;
+
+       /* Set address of NAND IO lines */
+       this->IO_ADDR_R = (unsigned long)&(tx4925_ndfmcptr->dtr);
+       this->IO_ADDR_W = (unsigned long)&(tx4925_ndfmcptr->dtr);
+       this->hwcontrol = tx4925ndfmc_hwcontrol;
+       this->enable_hwecc = tx4925ndfmc_enable_hwecc;
+       this->calculate_ecc = tx4925ndfmc_readecc;
+       this->correct_data = nand_correct_data;
+       this->eccmode = NAND_ECC_HW6_512;       
+       this->dev_ready = tx4925ndfmc_device_ready;
+       /* 20 us command delay time */
+       this->chip_delay = 20;          
+        this->read_byte = tx4925ndfmc_nand_read_byte;
+        this->write_byte = tx4925ndfmc_nand_write_byte;
+       this->cmdfunc = tx4925ndfmc_nand_command;
+       this->write_buf = tx4925ndfmc_nand_write_buf;
+       this->read_buf = tx4925ndfmc_nand_read_buf;
+       this->verify_buf = tx4925ndfmc_nand_verify_buf;
+
+       /* Scan to find existance of the device */
+       if (nand_scan (tx4925ndfmc_mtd, 1)) {
+               err = -ENXIO;
+               goto out_ior;
+       }
+
+       /* Allocate memory for internal data buffer */
+       this->data_buf = kmalloc (sizeof(u_char) * (tx4925ndfmc_mtd->oobblock + tx4925ndfmc_mtd->oobsize), GFP_KERNEL);
+       if (!this->data_buf) {
+               printk ("Unable to allocate NAND data buffer for RBTX4925.\n");
+               err = -ENOMEM;
+               goto out_ior;
+       }
+
+       /* Register the partitions */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+        {
+                int mtd_parts_nb = 0;
+                struct mtd_partition *mtd_parts = 0;
+                mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc");
+                if (mtd_parts_nb > 0)
+                        add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb);
+                else
+                        add_mtd_device(tx4925ndfmc_mtd);
+        }
+#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */
+       switch(tx4925ndfmc_mtd->size){
+               case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break;
+               case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break;
+               case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
+               case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
+               default: {
+                       printk ("Unsupported SmartMedia device\n"); 
+                       err = -ENXIO;
+                       goto out_buf;
+               }
+       }
+#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
+       goto out;
+
+out_buf:
+       kfree (this->data_buf);    
+out_ior:
+out:
+       return err;
+}
+
+module_init(tx4925ndfmc_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit tx4925ndfmc_cleanup (void)
+{
+       struct nand_chip *this = (struct nand_chip *) &tx4925ndfmc_mtd[1];
+
+       /* Unregister partitions */
+       del_mtd_partitions(tx4925ndfmc_mtd);
+       
+       /* Unregister the device */
+       del_mtd_device (tx4925ndfmc_mtd);
+
+       /* Free internal data buffers */
+       kfree (this->data_buf);
+
+       /* Free the MTD device structure */
+       kfree (tx4925ndfmc_mtd);
+}
+module_exit(tx4925ndfmc_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925");
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
new file mode 100644 (file)
index 0000000..f053d2a
--- /dev/null
@@ -0,0 +1,3277 @@
+/*
+ * This code is derived from the VIA reference driver (copyright message
+ * below) provided to Red Hat by VIA Networking Technologies, Inc. for
+ * addition to the Linux kernel.
+ *
+ * The code has been merged into one source file, cleaned up to follow
+ * Linux coding style,  ported to the Linux 2.6 kernel tree and cleaned
+ * for 64bit hardware platforms.
+ *
+ * TODO
+ *     Big-endian support
+ *     rx_copybreak/alignment
+ *     Scatter gather
+ *     More testing
+ *
+ * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com>
+ * Additional fixes and clean up: Francois Romieu
+ *
+ * This source has not been verified for use in safety critical systems.
+ *
+ * Please direct queries about the revamped driver to the linux-kernel
+ * list not VIA.
+ *
+ * Original code:
+ *
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software may be redistributed and/or modified under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or
+ * 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.
+ *
+ * Author: Chuang Liang-Shing, AJ Jiang
+ *
+ * Date: Jan 24, 2003
+ *
+ * MODULE_LICENSE("GPL");
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <linux/if.h>
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/inetdevice.h>
+#include <linux/reboot.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+#include "via-velocity.h"
+
+
+static int velocity_nics = 0;
+static int msglevel = MSG_LEVEL_INFO;
+
+
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static struct ethtool_ops velocity_ethtool_ops;
+
+/*
+    Define module options
+*/
+
+MODULE_AUTHOR("VIA Networking Technologies, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
+
+#define VELOCITY_PARAM(N,D) \
+        static const int N[MAX_UNITS]=OPTION_DEFAULT;\
+        MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\
+        MODULE_PARM_DESC(N, D);
+
+#define RX_DESC_MIN     64
+#define RX_DESC_MAX     255
+#define RX_DESC_DEF     64
+VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
+
+#define TX_DESC_MIN     16
+#define TX_DESC_MAX     256
+#define TX_DESC_DEF     64
+VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+#define VLAN_ID_MIN     0
+#define VLAN_ID_MAX     4095
+#define VLAN_ID_DEF     0
+/* VID_setting[] is used for setting the VID of NIC.
+   0: default VID.
+   1-4094: other VIDs.
+*/
+VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
+
+#define RX_THRESH_MIN   0
+#define RX_THRESH_MAX   3
+#define RX_THRESH_DEF   0
+/* rx_thresh[] is used for controlling the receive fifo threshold.
+   0: indicate the rxfifo threshold is 128 bytes.
+   1: indicate the rxfifo threshold is 512 bytes.
+   2: indicate the rxfifo threshold is 1024 bytes.
+   3: indicate the rxfifo threshold is store & forward.
+*/
+VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
+
+#define DMA_LENGTH_MIN  0
+#define DMA_LENGTH_MAX  7
+#define DMA_LENGTH_DEF  0
+
+/* DMA_length[] is used for controlling the DMA length
+   0: 8 DWORDs
+   1: 16 DWORDs
+   2: 32 DWORDs
+   3: 64 DWORDs
+   4: 128 DWORDs
+   5: 256 DWORDs
+   6: SF(flush till emply)
+   7: SF(flush till emply)
+*/
+VELOCITY_PARAM(DMA_length, "DMA length");
+
+#define TAGGING_DEF     0
+/* enable_tagging[] is used for enabling 802.1Q VID tagging.
+   0: disable VID seeting(default).
+   1: enable VID setting.
+*/
+VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
+
+#define IP_ALIG_DEF     0
+/* IP_byte_align[] is used for IP header DWORD byte aligned
+   0: indicate the IP header won't be DWORD byte aligned.(Default) .
+   1: indicate the IP header will be DWORD byte aligned.
+      In some enviroment, the IP header should be DWORD byte aligned,
+      or the packet will be droped when we receive it. (eg: IPVS)
+*/
+VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
+
+#define TX_CSUM_DEF     1
+/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
+   (We only support RX checksum offload now)
+   0: disable csum_offload[checksum offload
+   1: enable checksum offload. (Default)
+*/
+VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
+
+#define FLOW_CNTL_DEF   1
+#define FLOW_CNTL_MIN   1
+#define FLOW_CNTL_MAX   5
+
+/* flow_control[] is used for setting the flow control ability of NIC.
+   1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
+   2: enable TX flow control.
+   3: enable RX flow control.
+   4: enable RX/TX flow control.
+   5: disable
+*/
+VELOCITY_PARAM(flow_control, "Enable flow control ability");
+
+#define MED_LNK_DEF 0
+#define MED_LNK_MIN 0
+#define MED_LNK_MAX 4
+/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
+   0: indicate autonegotiation for both speed and duplex mode
+   1: indicate 100Mbps half duplex mode
+   2: indicate 100Mbps full duplex mode
+   3: indicate 10Mbps half duplex mode
+   4: indicate 10Mbps full duplex mode
+
+   Note:
+        if EEPROM have been set to the force mode, this option is ignored
+            by driver.
+*/
+VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
+
+#define VAL_PKT_LEN_DEF     0
+/* ValPktLen[] is used for setting the checksum offload ability of NIC.
+   0: Receive frame with invalid layer 2 length (Default)
+   1: Drop frame with invalid layer 2 length
+*/
+VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
+
+#define WOL_OPT_DEF     0
+#define WOL_OPT_MIN     0
+#define WOL_OPT_MAX     7
+/* wol_opts[] is used for controlling wake on lan behavior.
+   0: Wake up if recevied a magic packet. (Default)
+   1: Wake up if link status is on/off.
+   2: Wake up if recevied an arp packet.
+   4: Wake up if recevied any unicast packet.
+   Those value can be sumed up to support more than one option.
+*/
+VELOCITY_PARAM(wol_opts, "Wake On Lan options");
+
+#define INT_WORKS_DEF   20
+#define INT_WORKS_MIN   10
+#define INT_WORKS_MAX   64
+
+VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
+
+static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
+static void velocity_print_info(struct velocity_info *vptr);
+static int velocity_open(struct net_device *dev);
+static int velocity_change_mtu(struct net_device *dev, int mtu);
+static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
+static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs);
+static void velocity_set_multi(struct net_device *dev);
+static struct net_device_stats *velocity_get_stats(struct net_device *dev);
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int velocity_close(struct net_device *dev);
+static int velocity_rx_srv(struct velocity_info *vptr, int status);
+static int velocity_receive_frame(struct velocity_info *, int idx);
+static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
+static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type);
+static void velocity_free_rd_ring(struct velocity_info *vptr);
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
+static int velocity_soft_reset(struct velocity_info *vptr);
+static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
+static void velocity_print_link_status(struct velocity_info *vptr);
+static void safe_disable_mii_autopoll(struct mac_regs * regs);
+static void velocity_shutdown(struct velocity_info *vptr);
+static void enable_flow_control_ability(struct velocity_info *vptr);
+static void enable_mii_autopoll(struct mac_regs * regs);
+static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
+static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
+static int velocity_set_wol(struct velocity_info *vptr);
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context);
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context);
+static u32 mii_check_media_mode(struct mac_regs * regs);
+static u32 check_connection_type(struct mac_regs * regs);
+static void velocity_init_cam_filter(struct velocity_info *vptr);
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
+
+#ifdef CONFIG_PM
+static int velocity_suspend(struct pci_dev *pdev, u32 state);
+static int velocity_resume(struct pci_dev *pdev);
+
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
+
+static struct notifier_block velocity_inetaddr_notifier = {
+      notifier_call:velocity_netdev_event,
+};
+
+#endif                         /* CONFIG_PM */
+
+/*
+ *     Internal board variants. At the moment we have only one
+ */
+
+static struct velocity_info_tbl chip_info_table[] = {
+       {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
+       {0, NULL}
+};
+
+/*
+ *     Describe the PCI device identifiers that we support in this
+ *     device driver. Used for hotplug autoloading.
+ */
+
+static struct pci_device_id velocity_id_table[] __devinitdata = {
+       {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, velocity_id_table);
+
+/**
+ *     get_chip_name   -       identifier to name
+ *     @id: chip identifier
+ *
+ *     Given a chip identifier return a suitable description. Returns
+ *     a pointer a static string valid while the driver is loaded.
+ */
+
+static char __devinit *get_chip_name(enum chip_type chip_id)
+{
+       int i;
+       for (i = 0; chip_info_table[i].name != NULL; i++)
+               if (chip_info_table[i].chip_id == chip_id)
+                       break;
+       return chip_info_table[i].name;
+}
+
+/**
+ *     velocity_remove1        -       device unplug
+ *     @pdev: PCI device being removed
+ *
+ *     Device unload callback. Called on an unplug or on module
+ *     unload for each active device that is present. Disconnects
+ *     the device from the network layer and frees all the resources
+ */
+
+static void __devexit velocity_remove1(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct velocity_info *vptr = dev->priv;
+
+       unregister_netdev(dev);
+       iounmap(vptr->mac_regs);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       free_netdev(dev);
+}
+
+/**
+ *     velocity_set_int_opt    -       parser for integer options
+ *     @opt: pointer to option value
+ *     @val: value the user requested (or -1 for default)
+ *     @min: lowest value allowed
+ *     @max: highest value allowed
+ *     @def: default value
+ *     @name: property name
+ *     @dev: device name
+ *
+ *     Set an integer property in the module options. This function does
+ *     all the verification and checking as well as reporting so that
+ *     we don't duplicate code for each option.
+ */
+
+static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, char *devname)
+{
+       if (val == -1)
+               *opt = def;
+       else if (val < min || val > max) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n",
+                                       devname, name, min, max);
+               *opt = def;
+       } else {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n",
+                                       devname, name, val);
+               *opt = val;
+       }
+}
+
+/**
+ *     velocity_set_bool_opt   -       parser for boolean options
+ *     @opt: pointer to option value
+ *     @val: value the user requested (or -1 for default)
+ *     @def: default value (yes/no)
+ *     @flag: numeric value to set for true.
+ *     @name: property name
+ *     @dev: device name
+ *
+ *     Set a boolean property in the module options. This function does
+ *     all the verification and checking as well as reporting so that
+ *     we don't duplicate code for each option.
+ */
+
+static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, char *devname)
+{
+       (*opt) &= (~flag);
+       if (val == -1)
+               *opt |= (def ? flag : 0);
+       else if (val < 0 || val > 1) {
+               printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n", 
+                       devname, name);
+               *opt |= (def ? flag : 0);
+       } else {
+               printk(KERN_INFO "%s: set parameter %s to %s\n", 
+                       devname, name, val ? "TRUE" : "FALSE");
+               *opt |= (val ? flag : 0);
+       }
+}
+
+/**
+ *     velocity_get_options    -       set options on device
+ *     @opts: option structure for the device
+ *     @index: index of option to use in module options array
+ *     @devname: device name
+ *
+ *     Turn the module and command options into a single structure
+ *     for the current device
+ */
+
+static void __devinit velocity_get_options(struct velocity_opt *opts, int index, char *devname)
+{
+
+       velocity_set_int_opt(&opts->rx_thresh, rx_thresh[index], RX_THRESH_MIN, RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", devname);
+       velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
+       velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
+       velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
+       velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
+       velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+       velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
+       velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
+       velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
+       velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
+       velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
+       velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
+       velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname);
+       opts->numrx = (opts->numrx & ~3);
+}
+
+/**
+ *     velocity_init_cam_filter        -       initialise CAM
+ *     @vptr: velocity to program
+ *
+ *     Initialize the content addressable memory used for filters. Load
+ *     appropriately according to the presence of VLAN
+ */
+
+static void velocity_init_cam_filter(struct velocity_info *vptr)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+
+       /* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */
+       WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
+       WORD_REG_BITS_ON(MCFG_VIDFR, &regs->MCFG);
+
+       /* Disable all CAMs */
+       memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
+       memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
+       mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+       mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+       /* Enable first VCAM */
+       if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+               /* If Tagging option is enabled and VLAN ID is not zero, then
+                  turn on MCFG_RTGOPT also */
+               if (vptr->options.vid != 0)
+                       WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+               mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+               vptr->vCAMmask[0] |= 1;
+               mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+       } else {
+               u16 temp = 0;
+               mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+               temp = 1;
+               mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+       }
+}
+
+/**
+ *     velocity_rx_reset       -       handle a receive reset
+ *     @vptr: velocity we are resetting
+ *
+ *     Reset the ownership and status for the receive ring side.
+ *     Hand all the receive queue to the NIC.
+ */
+
+static void velocity_rx_reset(struct velocity_info *vptr)
+{
+
+       struct mac_regs * regs = vptr->mac_regs;
+       int i;
+
+       vptr->rd_used = vptr->rd_curr = 0;
+
+       /*
+        *      Init state, all RD entries belong to the NIC
+        */
+       for (i = 0; i < vptr->options.numrx; ++i)
+               vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC);
+
+       writew(vptr->options.numrx, &regs->RBRDU);
+       writel(vptr->rd_pool_dma, &regs->RDBaseLo);
+       writew(0, &regs->RDIdx);
+       writew(vptr->options.numrx - 1, &regs->RDCSize);
+}
+
+/**
+ *     velocity_init_registers -       initialise MAC registers
+ *     @vptr: velocity to init
+ *     @type: type of initialisation (hot or cold)
+ *
+ *     Initialise the MAC on a reset or on first set up on the
+ *     hardware.
+ */
+
+static void velocity_init_registers(struct velocity_info *vptr, 
+                                   enum velocity_init_type type)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       int i, mii_status;
+
+       mac_wol_reset(regs);
+
+       switch (type) {
+       case VELOCITY_INIT_RESET:
+       case VELOCITY_INIT_WOL:
+
+               netif_stop_queue(vptr->dev);
+
+               /*
+                *      Reset RX to prevent RX pointer not on the 4X location
+                */
+               velocity_rx_reset(vptr);
+               mac_rx_queue_run(regs);
+               mac_rx_queue_wake(regs);
+
+               mii_status = velocity_get_opt_media_mode(vptr);
+               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+                       velocity_print_link_status(vptr);
+                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+                               netif_wake_queue(vptr->dev);
+               }
+
+               enable_flow_control_ability(vptr);
+
+               mac_clear_isr(regs);
+               writel(CR0_STOP, &regs->CR0Clr);
+               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), 
+                                                       &regs->CR0Set);
+
+               break;
+
+       case VELOCITY_INIT_COLD:
+       default:
+               /*
+                *      Do reset
+                */
+               velocity_soft_reset(vptr);
+               mdelay(5);
+
+               mac_eeprom_reload(regs);
+               for (i = 0; i < 6; i++) {
+                       writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
+               }
+               /*
+                *      clear Pre_ACPI bit.
+                */
+               BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
+               mac_set_rx_thresh(regs, vptr->options.rx_thresh);
+               mac_set_dma_length(regs, vptr->options.DMA_length);
+
+               writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
+               /*
+                *      Bback off algorithm use original IEEE standard
+                */
+               BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
+
+               /*
+                *      Set packet filter: Receive directed and broadcast address
+                */
+               velocity_set_multi(vptr->dev);
+
+               /*
+                *      Enable MII auto-polling
+                */
+               enable_mii_autopoll(regs);
+
+               vptr->int_mask = INT_MASK_DEF;
+
+               writel(cpu_to_le32(vptr->rd_pool_dma), &regs->RDBaseLo);
+               writew(vptr->options.numrx - 1, &regs->RDCSize);
+               mac_rx_queue_run(regs);
+               mac_rx_queue_wake(regs);
+
+               writew(vptr->options.numtx - 1, &regs->TDCSize);
+
+               for (i = 0; i < vptr->num_txq; i++) {
+                       writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i]));
+                       mac_tx_queue_run(regs, i);
+               }
+
+               velocity_init_cam_filter(vptr);
+
+               init_flow_control_register(vptr);
+
+               writel(CR0_STOP, &regs->CR0Clr);
+               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
+
+               mii_status = velocity_get_opt_media_mode(vptr);
+               netif_stop_queue(vptr->dev);
+               mac_clear_isr(regs);
+
+               mii_init(vptr, mii_status);
+
+               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+                       velocity_print_link_status(vptr);
+                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+                               netif_wake_queue(vptr->dev);
+               }
+
+               enable_flow_control_ability(vptr);
+               mac_hw_mibs_init(regs);
+               mac_write_int_mask(vptr->int_mask, regs);
+               mac_clear_isr(regs);
+
+       }
+}
+
+/**
+ *     velocity_soft_reset     -       soft reset
+ *     @vptr: velocity to reset
+ *
+ *     Kick off a soft reset of the velocity adapter and then poll
+ *     until the reset sequence has completed before returning.
+ */
+
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       int i = 0;
+
+       writel(CR0_SFRST, &regs->CR0Set);
+
+       for (i = 0; i < W_MAX_TIMEOUT; i++) {
+               udelay(5);
+               if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+                       break;
+       }
+
+       if (i == W_MAX_TIMEOUT) {
+               writel(CR0_FORSRST, &regs->CR0Set);
+               /* FIXME: PCI POSTING */
+               /* delay 2ms */
+               mdelay(2);
+       }
+       return 0;
+}
+
+/**
+ *     velocity_found1         -       set up discovered velocity card
+ *     @pdev: PCI device
+ *     @ent: PCI device table entry that matched
+ *
+ *     Configure a discovered adapter from scratch. Return a negative
+ *     errno error code on failure paths.
+ */
+
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int first = 1;
+       struct net_device *dev;
+       int i;
+       struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+       struct velocity_info *vptr;
+       struct mac_regs * regs;
+       int ret = -ENOMEM;
+
+       if (velocity_nics++ >= MAX_UNITS) {
+               printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", 
+                               velocity_nics);
+               return -ENODEV;
+       }
+
+       dev = alloc_etherdev(sizeof(struct velocity_info));
+
+       if (dev == NULL) {
+               printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+               goto out;
+       }
+       
+       /* Chain it all together */
+       
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       vptr = dev->priv;
+
+
+       if (first) {
+               printk(KERN_INFO "%s Ver. %s\n", 
+                       VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+               printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+               printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+               first = 0;
+       }
+
+       velocity_init_info(pdev, vptr, info);
+
+       vptr->dev = dev;
+
+       dev->priv = vptr;
+       dev->irq = pdev->irq;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0) 
+               goto err_free_dev;
+
+       ret = velocity_get_pci_info(vptr, pdev);
+       if (ret < 0) {
+               printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+               goto err_disable;
+       }
+
+       ret = pci_request_regions(pdev, VELOCITY_NAME);
+       if (ret < 0) {
+               printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+               goto err_disable;
+       }
+
+       regs = ioremap(vptr->memaddr, vptr->io_size);
+       if (regs == NULL) {
+               ret = -EIO;
+               goto err_release_res;
+       }
+
+       vptr->mac_regs = regs;
+
+       mac_wol_reset(regs);
+
+       dev->base_addr = vptr->ioaddr;
+
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = readb(&regs->PAR[i]);
+
+
+       velocity_get_options(&vptr->options, velocity_nics - 1, dev->name);
+
+       /* 
+        *      Mask out the options cannot be set to the chip
+        */
+        
+       vptr->options.flags &= info->flags;
+
+       /*
+        *      Enable the chip specified capbilities
+        */
+        
+       vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+
+       vptr->wol_opts = vptr->options.wol_opts;
+       vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+
+       vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
+
+       dev->irq = pdev->irq;
+       dev->open = velocity_open;
+       dev->hard_start_xmit = velocity_xmit;
+       dev->stop = velocity_close;
+       dev->get_stats = velocity_get_stats;
+       dev->set_multicast_list = velocity_set_multi;
+       dev->do_ioctl = velocity_ioctl;
+       dev->ethtool_ops = &velocity_ethtool_ops;
+       dev->change_mtu = velocity_change_mtu;
+#ifdef  VELOCITY_ZERO_COPY_SUPPORT
+       dev->features |= NETIF_F_SG;
+#endif
+
+       if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+               dev->features |= NETIF_F_HW_CSUM;
+       }
+
+       ret = register_netdev(dev);
+       if (ret < 0)
+               goto err_iounmap;
+
+       velocity_print_info(vptr);
+       pci_set_drvdata(pdev, dev);
+       
+       /* and leave the chip powered down */
+       
+       pci_set_power_state(pdev, 3);
+out:
+       return ret;
+
+err_iounmap:
+       iounmap(regs);
+err_release_res:
+       pci_release_regions(pdev);
+err_disable:
+       pci_disable_device(pdev);
+err_free_dev:
+       free_netdev(dev);
+       goto out;
+}
+
+/**
+ *     velocity_print_info     -       per driver data
+ *     @vptr: velocity
+ *
+ *     Print per driver data as the kernel driver finds Velocity
+ *     hardware
+ */
+
+static void __devinit velocity_print_info(struct velocity_info *vptr)
+{
+       struct net_device *dev = vptr->dev;
+
+       printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+       printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
+               dev->name, 
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], 
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+}
+
+/**
+ *     velocity_init_info      -       init private data
+ *     @pdev: PCI device
+ *     @vptr: Velocity info
+ *     @info: Board type
+ *
+ *     Set up the initial velocity_info struct for the device that has been
+ *     discovered.
+ */
+
+static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+{
+       memset(vptr, 0, sizeof(struct velocity_info));
+
+       vptr->pdev = pdev;
+       vptr->chip_id = info->chip_id;
+       vptr->io_size = info->io_size;
+       vptr->num_txq = info->txqueue;
+       vptr->multicast_limit = MCAM_SIZE;
+
+       spin_lock_init(&vptr->lock);
+       spin_lock_init(&vptr->xmit_lock);
+}
+
+/**
+ *     velocity_get_pci_info   -       retrieve PCI info for device
+ *     @vptr: velocity device
+ *     @pdev: PCI device it matches
+ *
+ *     Retrieve the PCI configuration space data that interests us from
+ *     the kernel PCI layer
+ */
+
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
+{
+
+       if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+               return -EIO;
+               
+       pci_set_master(pdev);
+
+       vptr->ioaddr = pci_resource_start(pdev, 0);
+       vptr->memaddr = pci_resource_start(pdev, 1);
+       
+       if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
+       {
+               printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
+                               pci_name(pdev));
+               return -EINVAL;
+       }
+
+       if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
+       {
+               printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
+                               pci_name(pdev));
+               return -EINVAL;
+       }
+
+       if(pci_resource_len(pdev, 1) < 256)
+       {
+               printk(KERN_ERR "%s: region #1 is too small.\n", 
+                               pci_name(pdev));
+               return -EINVAL;
+       }
+       vptr->pdev = pdev;
+
+       return 0;
+}
+
+/**
+ *     velocity_init_rings     -       set up DMA rings
+ *     @vptr: Velocity to set up
+ *
+ *     Allocate PCI mapped DMA rings for the receive and transmit layer
+ *     to use.
+ */
+
+static int velocity_init_rings(struct velocity_info *vptr)
+{
+       int i;
+       unsigned int psize;
+       unsigned int tsize;
+       dma_addr_t pool_dma;
+       u8 *pool;
+
+       /*
+        *      Allocate all RD/TD rings a single pool 
+        */
+        
+       psize = vptr->options.numrx * sizeof(struct rx_desc) + 
+               vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+       /*
+        * pci_alloc_consistent() fulfills the requirement for 64 bytes
+        * alignment
+        */
+       pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma);
+
+       if (pool == NULL) {
+               printk(KERN_ERR "%s : DMA memory allocation failed.\n", 
+                                       vptr->dev->name);
+               return -ENOMEM;
+       }
+
+       memset(pool, 0, psize);
+
+       vptr->rd_ring = (struct rx_desc *) pool;
+
+       vptr->rd_pool_dma = pool_dma;
+
+       tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+       vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize, 
+                                               &vptr->tx_bufs_dma);
+
+       if (vptr->tx_bufs == NULL) {
+               printk(KERN_ERR "%s: DMA memory allocation failed.\n", 
+                                       vptr->dev->name);
+               pci_free_consistent(vptr->pdev, psize, pool, pool_dma);
+               return -ENOMEM;
+       }
+
+       memset(vptr->tx_bufs, 0, vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq);
+
+       i = vptr->options.numrx * sizeof(struct rx_desc);
+       pool += i;
+       pool_dma += i;
+       for (i = 0; i < vptr->num_txq; i++) {
+               int offset = vptr->options.numtx * sizeof(struct tx_desc);
+
+               vptr->td_pool_dma[i] = pool_dma;
+               vptr->td_rings[i] = (struct tx_desc *) pool;
+               pool += offset;
+               pool_dma += offset;
+       }
+       return 0;
+}
+
+/**
+ *     velocity_free_rings     -       free PCI ring pointers
+ *     @vptr: Velocity to free from
+ *
+ *     Clean up the PCI ring buffers allocated to this velocity.
+ */
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+       int size;
+
+       size = vptr->options.numrx * sizeof(struct rx_desc) + 
+              vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+       pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma);
+
+       size = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+
+       pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma);
+}
+
+/**
+ *     velocity_init_rd_ring   -       set up receive ring
+ *     @vptr: velocity to configure
+ *
+ *     Allocate and set up the receive buffers for each ring slot and
+ *     assign them to the network adapter.
+ */
+
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+       int i, ret = -ENOMEM;
+       struct rx_desc *rd;
+       struct velocity_rd_info *rd_info;
+       unsigned int rsize = sizeof(struct velocity_rd_info) * 
+                                       vptr->options.numrx;
+
+       vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
+       if(vptr->rd_info == NULL)
+               goto out;
+       memset(vptr->rd_info, 0, rsize);
+
+       /* Init the RD ring entries */
+       for (i = 0; i < vptr->options.numrx; i++) {
+               rd = &(vptr->rd_ring[i]);
+               rd_info = &(vptr->rd_info[i]);
+
+               ret = velocity_alloc_rx_buf(vptr, i);
+               if (ret < 0) {
+                       VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+                               "%s: failed to allocate RX buffer.\n", 
+                               vptr->dev->name);
+                       velocity_free_rd_ring(vptr);
+                       goto out;
+               }
+               rd->rdesc0.owner = OWNED_BY_NIC;
+       }
+       vptr->rd_used = vptr->rd_curr = 0;
+out:
+       return ret;
+}
+
+/**
+ *     velocity_free_rd_ring   -       set up receive ring
+ *     @vptr: velocity to clean up
+ *
+ *     Free the receive buffers for each ring slot and any
+ *     attached socket buffers that need to go away.
+ */
+
+static void velocity_free_rd_ring(struct velocity_info *vptr)
+{
+       int i;
+
+       if (vptr->rd_info == NULL)
+               return;
+
+       for (i = 0; i < vptr->options.numrx; i++) {
+               struct velocity_rd_info *rd_info = &(vptr->rd_info[i]);
+
+               if (!rd_info->skb_dma)
+                       continue;
+               pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz,
+                                PCI_DMA_FROMDEVICE);
+               rd_info->skb_dma = (dma_addr_t) NULL;
+
+               dev_kfree_skb(rd_info->skb);
+               rd_info->skb = NULL;
+       }
+
+       kfree(vptr->rd_info);
+       vptr->rd_info = NULL;
+}
+
+/**
+ *     velocity_init_td_ring   -       set up transmit ring
+ *     @vptr:  velocity
+ *
+ *     Set up the transmit ring and chain the ring pointers together.
+ *     Returns zero on success or a negative posix errno code for
+ *     failure.
+ */
+static int velocity_init_td_ring(struct velocity_info *vptr)
+{
+       int i, j;
+       dma_addr_t curr;
+       struct tx_desc *td;
+       struct velocity_td_info *td_info;
+       unsigned int tsize = sizeof(struct velocity_td_info) * 
+                                       vptr->options.numtx;
+
+       /* Init the TD ring entries */
+       for (j = 0; j < vptr->num_txq; j++) {
+               curr = vptr->td_pool_dma[j];
+
+               vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL);
+               if(vptr->td_infos[j] == NULL)
+               {
+                       while(--j >= 0)
+                               kfree(vptr->td_infos[j]);
+                       return -ENOMEM;
+               }
+               memset(vptr->td_infos[j], 0, tsize);
+
+               for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
+                       td = &(vptr->td_rings[j][i]);
+                       td_info = &(vptr->td_infos[j][i]);
+                       td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ;
+                       td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ;
+               }
+               vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0;
+       }
+       return 0;
+}
+
+/*
+ *     FIXME: could we merge this with velocity_free_tx_buf ?
+ */
+
+static void velocity_free_td_ring_entry(struct velocity_info *vptr,
+                                                        int q, int n)
+{
+       struct velocity_td_info * td_info = &(vptr->td_infos[q][n]);
+       int i;
+       
+       if (td_info == NULL)
+               return;
+               
+       if (td_info->skb) {
+               for (i = 0; i < td_info->nskb_dma; i++)
+               {
+                       if (td_info->skb_dma[i]) {
+                               pci_unmap_single(vptr->pdev, td_info->skb_dma[i], 
+                                       td_info->skb->len, PCI_DMA_TODEVICE);
+                               td_info->skb_dma[i] = (dma_addr_t) NULL;
+                       }
+               }
+               dev_kfree_skb(td_info->skb);
+               td_info->skb = NULL;
+       }
+}
+
+/**
+ *     velocity_free_td_ring   -       free td ring
+ *     @vptr: velocity
+ *
+ *     Free up the transmit ring for this particular velocity adapter.
+ *     We free the ring contents but not the ring itself.
+ */
+static void velocity_free_td_ring(struct velocity_info *vptr)
+{
+       int i, j;
+
+       for (j = 0; j < vptr->num_txq; j++) {
+               if (vptr->td_infos[j] == NULL)
+                       continue;
+               for (i = 0; i < vptr->options.numtx; i++) {
+                       velocity_free_td_ring_entry(vptr, j, i);
+
+               }
+               if (vptr->td_infos[j]) {
+                       kfree(vptr->td_infos[j]);
+                       vptr->td_infos[j] = NULL;
+               }
+       }
+}
+
+/**
+ *     velocity_rx_srv         -       service RX interrupt
+ *     @vptr: velocity
+ *     @status: adapter status (unused)
+ *
+ *     Walk the receive ring of the velocity adapter and remove
+ *     any received packets from the receive queue. Hand the ring
+ *     slots back to the adapter for reuse.
+ */
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
+{
+       struct rx_desc *rd;
+       struct net_device_stats *stats = &vptr->stats;
+       struct mac_regs * regs = vptr->mac_regs;
+       int rd_curr = vptr->rd_curr;
+       int works = 0;
+
+       while (1) {
+
+               rd = &(vptr->rd_ring[rd_curr]);
+
+               if ((vptr->rd_info[rd_curr]).skb == NULL) {
+                       if (velocity_alloc_rx_buf(vptr, rd_curr) < 0)
+                               break;
+               }
+
+               if (works++ > 15)
+                       break;
+
+               if (rd->rdesc0.owner == OWNED_BY_NIC)
+                       break;
+
+               /*
+                *      Don't drop CE or RL error frame although RXOK is off
+                *      FIXME: need to handle copybreak
+                */
+               if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+                       if (velocity_receive_frame(vptr, rd_curr) == 0) {
+                               if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) {
+                                       VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name);
+                                       break;
+                               }
+                       } else {
+                               stats->rx_dropped++;
+                       }
+               } else {
+                       if (rd->rdesc0.RSR & RSR_CRC)
+                               stats->rx_crc_errors++;
+                       if (rd->rdesc0.RSR & RSR_FAE)
+                               stats->rx_frame_errors++;
+
+                       stats->rx_dropped++;
+               }
+
+               rd->inten = 1;
+
+               if (++vptr->rd_used >= 4) {
+                       int i, rd_prev = rd_curr;
+                       for (i = 0; i < 4; i++) {
+                               if (--rd_prev < 0)
+                                       rd_prev = vptr->options.numrx - 1;
+
+                               rd = &(vptr->rd_ring[rd_prev]);
+                               rd->rdesc0.owner = OWNED_BY_NIC;
+                       }
+                       writew(4, &(regs->RBRDU));
+                       vptr->rd_used -= 4;
+               }
+
+               vptr->dev->last_rx = jiffies;
+
+               rd_curr++;
+               if (rd_curr >= vptr->options.numrx)
+                       rd_curr = 0;
+       }
+       vptr->rd_curr = rd_curr;
+       VAR_USED(stats);
+       return works;
+}
+
+/**
+ *     velocity_rx_csum        -       checksum process
+ *     @rd: receive packet descriptor
+ *     @skb: network layer packet buffer
+ *
+ *     Process the status bits for the received packet and determine
+ *     if the checksum was computed and verified by the hardware
+ */
+static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
+{
+       skb->ip_summed = CHECKSUM_NONE;
+
+       if (rd->rdesc1.CSM & CSM_IPKT) {
+               if (rd->rdesc1.CSM & CSM_IPOK) {
+                       if ((rd->rdesc1.CSM & CSM_TCPKT) || 
+                                       (rd->rdesc1.CSM & CSM_UDPKT)) {
+                               if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+                                       return;
+                               }
+                       }
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               }
+       }
+}
+
+/**
+ *     velocity_receive_frame  -       received packet processor
+ *     @vptr: velocity we are handling
+ *     @idx: ring index
+ *     
+ *     A packet has arrived. We process the packet and if appropriate
+ *     pass the frame up the network stack
+ */
+static int velocity_receive_frame(struct velocity_info *vptr, int idx)
+{
+       struct net_device_stats *stats = &vptr->stats;
+       struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
+       struct rx_desc *rd = &(vptr->rd_ring[idx]);
+       struct sk_buff *skb;
+
+       if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
+               VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name);
+               stats->rx_length_errors++;
+               return -EINVAL;
+       }
+
+       if (rd->rdesc0.RSR & RSR_MAR)
+               vptr->stats.multicast++;
+
+       skb = rd_info->skb;
+       skb->dev = vptr->dev;
+
+       pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, 
+                                                       PCI_DMA_FROMDEVICE);
+       rd_info->skb_dma = (dma_addr_t) NULL;
+       rd_info->skb = NULL;
+
+       /* FIXME - memmove ? */
+       if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
+               int i;
+               for (i = rd->rdesc0.len + 4; i >= 0; i--)
+                       *(skb->data + i + 2) = *(skb->data + i);
+               skb->data += 2;
+               skb->tail += 2;
+       }
+
+       skb_put(skb, (rd->rdesc0.len - 4));
+       skb->protocol = eth_type_trans(skb, skb->dev);
+
+       /*
+        *      Drop frame not meeting IEEE 802.3
+        */
+        
+       if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
+               if (rd->rdesc0.RSR & RSR_RL) {
+                       stats->rx_length_errors++;
+                       return -EINVAL;
+               }
+       }
+
+       velocity_rx_csum(rd, skb);
+       
+       /*
+        *      FIXME: need rx_copybreak handling
+        */
+
+       stats->rx_bytes += skb->len;
+       netif_rx(skb);
+
+       return 0;
+}
+
+/**
+ *     velocity_alloc_rx_buf   -       allocate aligned receive buffer
+ *     @vptr: velocity
+ *     @idx: ring index
+ *
+ *     Allocate a new full sized buffer for the reception of a frame and
+ *     map it into PCI space for the hardware to use. The hardware
+ *     requires *64* byte alignment of the buffer which makes life
+ *     less fun than would be ideal.
+ */
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
+{
+       struct rx_desc *rd = &(vptr->rd_ring[idx]);
+       struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
+
+       rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64);
+       if (rd_info->skb == NULL)
+               return -ENOMEM;
+
+       /*
+        *      Do the gymnastics to get the buffer head for data at
+        *      64byte alignment.
+        */
+       skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63);
+       rd_info->skb->dev = vptr->dev;
+       rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
+       
+       /*
+        *      Fill in the descriptor to match
+        */     
+        
+       *((u32 *) & (rd->rdesc0)) = 0;
+       rd->len = cpu_to_le32(vptr->rx_buf_sz);
+       rd->inten = 1;
+       rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+       rd->pa_high = 0;
+       return 0;
+}
+
+/**
+ *     tx_srv          -       transmit interrupt service
+ *     @vptr; Velocity
+ *     @status:
+ *
+ *     Scan the queues looking for transmitted packets that
+ *     we can complete and clean up. Update any statistics as
+ *     neccessary/
+ */
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+       struct tx_desc *td;
+       int qnum;
+       int full = 0;
+       int idx;
+       int works = 0;
+       struct velocity_td_info *tdinfo;
+       struct net_device_stats *stats = &vptr->stats;
+
+       for (qnum = 0; qnum < vptr->num_txq; qnum++) {
+               for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0; 
+                       idx = (idx + 1) % vptr->options.numtx) {
+
+                       /*
+                        *      Get Tx Descriptor
+                        */
+                       td = &(vptr->td_rings[qnum][idx]);
+                       tdinfo = &(vptr->td_infos[qnum][idx]);
+
+                       if (td->tdesc0.owner == OWNED_BY_NIC)
+                               break;
+
+                       if ((works++ > 15))
+                               break;
+
+                       if (td->tdesc0.TSR & TSR0_TERR) {
+                               stats->tx_errors++;
+                               stats->tx_dropped++;
+                               if (td->tdesc0.TSR & TSR0_CDH)
+                                       stats->tx_heartbeat_errors++;
+                               if (td->tdesc0.TSR & TSR0_CRS)
+                                       stats->tx_carrier_errors++;
+                               if (td->tdesc0.TSR & TSR0_ABT)
+                                       stats->tx_aborted_errors++;
+                               if (td->tdesc0.TSR & TSR0_OWC)
+                                       stats->tx_window_errors++;
+                       } else {
+                               stats->tx_packets++;
+                               stats->tx_bytes += tdinfo->skb->len;
+                       }
+                       velocity_free_tx_buf(vptr, tdinfo);
+                       vptr->td_used[qnum]--;
+               }
+               vptr->td_tail[qnum] = idx;
+
+               if (AVAIL_TD(vptr, qnum) < 1) {
+                       full = 1;
+               }
+       }
+       /*
+        *      Look to see if we should kick the transmit network
+        *      layer for more work.
+        */
+       if (netif_queue_stopped(vptr->dev) && (full == 0)
+           && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+               netif_wake_queue(vptr->dev);
+       }
+       return works;
+}
+
+/**
+ *     velocity_print_link_status      -       link status reporting
+ *     @vptr: velocity to report on
+ *
+ *     Turn the link status of the velocity card into a kernel log
+ *     description of the new link state, detailing speed and duplex
+ *     status
+ */
+
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+       if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+       } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link autonegation", vptr->dev->name);
+
+               if (vptr->mii_status & VELOCITY_SPEED_1000)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+               else if (vptr->mii_status & VELOCITY_SPEED_100)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+               else
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+               else
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+       } else {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+               switch (vptr->options.spd_dpx) {
+               case SPD_DPX_100_HALF:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+                       break;
+               case SPD_DPX_100_FULL:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+                       break;
+               case SPD_DPX_10_HALF:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+                       break;
+               case SPD_DPX_10_FULL:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+/**
+ *     velocity_error  -       handle error from controller
+ *     @vptr: velocity
+ *     @status: card status
+ *
+ *     Process an error report from the hardware and attempt to recover
+ *     the card itself. At the moment we cannot recover from some 
+ *     theoretically impossible errors but this could be fixed using
+ *     the pci_device_failed logic to bounce the hardware
+ *
+ */
+static void velocity_error(struct velocity_info *vptr, int status)
+{
+
+       if (status & ISR_TXSTLI) {
+               struct mac_regs * regs = vptr->mac_regs;
+
+               printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(&regs->TDIdx[0]));
+               BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
+               writew(TRDCSR_RUN, &regs->TDCSRClr);
+               netif_stop_queue(vptr->dev);
+               
+               /* FIXME: port over the pci_device_failed code and use it
+                  here */
+       }
+
+       if (status & ISR_SRCI) {
+               struct mac_regs * regs = vptr->mac_regs;
+               int linked;
+
+               if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+                       vptr->mii_status = check_connection_type(regs);
+
+                       /*
+                        *      If it is a 3119, disable frame bursting in 
+                        *      halfduplex mode and enable it in fullduplex
+                        *       mode
+                        */
+                       if (vptr->rev_id < REV_ID_VT3216_A0) {
+                               if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+                                       BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+                               else
+                                       BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+                       }
+                       /*
+                        *      Only enable CD heart beat counter in 10HD mode
+                        */
+                       if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
+                               BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+                       } else {
+                               BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+                       }
+               }
+               /*
+                *      Get link status from PHYSR0
+                */
+               linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
+
+               if (linked) {
+                       vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+               } else {
+                       vptr->mii_status |= VELOCITY_LINK_FAIL;
+               }
+
+               velocity_print_link_status(vptr);
+               enable_flow_control_ability(vptr);
+
+               /*
+                *      Re-enable auto-polling because SRCI will disable 
+                *      auto-polling
+                */
+                
+               enable_mii_autopoll(regs);
+
+               if (vptr->mii_status & VELOCITY_LINK_FAIL)
+                       netif_stop_queue(vptr->dev);
+               else
+                       netif_wake_queue(vptr->dev);
+
+       };
+       if (status & ISR_MIBFI)
+               velocity_update_hw_mibs(vptr);
+       if (status & ISR_LSTEI)
+               mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ *     velocity_free_tx_buf    -       free transmit buffer
+ *     @vptr: velocity
+ *     @tdinfo: buffer
+ *
+ *     Release an transmit buffer. If the buffer was preallocated then
+ *     recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+       struct sk_buff *skb = tdinfo->skb;
+       int i;
+
+       /*
+        *      Don't unmap the pre-allocated tx_bufs
+        */
+       if (tdinfo->skb_dma && (tdinfo->skb_dma[0] != tdinfo->buf_dma)) {
+
+               for (i = 0; i < tdinfo->nskb_dma; i++) {
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE);
+#else
+                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);
+#endif
+                       tdinfo->skb_dma[i] = 0;
+               }
+       }
+       dev_kfree_skb_irq(skb);
+       tdinfo->skb = NULL;
+}
+
+/**
+ *     velocity_open           -       interface activation callback
+ *     @dev: network layer device to open
+ *
+ *     Called when the network layer brings the interface up. Returns
+ *     a negative posix error code on failure, or zero on success.
+ *
+ *     All the ring allocation and set up is done on open for this
+ *     adapter to minimise memory usage when inactive
+ */
+static int velocity_open(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       int ret;
+
+       vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
+
+       ret = velocity_init_rings(vptr);
+       if (ret < 0)
+               goto out;
+
+       ret = velocity_init_rd_ring(vptr);
+       if (ret < 0)
+               goto err_free_desc_rings;
+
+       ret = velocity_init_td_ring(vptr);
+       if (ret < 0)
+               goto err_free_rd_ring;
+       
+       /* Ensure chip is running */    
+       pci_set_power_state(vptr->pdev, 0);
+       
+       velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+       ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ,
+                         dev->name, dev);
+       if (ret < 0) {
+               /* Power down the chip */
+               pci_set_power_state(vptr->pdev, 3);
+               goto err_free_td_ring;
+       }
+
+       mac_enable_int(vptr->mac_regs);
+       netif_start_queue(dev);
+       vptr->flags |= VELOCITY_FLAGS_OPENED;
+out:
+       return ret;
+
+err_free_td_ring:
+       velocity_free_td_ring(vptr);
+err_free_rd_ring:
+       velocity_free_rd_ring(vptr);
+err_free_desc_rings:
+       velocity_free_rings(vptr);
+       goto out;
+}
+
+/** 
+ *     velocity_change_mtu     -       MTU change callback
+ *     @dev: network device
+ *     @new_mtu: desired MTU
+ *
+ *     Handle requests from the networking layer for MTU change on
+ *     this interface. It gets called on a change by the network layer.
+ *     Return zero for success or negative posix error code.
+ */
+static int velocity_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct velocity_info *vptr = dev->priv;
+       unsigned long flags;
+       int oldmtu = dev->mtu;
+       int ret = 0;
+
+       if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
+               VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", 
+                               vptr->dev->name);
+               return -EINVAL;
+       }
+
+       if (new_mtu != oldmtu) {
+               spin_lock_irqsave(&vptr->lock, flags);
+
+               netif_stop_queue(dev);
+               velocity_shutdown(vptr);
+
+               velocity_free_td_ring(vptr);
+               velocity_free_rd_ring(vptr);
+
+               dev->mtu = new_mtu;
+               if (new_mtu > 8192)
+                       vptr->rx_buf_sz = 9 * 1024;
+               else if (new_mtu > 4096)
+                       vptr->rx_buf_sz = 8192;
+               else
+                       vptr->rx_buf_sz = 4 * 1024;
+
+               ret = velocity_init_rd_ring(vptr);
+               if (ret < 0)
+                       goto out_unlock;
+
+               ret = velocity_init_td_ring(vptr);
+               if (ret < 0)
+                       goto out_unlock;
+
+               velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+               mac_enable_int(vptr->mac_regs);
+               netif_start_queue(dev);
+out_unlock:
+               spin_unlock_irqrestore(&vptr->lock, flags);
+       }
+
+       return ret;
+}
+
+/**
+ *     velocity_shutdown       -       shut down the chip
+ *     @vptr: velocity to deactivate
+ *
+ *     Shuts down the internal operations of the velocity and
+ *     disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       mac_disable_int(regs);
+       writel(CR0_STOP, &regs->CR0Set);
+       writew(0xFFFF, &regs->TDCSRClr);
+       writeb(0xFF, &regs->RDCSRClr);
+       safe_disable_mii_autopoll(regs);
+       mac_clear_isr(regs);
+}
+
+/**
+ *     velocity_close          -       close adapter callback
+ *     @dev: network device
+ *
+ *     Callback from the network layer when the velocity is being
+ *     deactivated by the network layer
+ */
+
+static int velocity_close(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+
+       netif_stop_queue(dev);
+       velocity_shutdown(vptr);
+
+       if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
+               velocity_get_ip(vptr);
+       if (dev->irq != 0)
+               free_irq(dev->irq, dev);
+               
+       /* Power down the chip */
+       pci_set_power_state(vptr->pdev, 3);
+       
+       /* Free the resources */
+       velocity_free_td_ring(vptr);
+       velocity_free_rd_ring(vptr);
+       velocity_free_rings(vptr);
+
+       vptr->flags &= (~VELOCITY_FLAGS_OPENED);
+       return 0;
+}
+
+/**
+ *     velocity_xmit           -       transmit packet callback
+ *     @skb: buffer to transmit
+ *     @dev: network device
+ *
+ *     Called by the networ layer to request a packet is queued to
+ *     the velocity. Returns zero on success.
+ */
+static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       int qnum = 0;
+       struct tx_desc *td_ptr;
+       struct velocity_td_info *tdinfo;
+       unsigned long flags;
+       int index;
+
+       int pktlen = skb->len;
+
+       spin_lock_irqsave(&vptr->lock, flags);
+
+       index = vptr->td_curr[qnum];
+       td_ptr = &(vptr->td_rings[qnum][index]);
+       tdinfo = &(vptr->td_infos[qnum][index]);
+
+       td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
+       td_ptr->tdesc1.TCR = TCR0_TIC;
+       td_ptr->td_buf[0].queue = 0;
+
+       /*
+        *      Pad short frames. 
+        */
+       if (pktlen < ETH_ZLEN) {
+               /* Cannot occur until ZC support */
+               if(skb_linearize(skb, GFP_ATOMIC))
+                       return 0; 
+               pktlen = ETH_ZLEN;
+               memcpy(tdinfo->buf, skb->data, skb->len);
+               memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
+               tdinfo->skb = skb;
+               tdinfo->skb_dma[0] = tdinfo->buf_dma;
+               td_ptr->tdesc0.pktsize = pktlen;
+               td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+               td_ptr->td_buf[0].pa_high = 0;
+               td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+               tdinfo->nskb_dma = 1;
+               td_ptr->tdesc1.CMDZ = 2;
+       } else
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+       if (skb_shinfo(skb)->nr_frags > 0) {
+               int nfrags = skb_shinfo(skb)->nr_frags;
+               tdinfo->skb = skb;
+               if (nfrags > 6) {
+                       skb_linearize(skb, GFP_ATOMIC);
+                       memcpy(tdinfo->buf, skb->data, skb->len);
+                       tdinfo->skb_dma[0] = tdinfo->buf_dma;
+                       td_ptr->tdesc0.pktsize = 
+                       td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+                       td_ptr->td_buf[0].pa_high = 0;
+                       td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+                       tdinfo->nskb_dma = 1;
+                       td_ptr->tdesc1.CMDZ = 2;
+               } else {
+                       int i = 0;
+                       tdinfo->nskb_dma = 0;
+                       tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE);
+
+                       td_ptr->tdesc0.pktsize = pktlen;
+
+                       /* FIXME: support 48bit DMA later */
+                       td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
+                       td_ptr->td_buf[i].pa_high = 0;
+                       td_ptr->td_buf[i].bufsize = skb->len->skb->data_len;
+
+                       for (i = 0; i < nfrags; i++) {
+                               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+                               void *addr = ((void *) page_address(frag->page + frag->page_offset));
+
+                               tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
+
+                               td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
+                               td_ptr->td_buf[i + 1].pa_high = 0;
+                               td_ptr->td_buf[i + 1].bufsize = frag->size;
+                       }
+                       tdinfo->nskb_dma = i - 1;
+                       td_ptr->tdesc1.CMDZ = i;
+               }
+
+       } else
+#endif
+       {
+               /*
+                *      Map the linear network buffer into PCI space and
+                *      add it to the transmit ring.
+                */
+               tdinfo->skb = skb;
+               tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+               td_ptr->tdesc0.pktsize = pktlen;
+               td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+               td_ptr->td_buf[0].pa_high = 0;
+               td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+               tdinfo->nskb_dma = 1;
+               td_ptr->tdesc1.CMDZ = 2;
+       }
+
+       if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+               td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+               td_ptr->tdesc1.pqinf.priority = 0;
+               td_ptr->tdesc1.pqinf.CFI = 0;
+               td_ptr->tdesc1.TCR |= TCR0_VETAG;
+       }
+
+       /*
+        *      Handle hardware checksum
+        */
+       if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+                                && (skb->ip_summed == CHECKSUM_HW)) {
+               struct iphdr *ip = skb->nh.iph;
+               if (ip->protocol == IPPROTO_TCP)
+                       td_ptr->tdesc1.TCR |= TCR0_TCPCK;
+               else if (ip->protocol == IPPROTO_UDP)
+                       td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
+               td_ptr->tdesc1.TCR |= TCR0_IPCK;
+       }
+       {
+
+               int prev = index - 1;
+
+               if (prev < 0)
+                       prev = vptr->options.numtx - 1;
+               td_ptr->tdesc0.owner = OWNED_BY_NIC;
+               vptr->td_used[qnum]++;
+               vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;
+
+               if (AVAIL_TD(vptr, qnum) < 1)
+                       netif_stop_queue(dev);
+
+               td_ptr = &(vptr->td_rings[qnum][prev]);
+               td_ptr->td_buf[0].queue = 1;
+               mac_tx_queue_wake(vptr->mac_regs, qnum);
+       }
+       dev->trans_start = jiffies;
+       spin_unlock_irqrestore(&vptr->lock, flags);
+       return 0;
+}
+
+/**
+ *     velocity_intr           -       interrupt callback
+ *     @irq: interrupt number
+ *     @dev_instance: interrupting device
+ *     @pt_regs: CPU register state at interrupt
+ *
+ *     Called whenever an interrupt is generated by the velocity
+ *     adapter IRQ line. We may not be the source of the interrupt
+ *     and need to identify initially if we are, and if not exit as
+ *     efficiently as possible.
+ */
+static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_instance;
+       struct velocity_info *vptr = dev->priv;
+       u32 isr_status;
+       int max_count = 0;
+
+
+       spin_lock(&vptr->lock);
+       isr_status = mac_read_isr(vptr->mac_regs);
+
+       /* Not us ? */
+       if (isr_status == 0) {
+               spin_unlock(&vptr->lock);
+               return IRQ_NONE;
+       }
+
+       mac_disable_int(vptr->mac_regs);
+
+       /*
+        *      Keep processing the ISR until we have completed
+        *      processing and the isr_status becomes zero
+        */
+        
+       while (isr_status != 0) {
+               mac_write_isr(vptr->mac_regs, isr_status);
+               if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+                       velocity_error(vptr, isr_status);
+               if (isr_status & (ISR_PRXI | ISR_PPRXI))
+                       max_count += velocity_rx_srv(vptr, isr_status);
+               if (isr_status & (ISR_PTXI | ISR_PPTXI))
+                       max_count += velocity_tx_srv(vptr, isr_status);
+               isr_status = mac_read_isr(vptr->mac_regs);
+               if (max_count > vptr->options.int_works)
+               {
+                       printk(KERN_WARNING "%s: excessive work at interrupt.\n", 
+                               dev->name);
+                       max_count = 0;
+               }
+       }
+       spin_unlock(&vptr->lock);
+       mac_enable_int(vptr->mac_regs);
+       return IRQ_HANDLED;
+
+}
+
+
+/**
+ *     ether_crc       -       ethernet CRC function
+ *
+ *     Compute an ethernet CRC hash of the data block provided. This
+ *     is not performance optimised but is not needed in performance
+ *     critical code paths.
+ *
+ *     FIXME: could we use shared code here ?
+ */
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+       static unsigned const ethernet_polynomial = 0x04c11db7U;
+       
+       int crc = -1;
+
+       while (--length >= 0) {
+               unsigned char current_octet = *data++;
+               int bit;
+               for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+                       crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+               }
+       }
+       return crc;
+}
+
+/**
+ *     velocity_set_multi      -       filter list change callback
+ *     @dev: network device
+ *
+ *     Called by the network layer when the filter lists need to change
+ *     for a velocity adapter. Reload the CAMs with the new address
+ *     filter ruleset.
+ */
+static void velocity_set_multi(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       struct mac_regs * regs = vptr->mac_regs;
+       u8 rx_mode;
+       int i;
+       struct dev_mc_list *mclist;
+
+       if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+               /* Unconditionally log net taps. */
+               printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+               writel(0xffffffff, &regs->MARCAM[0]);
+               writel(0xffffffff, &regs->MARCAM[4]);
+               rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+       } else if ((dev->mc_count > vptr->multicast_limit)
+                  || (dev->flags & IFF_ALLMULTI)) {
+               writel(0xffffffff, &regs->MARCAM[0]);
+               writel(0xffffffff, &regs->MARCAM[4]);
+               rx_mode = (RCR_AM | RCR_AB);
+       } else {
+               int offset = MCAM_SIZE - vptr->multicast_limit;
+               mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+                       mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);
+                       vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+               }
+
+               mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+               rx_mode = (RCR_AM | RCR_AB);
+       }
+       if (dev->mtu > 1500)
+               rx_mode |= RCR_AL;
+
+       BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/**
+ *     velocity_get_status     -       statistics callback
+ *     @dev: network device
+ *
+ *     Callback from the network layer to allow driver statistics
+ *     to be resynchronized with hardware collected state. In the
+ *     case of the velocity we need to pull the MIB counters from
+ *     the hardware into the counters before letting the network
+ *     layer display them.
+ */
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       
+       /* If the hardware is down, don't touch MII */
+       if(!netif_running(dev))
+               return &vptr->stats;
+
+       spin_lock_irq(&vptr->lock);
+       velocity_update_hw_mibs(vptr);
+       spin_unlock_irq(&vptr->lock);
+
+       vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+       vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+       vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+//  unsigned long   rx_dropped;     /* no space in linux buffers    */
+       vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+       /* detailed rx_errors: */
+//  unsigned long   rx_length_errors;
+//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
+       vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
+//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
+//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
+
+       /* detailed tx_errors */
+//  unsigned long   tx_fifo_errors;
+
+       return &vptr->stats;
+}
+
+
+/**
+ *     velocity_ioctl          -       ioctl entry point
+ *     @dev: network device
+ *     @rq: interface request ioctl
+ *     @cmd: command code
+ *
+ *     Called when the user issues an ioctl request to the network
+ *     device in question. The velocity interface supports MII.
+ */
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct velocity_info *vptr = dev->priv;
+       int ret;
+
+       /* If we are asked for information and the device is power
+          saving then we need to bring the device back up to talk to it */
+               
+       if(!netif_running(dev))
+               pci_set_power_state(vptr->pdev, 0);
+               
+       switch (cmd) {
+       case SIOCGMIIPHY:       /* Get address of MII PHY in use. */
+       case SIOCGMIIREG:       /* Read MII PHY register. */
+       case SIOCSMIIREG:       /* Write to MII PHY register. */
+               ret = velocity_mii_ioctl(dev, rq, cmd);
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+       }
+       if(!netif_running(dev))
+               pci_set_power_state(vptr->pdev, 3);
+               
+               
+       return ret;
+}
+
+/*
+ *     Definition for our device driver. The PCI layer interface
+ *     uses this to handle all our card discover and plugging
+ */
+static struct pci_driver velocity_driver = {
+      name:VELOCITY_NAME,
+      id_table:velocity_id_table,
+      probe:velocity_found1,
+      remove:velocity_remove1,
+#ifdef CONFIG_PM
+      suspend:velocity_suspend,
+      resume:velocity_resume,
+#endif
+};
+
+/**
+ *     velocity_init_module    -       load time function
+ *
+ *     Called when the velocity module is loaded. The PCI driver
+ *     is registered with the PCI layer, and in turn will call
+ *     the probe functions for each velocity adapter installed
+ *     in the system.
+ */
+static int __init velocity_init_module(void)
+{
+       int ret;
+       ret = pci_module_init(&velocity_driver);
+
+#ifdef CONFIG_PM
+       register_inetaddr_notifier(&velocity_inetaddr_notifier);
+#endif
+       return ret;
+}
+
+/**
+ *     velocity_cleanup        -       module unload
+ *
+ *     When the velocity hardware is unloaded this function is called.
+ *     It will clean up the notifiers and the unregister the PCI 
+ *     driver interface for this hardware. This in turn cleans up
+ *     all discovered interfaces before returning from the function
+ */
+static void __exit velocity_cleanup_module(void)
+{
+#ifdef CONFIG_PM
+       unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+#endif
+       pci_unregister_driver(&velocity_driver);
+}
+
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
+
+
+/*
+ * MII access , media link mode setting functions
+ */
+/**
+ *     mii_init        -       set up MII
+ *     @vptr: velocity adapter
+ *     @mii_status:  links tatus
+ *
+ *     Set up the PHY for the current link state.
+ */
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+       u16 BMCR;
+
+       switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+       case PHYID_CICADA_CS8201:
+               /*
+                *      Reset to hardware default
+                */
+               MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               /*
+                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+                *      off it in NWay-forced half mode for NWay-forced v.s. 
+                *      legacy-forced issue.
+                */
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               else
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               /*
+                *      Turn on Link/Activity LED enable bit for CIS8201
+                */
+               MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+               break;
+       case PHYID_VT3216_32BIT:
+       case PHYID_VT3216_64BIT:
+               /*
+                *      Reset to hardware default
+                */
+               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               /*
+                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+                *      off it in NWay-forced half mode for NWay-forced v.s. 
+                *      legacy-forced issue
+                */
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               else
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               break;
+
+       case PHYID_MARVELL_1000:
+       case PHYID_MARVELL_1000S:
+               /*
+                *      Assert CRS on Transmit 
+                */
+               MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+               /*
+                *      Reset to hardware default 
+                */
+               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               break;
+       default:
+               ;
+       }
+       velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+       if (BMCR & BMCR_ISO) {
+               BMCR &= ~BMCR_ISO;
+               velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+       }
+}
+
+/**
+ *     safe_disable_mii_autopoll       -       autopoll off
+ *     @regs: velocity registers
+ *
+ *     Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs * regs)
+{
+       u16 ww;
+
+       /*  turn off MAUTO */
+       writeb(0, &regs->MIICR);
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               udelay(1);
+               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
+       }
+}
+
+/**
+ *     enable_mii_autopoll     -       turn on autopolling
+ *     @regs: velocity registers
+ *
+ *     Enable the MII link status autopoll feature on the Velocity
+ *     hardware. Wait for it to enable.
+ */
+
+static void enable_mii_autopoll(struct mac_regs * regs)
+{
+       int ii;
+
+       writeb(0, &(regs->MIICR));
+       writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+               udelay(1);
+               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
+       }
+
+       writeb(MIICR_MAUTO, &regs->MIICR);
+
+       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+               udelay(1);
+               if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
+       }
+
+}
+
+/**
+ *     velocity_mii_read       -       read MII data
+ *     @regs: velocity registers
+ *     @index: MII register index
+ *     @data: buffer for received data
+ *
+ *     Perform a single read of an MII 16bit register. Returns zero
+ *     on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data)
+{
+       u16 ww;
+
+       /*
+        *      Disable MIICR_MAUTO, so that mii addr can be set normally
+        */
+       safe_disable_mii_autopoll(regs);
+
+       writeb(index, &regs->MIIADR);
+
+       BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               if (!(readb(&regs->MIICR) & MIICR_RCMD))
+                       break;
+       }
+
+       *data = readw(&regs->MIIDATA);
+
+       enable_mii_autopoll(regs);
+       if (ww == W_MAX_TIMEOUT)
+               return -ETIMEDOUT;
+       return 0;
+}
+
+/**
+ *     velocity_mii_write      -       write MII data
+ *     @regs: velocity registers
+ *     @index: MII register index
+ *     @data: 16bit data for the MII register
+ *
+ *     Perform a single write to an MII 16bit register. Returns zero
+ *     on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data)
+{
+       u16 ww;
+
+       /*
+        *      Disable MIICR_MAUTO, so that mii addr can be set normally
+        */
+       safe_disable_mii_autopoll(regs);
+
+       /* MII reg offset */
+       writeb(mii_addr, &regs->MIIADR);
+       /* set MII data */
+       writew(data, &regs->MIIDATA);
+
+       /* turn on MIICR_WCMD */
+       BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+       /* W_MAX_TIMEOUT is the timeout period */
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               udelay(5);
+               if (!(readb(&regs->MIICR) & MIICR_WCMD))
+                       break;
+       }
+       enable_mii_autopoll(regs);
+
+       if (ww == W_MAX_TIMEOUT)
+               return -ETIMEDOUT;
+       return 0;
+}
+
+/**
+ *     velocity_get_opt_media_mode     -       get media selection
+ *     @vptr: velocity adapter
+ *
+ *     Get the media mode stored in EEPROM or module options and load
+ *     mii_status accordingly. The requested link state information
+ *     is also returned.
+ */
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+       u32 status = 0;
+
+       switch (vptr->options.spd_dpx) {
+       case SPD_DPX_AUTO:
+               status = VELOCITY_AUTONEG_ENABLE;
+               break;
+       case SPD_DPX_100_FULL:
+               status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+               break;
+       case SPD_DPX_10_FULL:
+               status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+               break;
+       case SPD_DPX_100_HALF:
+               status = VELOCITY_SPEED_100;
+               break;
+       case SPD_DPX_10_HALF:
+               status = VELOCITY_SPEED_10;
+               break;
+       }
+       vptr->mii_status = status;
+       return status;
+}
+
+/**
+ *     mii_set_auto_on         -       autonegotiate on
+ *     @vptr: velocity
+ *
+ *     Enable autonegotation on this interface
+ */
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+       else
+               MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+
+/*
+static void mii_set_auto_off(struct velocity_info * vptr)
+{
+    MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+*/
+
+/**
+ *     set_mii_flow_control    -       flow control setup
+ *     @vptr: velocity interface
+ *
+ *     Set up the flow control on this interface according to
+ *     the supplied user/eeprom options.
+ */
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+       /*Enable or Disable PAUSE in ANAR */
+       switch (vptr->options.flow_cntl) {
+       case FLOW_CNTL_TX:
+               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
+
+       case FLOW_CNTL_RX:
+               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
+
+       case FLOW_CNTL_TX_RX:
+               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
+
+       case FLOW_CNTL_DISABLE:
+               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ *     velocity_set_media_mode         -       set media mode
+ *     @mii_status: old MII link state
+ *
+ *     Check the media link state and configure the flow control
+ *     PHY and also velocity hardware setup accordingly. In particular
+ *     we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+       u32 curr_status;
+       struct mac_regs * regs = vptr->mac_regs;
+
+       vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+       curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+       /* Set mii link status */
+       set_mii_flow_control(vptr);
+
+       /*
+          Check if new status is consisent with current status
+          if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+          || (mii_status==curr_status)) {
+          vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+          vptr->mii_status=check_connection_type(vptr->mac_regs);
+          VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+          return 0;
+          }
+        */
+
+       if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
+               MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+       }
+
+       /*
+        *      If connection type is AUTO
+        */
+       if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+               /* clear force MAC mode bit */
+               BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+               /* set duplex mode of MAC according to duplex mode of MII */
+               MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+               MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+
+               /* enable AUTO-NEGO mode */
+               mii_set_auto_on(vptr);
+       } else {
+               u16 ANAR;
+               u8 CHIPGCR;
+
+               /*
+                * 1. if it's 3119, disable frame bursting in halfduplex mode
+                *    and enable it in fullduplex mode
+                * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+                * 3. only enable CD heart beat counter in 10HD mode
+                */
+
+               /* set force MAC mode bit */
+               BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+               CHIPGCR = readb(&regs->CHIPGCR);
+               CHIPGCR &= ~CHIPGCR_FCGMII;
+
+               if (mii_status & VELOCITY_DUPLEX_FULL) {
+                       CHIPGCR |= CHIPGCR_FCFDX;
+                       writeb(CHIPGCR, &regs->CHIPGCR);
+                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+                       if (vptr->rev_id < REV_ID_VT3216_A0)
+                               BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+               } else {
+                       CHIPGCR &= ~CHIPGCR_FCFDX;
+                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+                       writeb(CHIPGCR, &regs->CHIPGCR);
+                       if (vptr->rev_id < REV_ID_VT3216_A0)
+                               BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+               }
+
+               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+               if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
+                       BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+               } else {
+                       BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+               }
+               /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+               velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+               ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+               if (mii_status & VELOCITY_SPEED_100) {
+                       if (mii_status & VELOCITY_DUPLEX_FULL)
+                               ANAR |= ANAR_TXFD;
+                       else
+                               ANAR |= ANAR_TX;
+               } else {
+                       if (mii_status & VELOCITY_DUPLEX_FULL)
+                               ANAR |= ANAR_10FD;
+                       else
+                               ANAR |= ANAR_10;
+               }
+               velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+               /* enable AUTO-NEGO mode */
+               mii_set_auto_on(vptr);
+               /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+       }
+       /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+       /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+       return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ *     mii_check_media_mode    -       check media state
+ *     @regs: velocity registers
+ *
+ *     Check the current MII status and determine the link status
+ *     accordingly
+ */
+static u32 mii_check_media_mode(struct mac_regs * regs)
+{
+       u32 status = 0;
+       u16 ANAR;
+
+       if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+               status |= VELOCITY_LINK_FAIL;
+
+       if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+               status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+       else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+               status |= (VELOCITY_SPEED_1000);
+       else {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if (ANAR & ANAR_TXFD)
+                       status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+               else if (ANAR & ANAR_TX)
+                       status |= VELOCITY_SPEED_100;
+               else if (ANAR & ANAR_10FD)
+                       status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+               else
+                       status |= (VELOCITY_SPEED_10);
+       }
+
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+                               status |= VELOCITY_AUTONEG_ENABLE;
+               }
+       }
+
+       return status;
+}
+
+static u32 check_connection_type(struct mac_regs * regs)
+{
+       u32 status = 0;
+       u8 PHYSR0;
+       u16 ANAR;
+       PHYSR0 = readb(&regs->PHYSR0);
+
+       /*
+          if (!(PHYSR0 & PHYSR0_LINKGD))
+          status|=VELOCITY_LINK_FAIL;
+        */
+
+       if (PHYSR0 & PHYSR0_FDPX)
+               status |= VELOCITY_DUPLEX_FULL;
+
+       if (PHYSR0 & PHYSR0_SPDG)
+               status |= VELOCITY_SPEED_1000;
+       if (PHYSR0 & PHYSR0_SPD10)
+               status |= VELOCITY_SPEED_10;
+       else
+               status |= VELOCITY_SPEED_100;
+
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+                               status |= VELOCITY_AUTONEG_ENABLE;
+               }
+       }
+
+       return status;
+}
+
+/**
+ *     enable_flow_control_ability     -       flow control
+ *     @vptr: veloity to configure
+ *
+ *     Set up flow control according to the flow control options
+ *     determined by the eeprom/configuration.
+ */
+
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+       struct mac_regs * regs = vptr->mac_regs;
+
+       switch (vptr->options.flow_cntl) {
+
+       case FLOW_CNTL_DEFAULT:
+               if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+                       writel(CR0_FDXRFCEN, &regs->CR0Set);
+               else
+                       writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+               if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+                       writel(CR0_FDXTFCEN, &regs->CR0Set);
+               else
+                       writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
+
+       case FLOW_CNTL_TX:
+               writel(CR0_FDXTFCEN, &regs->CR0Set);
+               writel(CR0_FDXRFCEN, &regs->CR0Clr);
+               break;
+
+       case FLOW_CNTL_RX:
+               writel(CR0_FDXRFCEN, &regs->CR0Set);
+               writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
+
+       case FLOW_CNTL_TX_RX:
+               writel(CR0_FDXTFCEN, &regs->CR0Set);
+               writel(CR0_FDXRFCEN, &regs->CR0Set);
+               break;
+
+       case FLOW_CNTL_DISABLE:
+               writel(CR0_FDXRFCEN, &regs->CR0Clr);
+               writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
+
+       default:
+               break;
+       }
+
+}
+
+
+/**
+ *     velocity_ethtool_up     -       pre hook for ethtool
+ *     @dev: network device
+ *
+ *     Called before an ethtool operation. We need to make sure the
+ *     chip is out of D3 state before we poke at it.
+ */
+static int velocity_ethtool_up(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       if(!netif_running(dev))
+               pci_set_power_state(vptr->pdev, 0);
+       return 0;
+}      
+
+/**
+ *     velocity_ethtool_down   -       post hook for ethtool
+ *     @dev: network device
+ *
+ *     Called after an ethtool operation. Restore the chip back to D3
+ *     state if it isn't running.
+ */
+static void velocity_ethtool_down(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       if(!netif_running(dev))
+               pci_set_power_state(vptr->pdev, 3);
+}
+
+static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct velocity_info *vptr = dev->priv;
+       struct mac_regs * regs = vptr->mac_regs;
+       u32 status;
+       status = check_connection_type(vptr->mac_regs);
+
+       cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
+       if (status & VELOCITY_SPEED_100)
+               cmd->speed = SPEED_100;
+       else
+               cmd->speed = SPEED_10;
+       cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+       cmd->port = PORT_TP;
+       cmd->transceiver = XCVR_INTERNAL;
+       cmd->phy_address = readb(&regs->MIIADR) & 0x1F;
+
+       if (status & VELOCITY_DUPLEX_FULL)
+               cmd->duplex = DUPLEX_FULL;
+       else
+               cmd->duplex = DUPLEX_HALF;
+               
+       return 0;
+}
+
+static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct velocity_info *vptr = dev->priv;
+       u32 curr_status;
+       u32 new_status = 0;
+       int ret = 0;
+       
+       curr_status = check_connection_type(vptr->mac_regs);
+       curr_status &= (~VELOCITY_LINK_FAIL);
+
+       new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
+       new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
+       new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
+       new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
+
+       if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
+               ret = -EINVAL;
+       else
+               velocity_set_media_mode(vptr, new_status);
+
+       return ret;
+}
+
+static u32 velocity_get_link(struct net_device *dev)
+{
+       struct velocity_info *vptr = dev->priv;
+       struct mac_regs * regs = vptr->mac_regs;
+       return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0)  ? 0 : 1;
+}
+
+static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct velocity_info *vptr = dev->priv;
+       strcpy(info->driver, VELOCITY_NAME);
+       strcpy(info->version, VELOCITY_VERSION);
+       strcpy(info->bus_info, vptr->pdev->slot_name);
+}
+
+static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct velocity_info *vptr = dev->priv;
+       wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
+       wol->wolopts |= WAKE_MAGIC;
+       /*
+          if (vptr->wol_opts & VELOCITY_WOL_PHY)
+                  wol.wolopts|=WAKE_PHY;
+                        */
+       if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+               wol->wolopts |= WAKE_UCAST;
+       if (vptr->wol_opts & VELOCITY_WOL_ARP)
+               wol->wolopts |= WAKE_ARP;
+       memcpy(&wol->sopass, vptr->wol_passwd, 6);
+}
+
+static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct velocity_info *vptr = dev->priv;
+
+       if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
+               return -EFAULT;
+       vptr->wol_opts = VELOCITY_WOL_MAGIC;
+
+       /*
+          if (wol.wolopts & WAKE_PHY) {
+          vptr->wol_opts|=VELOCITY_WOL_PHY;
+          vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED;
+          }
+        */
+
+       if (wol->wolopts & WAKE_MAGIC) {
+               vptr->wol_opts |= VELOCITY_WOL_MAGIC;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       if (wol->wolopts & WAKE_UCAST) {
+               vptr->wol_opts |= VELOCITY_WOL_UCAST;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       if (wol->wolopts & WAKE_ARP) {
+               vptr->wol_opts |= VELOCITY_WOL_ARP;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       memcpy(vptr->wol_passwd, wol->sopass, 6);
+       return 0;
+}
+
+static u32 velocity_get_msglevel(struct net_device *dev)
+{
+       return msglevel;
+}
+
+static void velocity_set_msglevel(struct net_device *dev, u32 value)
+{
+        msglevel = value;
+}
+
+static struct ethtool_ops velocity_ethtool_ops = {
+       .get_settings   =       velocity_get_settings,
+       .set_settings   =       velocity_set_settings,
+       .get_drvinfo    =       velocity_get_drvinfo,
+       .get_wol        =       velocity_ethtool_get_wol,
+       .set_wol        =       velocity_ethtool_set_wol,
+       .get_msglevel   =       velocity_get_msglevel,
+       .set_msglevel   =       velocity_set_msglevel,
+       .get_link       =       velocity_get_link,
+       .begin          =       velocity_ethtool_up,
+       .complete       =       velocity_ethtool_down
+};
+
+/**
+ *     velocity_mii_ioctl              -       MII ioctl handler
+ *     @dev: network device
+ *     @ifr: the ifreq block for the ioctl
+ *     @cmd: the command
+ *
+ *     Process MII requests made via ioctl from the network layer. These
+ *     are used by tools like kudzu to interrogate the link state of the
+ *     hardware
+ */
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct velocity_info *vptr = dev->priv;
+       struct mac_regs * regs = vptr->mac_regs;
+       unsigned long flags;
+       struct mii_ioctl_data *miidata = if_mii(ifr);
+       int err;
+       
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+               break;
+       case SIOCGMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+                       return -ETIMEDOUT;
+               break;
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               spin_lock_irqsave(&vptr->lock, flags);
+               err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+               spin_unlock_irqrestore(&vptr->lock, flags);
+               check_connection_type(vptr->mac_regs);
+               if(err)
+                       return err;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/**
+ *     velocity_save_context   -       save registers
+ *     @vptr: velocity 
+ *     @context: buffer for stored context
+ *
+ *     Retrieve the current configuration from the velocity hardware
+ *     and stash it in the context structure, for use by the context
+ *     restore functions. This allows us to save things we need across
+ *     power down states
+ */
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       u16 i;
+       u8 *ptr = (u8 *)regs;
+
+       for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+       for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+}
+
+/**
+ *     velocity_restore_context        -       restore registers
+ *     @vptr: velocity 
+ *     @context: buffer for stored context
+ *
+ *     Reload the register configuration from the velocity context 
+ *     created by velocity_save_context.
+ */
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       int i;
+       u8 *ptr = (u8 *)regs;
+
+       for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       }
+
+       /* Just skip cr0 */
+       for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+               /* Clear */
+               writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+               /* Set */
+               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+       }
+
+       for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       }
+
+       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       }
+
+       for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
+               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+       }
+
+}
+
+static int velocity_suspend(struct pci_dev *pdev, u32 state)
+{
+       struct velocity_info *vptr = pci_get_drvdata(pdev);
+       unsigned long flags;
+       
+       if(!netif_running(vptr->dev))
+               return 0;
+               
+       netif_device_detach(vptr->dev);
+       
+       spin_lock_irqsave(&vptr->lock, flags);
+       pci_save_state(pdev, vptr->pci_state);
+#ifdef ETHTOOL_GWOL
+       if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+               velocity_get_ip(vptr);
+               velocity_save_context(vptr, &vptr->context);
+               velocity_shutdown(vptr);
+               velocity_set_wol(vptr);
+               pci_enable_wake(pdev, 3, 1);
+               pci_set_power_state(pdev, 3);
+       } else {
+               velocity_save_context(vptr, &vptr->context);
+               velocity_shutdown(vptr);
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, state);
+       }
+#else
+       pci_set_power_state(pdev, state);
+#endif
+       spin_unlock_irqrestore(&vptr->lock, flags);
+       return 0;
+}
+
+static int velocity_resume(struct pci_dev *pdev)
+{
+       struct velocity_info *vptr = pci_get_drvdata(pdev);
+       unsigned long flags;
+       int i;
+       
+       if(!netif_running(vptr->dev))
+               return 0;
+               
+       pci_set_power_state(pdev, 0);
+       pci_enable_wake(pdev, 0, 0);
+       pci_restore_state(pdev, vptr->pci_state);
+
+       mac_wol_reset(vptr->mac_regs);
+
+       spin_lock_irqsave(&vptr->lock, flags);
+       velocity_restore_context(vptr, &vptr->context);
+       velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+       mac_disable_int(vptr->mac_regs);
+
+       velocity_tx_srv(vptr, 0);
+
+       for (i = 0; i < vptr->num_txq; i++) {
+               if (vptr->td_used[i]) {
+                       mac_tx_queue_wake(vptr->mac_regs, i);
+               }
+       }
+
+       mac_enable_int(vptr->mac_regs);
+       spin_unlock_irqrestore(&vptr->lock, flags);
+       netif_device_attach(vptr->dev);
+
+       return 0;
+}
+
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+{
+       struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+       struct net_device *dev;
+       struct velocity_info *vptr;
+
+       if (ifa) {
+               dev = ifa->ifa_dev->dev;
+               vptr = dev->priv;
+               velocity_get_ip(vptr);
+       }
+       return NOTIFY_DONE;
+}
+#endif
+
+/*
+ * Purpose: Functions to set WOL.
+ */
+
+const static unsigned short crc16_tab[256] = {
+       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+
+static u32 mask_pattern[2][4] = {
+       {0x00203000, 0x000003C0, 0x00000000, 0x0000000},        /* ARP          */
+       {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}         /* Magic Packet */ 
+};
+
+/**
+ *     ether_crc16     -       compute ethernet CRC
+ *     @len: buffer length
+ *     @cp: buffer
+ *     @crc16: initial CRC
+ *
+ *     Compute a CRC value for a block of data. 
+ *     FIXME: can we use generic functions ?
+ */
+static u16 ether_crc16(int len, u8 * cp, u16 crc16)
+{
+       while (len--)
+               crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff];
+       return (crc16);
+}
+
+/**
+ *     bit_reverse             -       16bit reverse
+ *     @data: 16bit data t reverse
+ *
+ *     Reverse the order of a 16bit value and return the reversed bits
+ */
+static u16 bit_reverse(u16 data)
+{
+       u32 new = 0x00000000;
+       int ii;
+
+
+       for (ii = 0; ii < 16; ii++) {
+               new |= ((u32) (data & 1) << (31 - ii));
+               data >>= 1;
+       }
+
+       return (u16) (new >> 16);
+}
+
+/**
+ *     wol_calc_crc            -       WOL CRC
+ *     @pattern: data pattern
+ *     @mask_pattern: mask
+ *
+ *     Compute the wake on lan crc hashes for the packet header
+ *     we are interested in.
+ */
+u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+{
+       u16 crc = 0xFFFF;
+       u8 mask;
+       int i, j;
+
+       for (i = 0; i < size; i++) {
+               mask = mask_pattern[i];
+
+               /* Skip this loop if the mask equals to zero */
+               if (mask == 0x00)
+                       continue;
+
+               for (j = 0; j < 8; j++) {
+                       if ((mask & 0x01) == 0) {
+                               mask >>= 1;
+                               continue;
+                       }
+                       mask >>= 1;
+                       crc = ether_crc16(1, &(pattern[i * 8 + j]), crc);
+               }
+       }
+       /*      Finally, invert the result once to get the correct data */
+       crc = ~crc;
+       return bit_reverse(crc);
+}
+
+/**
+ *     velocity_set_wol        -       set up for wake on lan
+ *     @vptr: velocity to set WOL status on
+ *
+ *     Set a card up for wake on lan either by unicast or by
+ *     ARP packet.
+ *
+ *     FIXME: check static buffer is safe here
+ */
+static int velocity_set_wol(struct velocity_info *vptr)
+{
+       struct mac_regs * regs = vptr->mac_regs;
+       static u8 buf[256];
+       int i;
+
+       writew(0xFFFF, &regs->WOLCRClr);
+       writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+       writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
+
+       /*
+          if (vptr->wol_opts & VELOCITY_WOL_PHY)
+          writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
+        */
+
+       if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
+               writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
+       }
+
+       if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+               struct arp_packet *arp = (struct arp_packet *) buf;
+               u16 crc;
+               memset(buf, 0, sizeof(struct arp_packet) + 7);
+
+               for (i = 0; i < 4; i++)
+                       writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
+
+               arp->type = htons(ETH_P_ARP);
+               arp->ar_op = htons(1);
+
+               memcpy(arp->ar_tip, vptr->ip_addr, 4);
+
+               crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]);
+
+               writew(crc, &regs->PatternCRC[0]);
+               writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+       }
+
+       BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+       BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+       writew(0x0FFF, &regs->WOLSRClr);
+
+       if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
+               if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+                       MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+       }
+
+       if (vptr->mii_status & VELOCITY_SPEED_1000)
+               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+
+       BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+       {
+               u8 GCR;
+               GCR = readb(&regs->CHIPGCR);
+               GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+               writeb(GCR, &regs->CHIPGCR);
+       }
+
+       BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+       /* Turn on SWPTAG just before entering power mode */
+       BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+       /* Go to bed ..... */
+       BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+       return 0;
+}
+
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
new file mode 100644 (file)
index 0000000..57b1bca
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+ * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
+ *
+ * Based on the i82092.c driver.
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "pd6729.h"
+#include "i82365.h"
+#include "cirrus.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge");
+MODULE_AUTHOR("Jun Komuro <komurojun@mbn.nifty.com>");
+
+#define MAX_SOCKETS 2
+
+/*
+ * simple helper functions
+ * External clock time, in nanoseconds.  120 ns = 8.33 MHz
+ */
+#define to_cycles(ns)  ((ns)/120)
+
+static spinlock_t port_lock = SPIN_LOCK_UNLOCKED;
+
+/* basic value read/write functions */
+
+static unsigned char indirect_read(struct pd6729_socket *socket, unsigned short reg)
+{
+       unsigned long port;
+       unsigned char val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg += socket->number * 0x40;
+       port = socket->io_base;
+       outb(reg, port);
+       val = inb(port + 1);
+       spin_unlock_irqrestore(&port_lock, flags);
+
+       return val;
+}
+
+static unsigned short indirect_read16(struct pd6729_socket *socket, unsigned short reg)
+{
+       unsigned long port;
+       unsigned short tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg  = reg + socket->number * 0x40;
+       port = socket->io_base;
+       outb(reg, port);
+       tmp = inb(port + 1);
+       reg++;
+       outb(reg, port);
+       tmp = tmp | (inb(port + 1) << 8);
+       spin_unlock_irqrestore(&port_lock, flags);
+
+       return tmp;
+}
+
+static void indirect_write(struct pd6729_socket *socket, unsigned short reg, unsigned char value)
+{
+       unsigned long port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg = reg + socket->number * 0x40;
+       port = socket->io_base;
+       outb(reg, port);
+       outb(value, port + 1);
+       spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg, unsigned char mask)
+{
+       unsigned long port;
+       unsigned char val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg = reg + socket->number * 0x40;
+       port = socket->io_base;
+       outb(reg, port);
+       val = inb(port + 1);
+       val |= mask;
+       outb(reg, port);
+       outb(val, port + 1);
+       spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg, unsigned char mask)
+{
+       unsigned long port;
+       unsigned char val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg = reg + socket->number * 0x40;
+       port = socket->io_base;
+       outb(reg, port);
+       val = inb(port + 1);
+       val &= ~mask;
+       outb(reg, port);
+       outb(val, port + 1);
+       spin_unlock_irqrestore(&port_lock, flags);
+}
+
+static void indirect_write16(struct pd6729_socket *socket, unsigned short reg, unsigned short value)
+{
+       unsigned long port;
+       unsigned char val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_lock, flags);
+       reg = reg + socket->number * 0x40;
+       port = socket->io_base;
+
+       outb(reg, port);
+       val = value & 255;
+       outb(val, port + 1);
+
+       reg++;
+
+       outb(reg, port);
+       val = value >> 8;
+       outb(val, port + 1);
+       spin_unlock_irqrestore(&port_lock, flags);
+}
+
+/* Interrupt handler functionality */
+
+static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+       struct pd6729_socket *socket = (struct pd6729_socket *)dev;
+       int i;
+       int loopcount = 0;
+       int handled = 0;
+       unsigned int events, active = 0;
+
+       while (1) {
+               loopcount++;
+               if (loopcount > 20) {
+                       printk(KERN_ERR "pd6729: infinite eventloop in interrupt\n");
+                       break;
+               }
+
+               active = 0;
+
+               for (i = 0; i < MAX_SOCKETS; i++) {
+                       unsigned int csc;
+
+                       /* card status change register */
+                       csc = indirect_read(&socket[i], I365_CSC);
+                       if (csc == 0)  /* no events on this socket */
+                               continue;
+
+                       handled = 1;
+                       events = 0;
+
+                       if (csc & I365_CSC_DETECT) {
+                               events |= SS_DETECT;
+                               dprintk("Card detected in socket %i!\n", i);
+                       }
+
+                       if (indirect_read(&socket[i], I365_INTCTL) & I365_PC_IOCARD) {
+                               /* For IO/CARDS, bit 0 means "read the card" */
+                               events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+                       } else {
+                               /* Check for battery/ready events */
+                               events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+                               events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+                               events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+                       }
+
+                       if (events) {
+                               pcmcia_parse_events(&socket[i].socket, events);
+                       }
+                       active |= events;
+               }
+
+               if (active == 0) /* no more events to handle */
+                       break;
+       }
+       return IRQ_RETVAL(handled);
+}
+
+/* socket functions */
+
+static void set_bridge_state(struct pd6729_socket *socket)
+{
+       indirect_write(socket, I365_GBLCTL, 0x00);
+       indirect_write(socket, I365_GENCTL, 0x00);
+
+       indirect_setbit(socket, I365_INTCTL, 0x08);
+}
+
+static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+       struct pd6729_socket *socket = container_of(sock, struct pd6729_socket, socket);
+       unsigned int status;
+       unsigned int data;
+       struct pd6729_socket *t;
+
+       /* Interface Status Register */
+       status = indirect_read(socket, I365_STATUS);
+       *value = 0;
+
+       if ((status & I365_CS_DETECT) == I365_CS_DETECT) {
+               *value |= SS_DETECT;
+       }
+
+       /*
+        * IO cards have a different meaning of bits 0,1
+        * Also notice the inverse-logic on the bits
+        */
+       if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) {
+               /* IO card */
+               if (!(status & I365_CS_STSCHG))
+                       *value |= SS_STSCHG;
+       } else {
+               /* non I/O card */
+               if (!(status & I365_CS_BVD1))
+                       *value |= SS_BATDEAD;
+               if (!(status & I365_CS_BVD2))
+                       *value |= SS_BATWARN;
+       }
+
+       if (status & I365_CS_WRPROT)
+               *value |= SS_WRPROT;    /* card is write protected */
+
+       if (status & I365_CS_READY)
+               *value |= SS_READY;     /* card is not busy */
+
+       if (status & I365_CS_POWERON)
+               *value |= SS_POWERON;   /* power is applied to the card */
+
+       t = (socket->number) ? socket : socket + 1;
+       indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA);
+       data = indirect_read16(t, PD67_EXT_DATA);
+       *value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD;
+
+       return 0;
+}
+
+
+static int pd6729_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+       struct pd6729_socket *socket = container_of(sock, struct pd6729_socket, socket);
+       unsigned char reg, vcc, vpp;
+
+       state->flags    = 0;
+       state->Vcc      = 0;
+       state->Vpp      = 0;
+       state->io_irq   = 0;
+       state->csc_mask = 0;
+
+       /*
+        * First the power status of the socket
+        * PCTRL - Power Control Register
+        */
+       reg = indirect_read(socket, I365_POWER);
+
+       if (reg & I365_PWR_AUTO)
+               state->flags |= SS_PWR_AUTO;  /* Automatic Power Switch */
+
+       if (reg & I365_PWR_OUT)
+               state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */
+
+       vcc = reg & I365_VCC_MASK;    vpp = reg & I365_VPP1_MASK;
+
+       if (reg & I365_VCC_5V) {
+               state->Vcc = (indirect_read(socket, PD67_MISC_CTL_1) &
+                       PD67_MC1_VCC_3V) ? 33 : 50;
+
+               if (vpp == I365_VPP1_5V) {
+                       if (state->Vcc == 50)
+                               state->Vpp = 50;
+                       else
+                               state->Vpp = 33;
+               }
+               if (vpp == I365_VPP1_12V)
+                       state->Vpp = 120;
+       }
+
+       /*
+        * Now the IO card, RESET flags and IO interrupt
+        * IGENC, Interrupt and General Control
+        */
+       reg = indirect_read(socket, I365_INTCTL);
+
+       if ((reg & I365_PC_RESET) == 0)
+               state->flags |= SS_RESET;
+       if (reg & I365_PC_IOCARD)
+               state->flags |= SS_IOCARD; /* This is an IO card */
+
+       /* Set the IRQ number */
+       state->io_irq = socket->socket.pci_irq;
+
+       /*
+        * Card status change
+        * CSCICR, Card Status Change Interrupt Configuration
+        */
+       reg = indirect_read(socket, I365_CSCINT);
+
+       if (reg & I365_CSC_DETECT)
+               state->csc_mask |= SS_DETECT; /* Card detect is enabled */
+
+       if (state->flags & SS_IOCARD) {/* IO Cards behave different */
+               if (reg & I365_CSC_STSCHG)
+                       state->csc_mask |= SS_STSCHG;
+       } else {
+               if (reg & I365_CSC_BVD1)
+                       state->csc_mask |= SS_BATDEAD;
+               if (reg & I365_CSC_BVD2)
+                       state->csc_mask |= SS_BATWARN;
+               if (reg & I365_CSC_READY)
+                       state->csc_mask |= SS_READY;
+       }
+
+       return 0;
+}
+
+static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+       struct pd6729_socket *socket = container_of(sock, struct pd6729_socket, socket);
+       unsigned char reg;
+
+       /* First, set the global controller options */
+
+       set_bridge_state(socket);
+
+       /* Values for the IGENC register */
+
+       reg = 0;
+       /* The reset bit has "inverse" logic */
+       if (!(state->flags & SS_RESET))
+               reg = reg | I365_PC_RESET;
+       if (state->flags & SS_IOCARD)
+               reg = reg | I365_PC_IOCARD;
+
+       /* IGENC, Interrupt and General Control Register */
+       indirect_write(socket, I365_INTCTL, reg);
+
+       /* Power registers */
+
+       reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
+
+       if (state->flags & SS_PWR_AUTO) {
+               dprintk("Auto power\n");
+               reg |= I365_PWR_AUTO;   /* automatic power mngmnt */
+       }
+       if (state->flags & SS_OUTPUT_ENA) {
+               dprintk("Power Enabled\n");
+               reg |= I365_PWR_OUT;    /* enable power */
+       }
+
+       switch (state->Vcc) {
+       case 0:
+               break;
+       case 33:
+               dprintk("setting voltage to Vcc to 3.3V on socket %i\n",
+                       socket->number);
+               reg |= I365_VCC_5V;
+               indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+               break;
+       case 50:
+               dprintk("setting voltage to Vcc to 5V on socket %i\n",
+                       socket->number);
+               reg |= I365_VCC_5V;
+               indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+               break;
+       default:
+               dprintk("pd6729: pd6729_set_socket called with invalid VCC power value: %i\n",
+                       state->Vcc);
+               return -EINVAL;
+       }
+
+       switch (state->Vpp) {
+       case 0:
+               dprintk("not setting Vpp on socket %i\n", socket->number);
+               break;
+       case 33:
+       case 50:
+               dprintk("setting Vpp to Vcc for socket %i\n", socket->number);
+               reg |= I365_VPP1_5V;
+               break;
+       case 120:
+               dprintk("setting Vpp to 12.0\n");
+               reg |= I365_VPP1_12V;
+               break;
+       default:
+               dprintk("pd6729: pd6729_set_socket called with invalid VPP power value: %i\n",
+                       state->Vpp);
+               return -EINVAL;
+       }
+
+       /* only write if changed */
+       if (reg != indirect_read(socket, I365_POWER))
+               indirect_write(socket, I365_POWER, reg);
+
+       /* Now, specifiy that all interrupts are to be done as PCI interrupts */
+       indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1);
+       indirect_write(socket, PD67_EXT_DATA, PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ);
+
+       /* Enable specific interrupt events */
+
+       reg = 0x00;
+       if (state->csc_mask & SS_DETECT) {
+               reg |= I365_CSC_DETECT;
+       }
+       if (state->flags & SS_IOCARD) {
+               if (state->csc_mask & SS_STSCHG)
+                       reg |= I365_CSC_STSCHG;
+       } else {
+               if (state->csc_mask & SS_BATDEAD)
+                       reg |= I365_CSC_BVD1;
+               if (state->csc_mask & SS_BATWARN)
+                       reg |= I365_CSC_BVD2;
+               if (state->csc_mask & SS_READY)
+                       reg |= I365_CSC_READY;
+       }
+       reg |= 0x30;    /* management IRQ: PCI INTA# = "irq 3" */
+       indirect_write(socket, I365_CSCINT, reg);
+
+       reg = indirect_read(socket, I365_INTCTL);
+       reg |= 0x03;    /* card IRQ: PCI INTA# = "irq 3" */
+       indirect_write(socket, I365_INTCTL, reg);
+
+       /* now clear the (probably bogus) pending stuff by doing a dummy read */
+       (void)indirect_read(socket, I365_CSC);
+
+       return 0;
+}
+
+static int pd6729_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
+{
+       struct pd6729_socket *socket = container_of(sock, struct pd6729_socket, socket);
+       unsigned char map, ioctl;
+
+       map = io->map;
+
+       /* Check error conditions */
+       if (map > 1) {
+               dprintk("pd6729_set_io_map with invalid map");
+               return -EINVAL;
+       }
+
+       /* Turn off the window before changing anything */
+       if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map))
+               indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
+
+/*     dprintk("set_io_map: Setting range to %x - %x\n", io->start, io->stop);*/
+
+       /* write the new values */
+       indirect_write16(socket, I365_IO(map)+I365_W_START, io->start);
+       indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop);
+
+       ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+
+       if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+       if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+       if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+
+       indirect_write(socket, I365_IOCTL, ioctl);
+
+       /* Turn the window back on if needed */
+       if (io->flags & MAP_ACTIVE)
+               indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
+
+       return 0;
+}
+
+static int pd6729_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+{
+       struct pd6729_socket *socket = container_of(sock, struct pd6729_socket, socket);
+       unsigned short base, i;
+       unsigned char map;
+
+       map = mem->map;
+       if (map > 4) {
+               printk("pd6729_set_mem_map: invalid map");
+               return -EINVAL;
+       }
+
+       if ((mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) {
+               printk("pd6729_set_mem_map: invalid address / speed");
+               /* printk("invalid mem map for socket %i : %lx to %lx with a start of %x\n",
+                        sock, mem->sys_start, mem->sys_stop, mem->card_start); */
+               return -EINVAL;
+       }
+
+       /* Turn off the window before changing anything */
+       if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map))
+               indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
+
+       /* write the start address */
+       base = I365_MEM(map);
+       i = (mem->sys_start >> 12) & 0x0fff;
+       if (mem->flags & MAP_16BIT)
+               i |= I365_MEM_16BIT;
+       if (mem->flags & MAP_0WS)
+               i |= I365_MEM_0WS;
+       indirect_write16(socket, base + I365_W_START, i);
+
+       /* write the stop address */
+
+       i= (mem->sys_stop >> 12) & 0x0fff;
+       switch (to_cycles(mem->speed)) {
+       case 0:
+               break;
+       case 1:
+               i |= I365_MEM_WS0;
+               break;
+       case 2:
+               i |= I365_MEM_WS1;
+               break;
+       default:
+               i |= I365_MEM_WS1 | I365_MEM_WS0;
+               break;
+       }
+
+       indirect_write16(socket, base + I365_W_STOP, i);
+
+       /* Take care of high byte */
+       indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+       indirect_write(socket, PD67_EXT_DATA, mem->sys_start >> 24);
+
+       /* card start */
+
+       i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+       if (mem->flags & MAP_WRPROT)
+               i |= I365_MEM_WRPROT;
+       if (mem->flags & MAP_ATTRIB) {
+/*             dprintk("requesting attribute memory for socket %i\n",
+                       socket->number);*/
+               i |= I365_MEM_REG;
+       } else {
+/*             dprintk("requesting normal memory for socket %i\n",
+                       socket->number);*/
+       }
+       indirect_write16(socket, base + I365_W_OFF, i);
+
+       /* Enable the window if necessary */
+       if (mem->flags & MAP_ACTIVE)
+               indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
+
+       return 0;
+}
+
+static int pd6729_suspend(struct pcmcia_socket *sock)
+{
+       return pd6729_set_socket(sock, &dead_socket);
+}
+
+static int pd6729_init(struct pcmcia_socket *sock)
+{
+       int i;
+       struct resource res = { .end = 0x0fff };
+       pccard_io_map io = { 0, 0, 0, 0, 1 };
+       pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff };
+
+       pd6729_set_socket(sock, &dead_socket);
+       for (i = 0; i < 2; i++) {
+               io.map = i;
+               pd6729_set_io_map(sock, &io);
+       }
+       for (i = 0; i < 5; i++) {
+               mem.map = i;
+               pd6729_set_mem_map(sock, &mem);
+       }
+
+       return 0;
+}
+
+
+/* the pccard structure and its functions */
+static struct pccard_operations pd6729_operations = {
+       .init                   = pd6729_init,
+       .suspend                = pd6729_suspend,
+       .get_status             = pd6729_get_status,
+       .get_socket             = pd6729_get_socket,
+       .set_socket             = pd6729_set_socket,
+       .set_io_map             = pd6729_set_io_map,
+       .set_mem_map            = pd6729_set_mem_map,
+};
+
+static int __devinit pd6729_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       int i, j, ret;
+       char configbyte;
+       struct pd6729_socket *socket;
+
+       socket = kmalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, GFP_KERNEL);
+       if (!socket)
+               return -ENOMEM;
+
+       memset(socket, 0, sizeof(struct pd6729_socket) * MAX_SOCKETS);
+
+       if ((ret = pci_enable_device(dev)))
+               goto err_out_free_mem;
+
+       printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge at 0x%lx on irq %d\n",
+               pci_resource_start(dev, 0), dev->irq);
+       printk(KERN_INFO "pd6729: configured as a %d socket device.\n", MAX_SOCKETS);
+       /*
+        * Since we have no memory BARs some firmware we may not
+        * have had PCI_COMMAND_MEM enabled, yet the device needs
+        * it.
+        */
+       pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
+       if (!(configbyte & PCI_COMMAND_MEMORY)) {
+               printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n");
+               configbyte |= PCI_COMMAND_MEMORY;
+               pci_write_config_byte(dev, PCI_COMMAND, configbyte);
+       }
+
+       ret = pci_request_regions(dev, "pd6729");
+       if (ret) {
+               printk(KERN_INFO "pd6729: pci request region failed.\n");
+               goto err_out_disable;
+       }
+
+       for (i = 0; i < MAX_SOCKETS; i++) {
+               socket[i].io_base = pci_resource_start(dev, 0);
+               socket[i].socket.features |= SS_CAP_PCCARD;
+               socket[i].socket.map_size = 0x1000;
+               socket[i].socket.irq_mask = 0;
+               socket[i].socket.pci_irq  = dev->irq;
+               socket[i].socket.owner = THIS_MODULE;
+
+               socket[i].number = i;
+
+               socket[i].socket.ops = &pd6729_operations;
+               socket[i].socket.dev.dev = &dev->dev;
+               socket[i].socket.driver_data = &socket[i];
+       }
+
+       pci_set_drvdata(dev, socket);
+
+       /* Register the interrupt handler */
+       if ((ret = request_irq(dev->irq, pd6729_interrupt, SA_SHIRQ, "pd6729", socket))) {
+               printk(KERN_ERR "pd6729: Failed to register irq %d, aborting\n", dev->irq);
+               goto err_out_free_res;
+       }
+
+       for (i = 0; i < MAX_SOCKETS; i++) {
+               ret = pcmcia_register_socket(&socket[i].socket);
+               if (ret) {
+                       printk(KERN_INFO "pd6729: pcmcia_register_socket failed.\n");
+                       for (j = 0; j < i ; j++)
+                               pcmcia_unregister_socket(&socket[j].socket);
+                       goto err_out_free_res2;
+               }
+       }
+
+       return 0;
+
+ err_out_free_res2:
+       free_irq(dev->irq, socket);
+ err_out_free_res:
+       pci_release_regions(dev);
+ err_out_disable:
+       pci_disable_device(dev);
+
+ err_out_free_mem:
+       kfree(socket);
+       return ret;
+}
+
+static void __devexit pd6729_pci_remove(struct pci_dev *dev)
+{
+       int i;
+       struct pd6729_socket *socket = pci_get_drvdata(dev);
+
+       for (i = 0; i < MAX_SOCKETS; i++)
+               pcmcia_unregister_socket(&socket[i].socket);
+
+       free_irq(dev->irq, socket);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+
+       kfree(socket);
+}
+
+static int pd6729_socket_suspend(struct pci_dev *dev, u32 state)
+{
+       return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int pd6729_socket_resume(struct pci_dev *dev)
+{
+       return pcmcia_socket_dev_resume(&dev->dev);
+}
+
+static struct pci_device_id pd6729_pci_ids[] = {
+       {
+               .vendor         = PCI_VENDOR_ID_CIRRUS,
+               .device         = PCI_DEVICE_ID_CIRRUS_6729,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
+
+static struct pci_driver pd6729_pci_drv = {
+       .name           = "pd6729",
+       .id_table       = pd6729_pci_ids,
+       .probe          = pd6729_pci_probe,
+       .remove         = __devexit_p(pd6729_pci_remove),
+       .suspend        = pd6729_socket_suspend,
+       .resume         = pd6729_socket_resume,
+};
+
+static int pd6729_module_init(void)
+{
+       return pci_module_init(&pd6729_pci_drv);
+}
+
+static void pd6729_module_exit(void)
+{
+       pci_unregister_driver(&pd6729_pci_drv);
+}
+
+module_init(pd6729_module_init);
+module_exit(pd6729_module_exit);
diff --git a/drivers/s390/net/ctcdbug.c b/drivers/s390/net/ctcdbug.c
new file mode 100644 (file)
index 0000000..2c86bfa
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *
+ * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $)
+ *
+ * CTC / ESCON network driver - s390 dbf exploit.
+ *
+ * Copyright 2000,2003 IBM Corporation
+ *
+ *    Author(s): Original Code written by
+ *                       Peter Tiedemann (ptiedem@de.ibm.com)
+ *
+ *    $Revision: 1.4 $  $Date: 2004/08/04 10:11:59 $
+ *
+ * This program is free software; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ctcdbug.h"
+
+/**
+ * Debug Facility Stuff
+ */
+debug_info_t *ctc_dbf_setup = NULL;
+debug_info_t *ctc_dbf_data = NULL;
+debug_info_t *ctc_dbf_trace = NULL;
+
+DEFINE_PER_CPU(char[256], ctc_dbf_txt_buf);
+
+void
+ctc_unregister_dbf_views(void)
+{
+       if (ctc_dbf_setup)
+               debug_unregister(ctc_dbf_setup);
+       if (ctc_dbf_data)
+               debug_unregister(ctc_dbf_data);
+       if (ctc_dbf_trace)
+               debug_unregister(ctc_dbf_trace);
+}
+int
+ctc_register_dbf_views(void)
+{
+       ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
+                                       CTC_DBF_SETUP_INDEX,
+                                       CTC_DBF_SETUP_NR_AREAS,
+                                       CTC_DBF_SETUP_LEN);
+       ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME,
+                                      CTC_DBF_DATA_INDEX,
+                                      CTC_DBF_DATA_NR_AREAS,
+                                      CTC_DBF_DATA_LEN);
+       ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
+                                       CTC_DBF_TRACE_INDEX,
+                                       CTC_DBF_TRACE_NR_AREAS,
+                                       CTC_DBF_TRACE_LEN);
+
+       if ((ctc_dbf_setup == NULL) || (ctc_dbf_data == NULL) ||
+           (ctc_dbf_trace == NULL)) {
+               ctc_unregister_dbf_views();
+               return -ENOMEM;
+       }
+       debug_register_view(ctc_dbf_setup, &debug_hex_ascii_view);
+       debug_set_level(ctc_dbf_setup, CTC_DBF_SETUP_LEVEL);
+
+       debug_register_view(ctc_dbf_data, &debug_hex_ascii_view);
+       debug_set_level(ctc_dbf_data, CTC_DBF_DATA_LEVEL);
+
+       debug_register_view(ctc_dbf_trace, &debug_hex_ascii_view);
+       debug_set_level(ctc_dbf_trace, CTC_DBF_TRACE_LEVEL);
+
+       return 0;
+}
+
+
diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h
new file mode 100644 (file)
index 0000000..5c0fcfc
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.3 $)
+ *
+ * CTC / ESCON network driver - s390 dbf exploit.
+ *
+ * Copyright 2000,2003 IBM Corporation
+ *
+ *    Author(s): Original Code written by
+ *                       Peter Tiedemann (ptiedem@de.ibm.com)
+ *
+ *    $Revision: 1.3 $  $Date: 2004/07/28 12:27:54 $
+ *
+ * This program is free software; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <asm/debug.h>
+/**
+ * Debug Facility stuff
+ */
+#define CTC_DBF_SETUP_NAME "ctc_setup"
+#define CTC_DBF_SETUP_LEN 16
+#define CTC_DBF_SETUP_INDEX 3
+#define CTC_DBF_SETUP_NR_AREAS 1
+#define CTC_DBF_SETUP_LEVEL 3
+
+#define CTC_DBF_DATA_NAME "ctc_data"
+#define CTC_DBF_DATA_LEN 128
+#define CTC_DBF_DATA_INDEX 3
+#define CTC_DBF_DATA_NR_AREAS 1
+#define CTC_DBF_DATA_LEVEL 2
+
+#define CTC_DBF_TRACE_NAME "ctc_trace"
+#define CTC_DBF_TRACE_LEN 16
+#define CTC_DBF_TRACE_INDEX 2
+#define CTC_DBF_TRACE_NR_AREAS 2
+#define CTC_DBF_TRACE_LEVEL 3
+
+#define DBF_TEXT(name,level,text) \
+       do { \
+               debug_text_event(ctc_dbf_##name,level,text); \
+       } while (0)
+
+#define DBF_HEX(name,level,addr,len) \
+       do { \
+               debug_event(ctc_dbf_##name,level,(void*)(addr),len); \
+       } while (0)
+
+extern DEFINE_PER_CPU(char[256], ctc_dbf_txt_buf);
+extern debug_info_t *ctc_dbf_setup;
+extern debug_info_t *ctc_dbf_data;
+extern debug_info_t *ctc_dbf_trace;
+
+
+#define DBF_TEXT_(name,level,text...)                          \
+       do {                                                            \
+               char* ctc_dbf_txt_buf = get_cpu_var(ctc_dbf_txt_buf);   \
+               sprintf(ctc_dbf_txt_buf, text);                         \
+               debug_text_event(ctc_dbf_##name,level,ctc_dbf_txt_buf); \
+               put_cpu_var(ctc_dbf_txt_buf);                           \
+       } while (0)
+
+#define DBF_SPRINTF(name,level,text...) \
+       do { \
+               debug_sprintf_event(ctc_dbf_trace, level, ##text ); \
+               debug_sprintf_event(ctc_dbf_trace, level, text ); \
+       } while (0)
+
+
+int ctc_register_dbf_views(void);
+
+void ctc_unregister_dbf_views(void);
+
+/**
+ * some more debug stuff
+ */
+
+#define HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+                  *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+                  *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+                  *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+                  *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+                  *(((char*)ptr)+12),*(((char*)ptr)+13), \
+                  *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+                  *(((char*)ptr)+16),*(((char*)ptr)+17), \
+                  *(((char*)ptr)+18),*(((char*)ptr)+19), \
+                  *(((char*)ptr)+20),*(((char*)ptr)+21), \
+                  *(((char*)ptr)+22),*(((char*)ptr)+23), \
+                  *(((char*)ptr)+24),*(((char*)ptr)+25), \
+                  *(((char*)ptr)+26),*(((char*)ptr)+27), \
+                  *(((char*)ptr)+28),*(((char*)ptr)+29), \
+                  *(((char*)ptr)+30),*(((char*)ptr)+31));
+
+static inline void
+hex_dump(unsigned char *buf, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               if (i && !(i % 16))
+                       printk("\n");
+               printk("%02x ", *(buf + i));
+       }
+       printk("\n");
+}
+
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
new file mode 100644 (file)
index 0000000..2bac40c
--- /dev/null
@@ -0,0 +1,2154 @@
+/*
+   3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004 Applied Micro Circuits Corporation.
+
+   This program is free software; 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.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   You 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
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+
+   Note: This version of the driver does not contain a bundled firmware
+         image.
+
+   History
+   -------
+   2.26.02.000 - Driver cleanup for kernel submission.
+   2.26.02.001 - Replace schedule_timeout() calls with msleep().
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-9xxx.h"
+
+/* Globals */
+static const char *twa_driver_version="2.26.02.001";
+static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
+static unsigned int twa_device_extension_count;
+static int twa_major = -1;
+extern struct timezone sys_tz;
+
+/* Module parameters */
+MODULE_AUTHOR ("AMCC");
+MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+
+/* Function prototypes */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_aen_severity_lookup(unsigned char severity_code);
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int twa_chrdev_open(struct inode *inode, struct file *file);
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
+static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+                             u32 set_features, unsigned short current_fw_srl, 
+                             unsigned short current_fw_arch_id, 
+                             unsigned short current_fw_branch, 
+                             unsigned short current_fw_build, 
+                             unsigned short *fw_on_ctlr_srl, 
+                             unsigned short *fw_on_ctlr_arch_id, 
+                             unsigned short *fw_on_ctlr_branch, 
+                             unsigned short *fw_on_ctlr_build, 
+                             u32 *init_connect_result);
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg);
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
+
+/* Functions */
+
+/* Show some statistics about the card */
+static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *host = class_to_shost(class_dev);
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+       unsigned long flags = 0;
+       ssize_t len;
+
+       spin_lock_irqsave(tw_dev->host->host_lock, flags);
+       len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n"
+                      "Current commands posted:   %4d\n"
+                      "Max commands posted:       %4d\n"
+                      "Current pending commands:  %4d\n"
+                      "Max pending commands:      %4d\n"
+                      "Last sgl length:           %4d\n"
+                      "Max sgl length:            %4d\n"
+                      "Last sector count:         %4d\n"
+                      "Max sector count:          %4d\n"
+                      "SCSI Host Resets:          %4d\n"
+                      "SCSI Aborts/Timeouts:      %4d\n"
+                      "AEN's:                     %4d\n", 
+                      twa_driver_version,
+                      tw_dev->posted_request_count,
+                      tw_dev->max_posted_request_count,
+                      tw_dev->pending_request_count,
+                      tw_dev->max_pending_request_count,
+                      tw_dev->sgl_entries,
+                      tw_dev->max_sgl_entries,
+                      tw_dev->sector_count,
+                      tw_dev->max_sector_count,
+                      tw_dev->num_resets,
+                      tw_dev->num_aborts,
+                      tw_dev->aen_count);
+       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+       return len;
+} /* End twa_show_stats() */
+
+/* This function will set a devices queue depth */
+static ssize_t twa_store_queue_depth(struct device *dev, const char *buf, size_t count)
+{
+       int queue_depth;
+       struct scsi_device *sdev = to_scsi_device(dev);
+
+       queue_depth = simple_strtoul(buf, NULL, 0);
+       if (queue_depth > TW_Q_LENGTH-2)
+               return -EINVAL;
+       scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+
+       return count;
+} /* End twa_store_queue_depth() */
+
+/* Create sysfs 'queue_depth' entry */
+static struct device_attribute twa_queue_depth_attr = {
+       .attr = {
+               .name =         "queue_depth",
+               .mode =         S_IRUSR | S_IWUSR,
+       },
+       .store = twa_store_queue_depth
+};
+
+/* Device attributes initializer */
+static struct device_attribute *twa_dev_attrs[] = {
+       &twa_queue_depth_attr,
+       NULL,
+};
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute twa_host_stats_attr = {
+       .attr = {
+               .name =         "stats",
+               .mode =         S_IRUGO,
+       },
+       .show = twa_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *twa_host_attrs[] = {
+       &twa_host_stats_attr,
+       NULL,
+};
+
+/* File operations struct for character device */
+static struct file_operations twa_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = twa_chrdev_ioctl,
+       .open           = twa_chrdev_open,
+       .release        = NULL
+};
+
+/* This function will complete an aen request from the isr */
+static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+       TW_Command_Full *full_command_packet;
+       TW_Command *command_packet;
+       TW_Command_Apache_Header *header;
+       unsigned short aen;
+       int retval = 1;
+
+       header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+       tw_dev->posted_request_count--;
+       aen = header->status_block.error;
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       command_packet = &full_command_packet->command.oldcommand;
+
+       /* First check for internal completion of set param for time sync */
+       if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
+               /* Keep reading the queue in case there are more aen's */
+               if (twa_aen_read_queue(tw_dev, request_id))
+                       goto out2;
+               else {
+                       retval = 0;
+                       goto out;
+               }
+       }
+
+       switch (aen) {
+       case TW_AEN_QUEUE_EMPTY:
+               /* Quit reading the queue if this is the last one */
+               break;
+       case TW_AEN_SYNC_TIME_WITH_HOST:
+               twa_aen_sync_time(tw_dev, request_id);
+               retval = 0;
+               goto out;
+       default:
+               twa_aen_queue_event(tw_dev, header);
+
+               /* If there are more aen's, keep reading the queue */
+               if (twa_aen_read_queue(tw_dev, request_id))
+                       goto out2;
+               else {
+                       retval = 0;
+                       goto out;
+               }
+       }
+       retval = 0;
+out2:
+       tw_dev->state[request_id] = TW_S_COMPLETED;
+       twa_free_request_id(tw_dev, request_id);
+       clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+out:
+       return retval;
+} /* End twa_aen_complete() */
+
+/* This function will drain aen queue */
+static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
+{
+       int request_id = 0;
+       char cdb[TW_MAX_CDB_LEN];
+       TW_SG_Apache sglist[1];
+       int finished = 0, count = 0;
+       TW_Command_Full *full_command_packet;
+       TW_Command_Apache_Header *header;
+       unsigned short aen;
+       int first_reset = 0, queue = 0, retval = 1;
+
+       if (no_check_reset)
+               first_reset = 0;
+       else
+               first_reset = 1;
+
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+       /* Initialize cdb */
+       memset(&cdb, 0, TW_MAX_CDB_LEN);
+       cdb[0] = REQUEST_SENSE; /* opcode */
+       cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+       /* Initialize sglist */
+       memset(&sglist, 0, sizeof(TW_SG_Apache));
+       sglist[0].length = TW_SECTOR_SIZE;
+       sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+       if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
+               goto out;
+       }
+
+       /* Mark internal command */
+       tw_dev->srb[request_id] = NULL;
+
+       do {
+               /* Send command to the board */
+               if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
+                       goto out;
+               }
+
+               /* Now poll for completion */
+               if (twa_poll_response(tw_dev, request_id, 30)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
+                       tw_dev->posted_request_count--;
+                       goto out;
+               }
+
+               tw_dev->posted_request_count--;
+               header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+               aen = header->status_block.error;
+               queue = 0;
+               count++;
+
+               switch (aen) {
+               case TW_AEN_QUEUE_EMPTY:
+                       if (first_reset != 1)
+                               goto out;
+                       else
+                               finished = 1;
+                       break;
+               case TW_AEN_SOFT_RESET:
+                       if (first_reset == 0)
+                               first_reset = 1;
+                       else
+                               queue = 1;
+                       break;
+               case TW_AEN_SYNC_TIME_WITH_HOST:
+                       break;
+               default:
+                       queue = 1;
+               }
+
+               /* Now queue an event info */
+               if (queue)
+                       twa_aen_queue_event(tw_dev, header);
+       } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
+
+       if (count == TW_MAX_AEN_DRAIN)
+               goto out;
+
+       retval = 0;
+out:
+       tw_dev->state[request_id] = TW_S_INITIAL;
+       return retval;
+} /* End twa_aen_drain_queue() */
+
+/* This function will queue an event */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
+{
+       u32 local_time;
+       struct timeval time;
+       TW_Event *event;
+       unsigned short aen;
+       char host[16];
+
+       tw_dev->aen_count++;
+
+       /* Fill out event info */
+       event = tw_dev->event_queue[tw_dev->error_index];
+
+       /* Check for clobber */
+       host[0] = '\0';
+       if (tw_dev->host) {
+               sprintf(host, " scsi%d:", tw_dev->host->host_no);
+               if (event->retrieved == TW_AEN_NOT_RETRIEVED)
+                       tw_dev->aen_clobber = 1;
+       }
+
+       aen = header->status_block.error;
+       memset(event, 0, sizeof(TW_Event));
+
+       event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
+       do_gettimeofday(&time);
+       local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+       event->time_stamp_sec = local_time;
+       event->aen_code = aen;
+       event->retrieved = TW_AEN_NOT_RETRIEVED;
+       event->sequence_id = tw_dev->error_sequence_id;
+       tw_dev->error_sequence_id++;
+
+       header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
+       event->parameter_len = strlen(header->err_specific_desc);
+       memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
+       if (event->severity != TW_AEN_SEVERITY_DEBUG)
+               printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
+                      host,
+                      twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
+                      TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
+                      twa_string_lookup(twa_aen_table, aen),
+                      header->err_specific_desc);
+       else
+               tw_dev->aen_count--;
+
+       if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
+               tw_dev->event_queue_wrapped = 1;
+       tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
+} /* End twa_aen_queue_event() */
+
+/* This function will read the aen queue from the isr */
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
+{
+       char cdb[TW_MAX_CDB_LEN];
+       TW_SG_Apache sglist[1];
+       TW_Command_Full *full_command_packet;
+       int retval = 1;
+
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+       /* Initialize cdb */
+       memset(&cdb, 0, TW_MAX_CDB_LEN);
+       cdb[0] = REQUEST_SENSE; /* opcode */
+       cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+       /* Initialize sglist */
+       memset(&sglist, 0, sizeof(TW_SG_Apache));
+       sglist[0].length = TW_SECTOR_SIZE;
+       sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+       /* Mark internal command */
+       tw_dev->srb[request_id] = NULL;
+
+       /* Now post the command packet */
+       if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
+               goto out;
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_aen_read_queue() */
+
+/* This function will look up an AEN severity string */
+static char *twa_aen_severity_lookup(unsigned char severity_code)
+{
+       char *retval = NULL;
+
+       if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
+           (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
+               goto out;
+
+       retval = twa_aen_severity_table[severity_code];
+out:
+       return retval;
+} /* End twa_aen_severity_lookup() */
+
+/* This function will sync firmware time with the host time */
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
+{
+       u32 schedulertime;
+       struct timeval utc;
+       TW_Command_Full *full_command_packet;
+       TW_Command *command_packet;
+       TW_Param_Apache *param;
+       u32 local_time;
+
+       /* Fill out the command packet */
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       memset(full_command_packet, 0, sizeof(TW_Command_Full));
+       command_packet = &full_command_packet->command.oldcommand;
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+       command_packet->request_id = request_id;
+       command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id];
+       command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+       command_packet->size = TW_COMMAND_SIZE;
+       command_packet->byte6_offset.parameter_count = 1;
+
+       /* Setup the param */
+       param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+       memset(param, 0, TW_SECTOR_SIZE);
+       param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */
+       param->parameter_id = 0x3; /* SchedulerTime */
+       param->parameter_size_bytes = 4;
+
+       /* Convert system time in UTC to local time seconds since last 
+           Sunday 12:00AM */
+       do_gettimeofday(&utc);
+       local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
+       schedulertime = local_time - (3 * 86400);
+       schedulertime = schedulertime % 604800;
+
+       memcpy(param->data, &schedulertime, sizeof(u32));
+
+       /* Mark internal command */
+       tw_dev->srb[request_id] = NULL;
+
+       /* Now post the command */
+       twa_post_command_packet(tw_dev, request_id, 1);
+} /* End twa_aen_sync_time() */
+
+/* This function will allocate memory and check if it is correctly aligned */
+static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+       int i;
+       dma_addr_t dma_handle;
+       unsigned long *cpu_addr;
+       int retval = 1;
+
+       cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+       if (!cpu_addr) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
+               goto out;
+       }
+
+       if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
+               pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+               goto out;
+       }
+
+       memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+       for (i = 0; i < TW_Q_LENGTH; i++) {
+               switch(which) {
+               case 0:
+                       tw_dev->command_packet_phys[i] = dma_handle+(i*size);
+                       tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
+                       break;
+               case 1:
+                       tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
+                       tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+                       break;
+               }
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_allocate_memory() */
+
+/* This function will check the status register for unexpected bits */
+static int twa_check_bits(u32 status_reg_value)
+{
+       int retval = 1;
+
+       if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
+               goto out;
+       if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
+               goto out;
+
+       retval = 0;
+out:
+       return retval;
+} /* End twa_check_bits() */
+
+/* This function will check the srl and decide if we are compatible  */
+static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
+{
+       int retval = 1;
+       unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
+       unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
+       u32 init_connect_result = 0;
+
+       if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+                              TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL,
+                              TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH,
+                              TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl,
+                              &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
+                              &fw_on_ctlr_build, &init_connect_result)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
+               goto out;
+       }
+
+       tw_dev->working_srl = TW_CURRENT_FW_SRL;
+       tw_dev->working_branch = TW_CURRENT_FW_BRANCH;
+       tw_dev->working_build = TW_CURRENT_FW_BUILD;
+
+       /* Try base mode compatibility */
+       if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+               if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+                                      TW_EXTENDED_INIT_CONNECT,
+                                      TW_BASE_FW_SRL, TW_9000_ARCH_ID,
+                                      TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
+                                      &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
+                                      &fw_on_ctlr_branch, &fw_on_ctlr_build,
+                                      &init_connect_result)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
+                       goto out;
+               }
+               if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+                       if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
+                       } else {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
+                       }
+                       goto out;
+               }
+               tw_dev->working_srl = TW_BASE_FW_SRL;
+               tw_dev->working_branch = TW_BASE_FW_BRANCH;
+               tw_dev->working_build = TW_BASE_FW_BUILD;
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_check_srl() */
+
+/* This function handles ioctl for the character device */
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       long timeout;
+       unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
+       dma_addr_t dma_handle;
+       int request_id = 0;
+       unsigned int sequence_id = 0;
+       unsigned char event_index, start_index;
+       TW_Ioctl_Driver_Command driver_command;
+       TW_Ioctl_Buf_Apache *tw_ioctl;
+       TW_Lock *tw_lock;
+       TW_Command_Full *full_command_packet;
+       TW_Compatibility_Info *tw_compat_info;
+       TW_Event *event;
+       struct timeval current_time;
+       u32 current_time_ms;
+       TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
+       int retval = TW_IOCTL_ERROR_OS_EFAULT;
+       void __user *argp = (void __user *)arg;
+
+       /* Only let one of these through at a time */
+       if (down_interruptible(&tw_dev->ioctl_sem)) {
+               retval = TW_IOCTL_ERROR_OS_EINTR;
+               goto out;
+       }
+
+       /* First copy down the driver command */
+       if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
+               goto out2;
+
+       /* Check data buffer size */
+       if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+               retval = TW_IOCTL_ERROR_OS_EINVAL;
+               goto out2;
+       }
+
+       /* Hardware can only do multiple of 512 byte transfers */
+       data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
+
+       /* Now allocate ioctl buf memory */
+       cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);
+       if (!cpu_addr) {
+               retval = TW_IOCTL_ERROR_OS_ENOMEM;
+               goto out2;
+       }
+
+       tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
+
+       /* Now copy down the entire ioctl */
+       if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+               goto out3;
+
+       /* See which ioctl we are doing */
+       switch (cmd) {
+       case TW_IOCTL_FIRMWARE_PASS_THROUGH:
+               spin_lock_irqsave(tw_dev->host->host_lock, flags);
+               twa_get_request_id(tw_dev, &request_id);
+
+               /* Flag internal command */
+               tw_dev->srb[request_id] = NULL;
+
+               /* Flag chrdev ioctl */
+               tw_dev->chrdev_request_id = request_id;
+
+               full_command_packet = &tw_ioctl->firmware_command;
+
+               /* Load request id and sglist for both command types */
+               twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+
+               memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
+
+               /* Now post the command packet to the controller */
+               twa_post_command_packet(tw_dev, request_id, 1);
+               spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+               timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+               /* Now wait for command to complete */
+               timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+               /* Check if we timed out, got a signal, or didn't get
+                   an interrupt */
+               if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+                       /* Now we need to reset the board */
+                       if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {
+                               retval = timeout;
+                       } else {
+                               printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+                                      tw_dev->host->host_no, TW_DRIVER, 0xc,
+                                      cmd);
+                               retval = TW_IOCTL_ERROR_OS_EIO;
+                       }
+                       spin_lock_irqsave(tw_dev->host->host_lock, flags);
+                       tw_dev->state[request_id] = TW_S_COMPLETED;
+                       twa_free_request_id(tw_dev, request_id);
+                       tw_dev->posted_request_count--;
+                       twa_reset_device_extension(tw_dev);
+                       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+                       goto out3;
+               }
+
+               /* Now copy in the command packet response */
+               memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
+               
+               /* Now complete the io */
+               spin_lock_irqsave(tw_dev->host->host_lock, flags);
+               tw_dev->posted_request_count--;
+               tw_dev->state[request_id] = TW_S_COMPLETED;
+               twa_free_request_id(tw_dev, request_id);
+               spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+               break;
+       case TW_IOCTL_GET_COMPATIBILITY_INFO:
+               tw_ioctl->driver_command.status = 0;
+               /* Copy compatiblity struct into ioctl data buffer */
+               tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
+               strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));
+               tw_compat_info->working_srl = tw_dev->working_srl;
+               tw_compat_info->working_branch = tw_dev->working_branch;
+               tw_compat_info->working_build = tw_dev->working_build;
+               break;
+       case TW_IOCTL_GET_LAST_EVENT:
+               if (tw_dev->event_queue_wrapped) {
+                       if (tw_dev->aen_clobber) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+                               tw_dev->aen_clobber = 0;
+                       } else
+                               tw_ioctl->driver_command.status = 0;
+               } else {
+                       if (!tw_dev->error_index) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                               break;
+                       }
+                       tw_ioctl->driver_command.status = 0;
+               }
+               event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
+               memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+               tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+               break;
+       case TW_IOCTL_GET_FIRST_EVENT:
+               if (tw_dev->event_queue_wrapped) {
+                       if (tw_dev->aen_clobber) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+                               tw_dev->aen_clobber = 0;
+                       } else 
+                               tw_ioctl->driver_command.status = 0;
+                       event_index = tw_dev->error_index;
+               } else {
+                       if (!tw_dev->error_index) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                               break;
+                       }
+                       tw_ioctl->driver_command.status = 0;
+                       event_index = 0;
+               }
+               memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+               tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+               break;
+       case TW_IOCTL_GET_NEXT_EVENT:
+               event = (TW_Event *)tw_ioctl->data_buffer;
+               sequence_id = event->sequence_id;
+               tw_ioctl->driver_command.status = 0;
+
+               if (tw_dev->event_queue_wrapped) {
+                       if (tw_dev->aen_clobber) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+                               tw_dev->aen_clobber = 0;
+                       }
+                       start_index = tw_dev->error_index;
+               } else {
+                       if (!tw_dev->error_index) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                               break;
+                       }
+                       start_index = 0;
+               }
+               event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
+
+               if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
+                       if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+                               tw_dev->aen_clobber = 1;
+                       tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                       break;
+               }
+               memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+               tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+               break;
+       case TW_IOCTL_GET_PREVIOUS_EVENT:
+               event = (TW_Event *)tw_ioctl->data_buffer;
+               sequence_id = event->sequence_id;
+               tw_ioctl->driver_command.status = 0;
+
+               if (tw_dev->event_queue_wrapped) {
+                       if (tw_dev->aen_clobber) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+                               tw_dev->aen_clobber = 0;
+                       }
+                       start_index = tw_dev->error_index;
+               } else {
+                       if (!tw_dev->error_index) {
+                               tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                               break;
+                       }
+                       start_index = 0;
+               }
+               event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
+
+               if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
+                       if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+                               tw_dev->aen_clobber = 1;
+                       tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+                       break;
+               }
+               memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+               tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+               break;
+       case TW_IOCTL_GET_LOCK:
+               tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
+               do_gettimeofday(&current_time);
+               current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
+
+               if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
+                       tw_dev->ioctl_sem_lock = 1;
+                       tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
+                       tw_ioctl->driver_command.status = 0;
+                       tw_lock->time_remaining_msec = tw_lock->timeout_msec;
+               } else {
+                       tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
+                       tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
+               }
+               break;
+       case TW_IOCTL_RELEASE_LOCK:
+               if (tw_dev->ioctl_sem_lock == 1) {
+                       tw_dev->ioctl_sem_lock = 0;
+                       tw_ioctl->driver_command.status = 0;
+               } else {
+                       tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
+               }
+               break;
+       default:
+               retval = TW_IOCTL_ERROR_OS_ENOTTY;
+               goto out3;
+       }
+
+       /* Now copy the entire response to userspace */
+       if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+               retval = 0;
+out3:
+       /* Now free ioctl buf memory */
+       pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+out2:
+       up(&tw_dev->ioctl_sem);
+out:
+       return retval;
+} /* End twa_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int twa_chrdev_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor_number;
+       int retval = TW_IOCTL_ERROR_OS_ENODEV;
+
+       minor_number = iminor(inode);
+       if (minor_number >= twa_device_extension_count)
+               goto out;
+       retval = 0;
+out:
+       return retval;
+} /* End twa_chrdev_open() */
+
+/* This function will print readable messages from status register errors */
+static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+{
+       int retval = 1;
+
+       /* Check for various error conditions and handle them appropriately */
+       if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
+               writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+       }
+
+       if (status_reg_value & TW_STATUS_PCI_ABORT) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
+               writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+               pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+       }
+
+       if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
+               writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+       }
+
+       if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
+               writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+       }
+
+       if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+               if (tw_dev->reset_print == 0) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
+                       tw_dev->reset_print = 1;
+               }
+               goto out;
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_decode_bits() */
+
+/* This function will empty the response queue */
+static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
+{
+       u32 status_reg_value, response_que_value;
+       int count = 0, retval = 1;
+
+       status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+       while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+               response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+               count++;
+       }
+       if (count == TW_MAX_RESPONSE_DRAIN)
+               goto out;
+
+       retval = 0;
+out:
+       return retval;
+} /* End twa_empty_response_queue() */
+
+/* This function passes sense keys from firmware to scsi layer */
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
+{
+       TW_Command_Full *full_command_packet;
+       unsigned short error;
+       int retval = 1;
+
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       /* Don't print error for Logical unit not supported during rollcall */
+       error = full_command_packet->header.status_block.error;
+       if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
+               if (print_host)
+                       printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+                              tw_dev->host->host_no,
+                              TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+                              full_command_packet->header.status_block.error,
+                              twa_string_lookup(twa_error_table,
+                                                full_command_packet->header.status_block.error),
+                              full_command_packet->header.err_specific_desc);
+               else
+                       printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+                              TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+                              full_command_packet->header.status_block.error,
+                              twa_string_lookup(twa_error_table,
+                                                full_command_packet->header.status_block.error),
+                              full_command_packet->header.err_specific_desc);
+       }
+
+       if (copy_sense) {
+               memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
+               tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
+               retval = TW_ISR_DONT_RESULT;
+               goto out;
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_fill_sense() */
+
+/* This function will free up device extension resources */
+static void twa_free_device_extension(TW_Device_Extension *tw_dev)
+{
+       if (tw_dev->command_packet_virt[0])
+               pci_free_consistent(tw_dev->tw_pci_dev,
+                                   sizeof(TW_Command_Full)*TW_Q_LENGTH,
+                                   tw_dev->command_packet_virt[0],
+                                   tw_dev->command_packet_phys[0]);
+
+       if (tw_dev->generic_buffer_virt[0])
+               pci_free_consistent(tw_dev->tw_pci_dev,
+                                   TW_SECTOR_SIZE*TW_Q_LENGTH,
+                                   tw_dev->generic_buffer_virt[0],
+                                   tw_dev->generic_buffer_phys[0]);
+
+       if (tw_dev->event_queue[0])
+               kfree(tw_dev->event_queue[0]);
+} /* End twa_free_device_extension() */
+
+/* This function will free a request id */
+static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
+{
+       tw_dev->free_queue[tw_dev->free_tail] = request_id;
+       tw_dev->state[request_id] = TW_S_FINISHED;
+       tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End twa_free_request_id() */
+
+/* This function will get parameter table entires from the firmware */
+static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
+{
+       TW_Command_Full *full_command_packet;
+       TW_Command *command_packet;
+       TW_Param_Apache *param;
+       unsigned long param_value;
+       void *retval = NULL;
+
+       /* Setup the command packet */
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       memset(full_command_packet, 0, sizeof(TW_Command_Full));
+       command_packet = &full_command_packet->command.oldcommand;
+
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size              = TW_COMMAND_SIZE;
+       command_packet->request_id        = request_id;
+       command_packet->byte6_offset.block_count = 1;
+
+       /* Now setup the param */
+       param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+       memset(param, 0, TW_SECTOR_SIZE);
+       param->table_id = table_id | 0x8000;
+       param->parameter_id = parameter_id;
+       param->parameter_size_bytes = parameter_size_bytes;
+       param_value = tw_dev->generic_buffer_phys[request_id];
+
+       command_packet->byte8_offset.param.sgl[0].address = param_value;
+       command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+
+       /* Post the command packet to the board */
+       twa_post_command_packet(tw_dev, request_id, 1);
+
+       /* Poll for completion */
+       if (twa_poll_response(tw_dev, request_id, 30))
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
+       else
+               retval = (void *)&(param->data[0]);
+
+       tw_dev->posted_request_count--;
+       tw_dev->state[request_id] = TW_S_INITIAL;
+
+       return retval;
+} /* End twa_get_param() */
+
+/* This function will assign an available request id */
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
+{
+       *request_id = tw_dev->free_queue[tw_dev->free_head];
+       tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+       tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End twa_get_request_id() */
+
+/* This function will send an initconnection command to controller */
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+                             u32 set_features, unsigned short current_fw_srl, 
+                             unsigned short current_fw_arch_id, 
+                             unsigned short current_fw_branch, 
+                             unsigned short current_fw_build, 
+                             unsigned short *fw_on_ctlr_srl, 
+                             unsigned short *fw_on_ctlr_arch_id, 
+                             unsigned short *fw_on_ctlr_branch, 
+                             unsigned short *fw_on_ctlr_build, 
+                             u32 *init_connect_result)
+{
+       TW_Command_Full *full_command_packet;
+       TW_Initconnect *tw_initconnect;
+       int request_id = 0, retval = 1;
+
+       /* Initialize InitConnection command packet */
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       memset(full_command_packet, 0, sizeof(TW_Command_Full));
+       full_command_packet->header.header_desc.size_header = 128;
+       
+       tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
+       tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
+       tw_initconnect->request_id = request_id;
+       tw_initconnect->message_credits = message_credits;
+       tw_initconnect->features = set_features;
+#if BITS_PER_LONG > 32
+       /* Turn on 64-bit sgl support */
+       tw_initconnect->features |= 1;
+#endif
+
+       if (set_features & TW_EXTENDED_INIT_CONNECT) {
+               tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
+               tw_initconnect->fw_srl = current_fw_srl;
+               tw_initconnect->fw_arch_id = current_fw_arch_id;
+               tw_initconnect->fw_branch = current_fw_branch;
+               tw_initconnect->fw_build = current_fw_build;
+       } else 
+               tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
+
+       /* Send command packet to the board */
+       twa_post_command_packet(tw_dev, request_id, 1);
+
+       /* Poll for completion */
+       if (twa_poll_response(tw_dev, request_id, 30)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
+       } else {
+               if (set_features & TW_EXTENDED_INIT_CONNECT) {
+                       *fw_on_ctlr_srl = tw_initconnect->fw_srl;
+                       *fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;
+                       *fw_on_ctlr_branch = tw_initconnect->fw_branch;
+                       *fw_on_ctlr_build = tw_initconnect->fw_build;
+                       *init_connect_result = tw_initconnect->result;
+               }
+               retval = 0;
+       }
+
+       tw_dev->posted_request_count--;
+       tw_dev->state[request_id] = TW_S_INITIAL;
+
+       return retval;
+} /* End twa_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+       int i, retval = 1;
+
+       /* Initialize command packet buffers */
+       if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
+               goto out;
+       }
+
+       /* Initialize generic buffer */
+       if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
+               goto out;
+       }
+
+       /* Allocate event info space */
+       tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+       if (!tw_dev->event_queue[0]) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
+               goto out;
+       }
+
+       memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
+
+       for (i = 0; i < TW_Q_LENGTH; i++) {
+               tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
+               tw_dev->free_queue[i] = i;
+               tw_dev->state[i] = TW_S_INITIAL;
+       }
+
+       tw_dev->pending_head = TW_Q_START;
+       tw_dev->pending_tail = TW_Q_START;
+       tw_dev->free_head = TW_Q_START;
+       tw_dev->free_tail = TW_Q_START;
+       tw_dev->error_sequence_id = 1;
+       tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+       init_MUTEX(&tw_dev->ioctl_sem);
+       init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+       retval = 0;
+out:
+       return retval;
+} /* End twa_initialize_device_extension() */
+
+/* This function is the interrupt service routine */
+static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+       int request_id, error = 0;
+       u32 status_reg_value;
+       TW_Response_Queue response_que;
+       TW_Command_Full *full_command_packet;
+       TW_Command *command_packet;
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+       int handled = 0;
+
+       /* Get the per adapter lock */
+       spin_lock(tw_dev->host->host_lock);
+
+       /* See if the interrupt matches this instance */
+       if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
+
+               handled = 1;
+
+               /* Read the registers */
+               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+               /* Check if this is our interrupt, otherwise bail */
+               if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+                       goto twa_interrupt_bail;
+
+               /* Check controller for errors */
+               if (twa_check_bits(status_reg_value)) {
+                       if (twa_decode_bits(tw_dev, status_reg_value)) {
+                               TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                               goto twa_interrupt_bail;
+                       }
+               }
+
+               /* Handle host interrupt */
+               if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+                       TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+               /* Handle attention interrupt */
+               if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+                       TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+                       if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+                               twa_get_request_id(tw_dev, &request_id);
+
+                               error = twa_aen_read_queue(tw_dev, request_id);
+                               if (error) {
+                                       tw_dev->state[request_id] = TW_S_COMPLETED;
+                                       twa_free_request_id(tw_dev, request_id);
+                                       clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+                               }
+                       }
+               }
+
+               /* Handle command interrupt */
+               if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+                       TW_MASK_COMMAND_INTERRUPT(tw_dev);
+                       /* Drain as many pending commands as we can */
+                       while (tw_dev->pending_request_count > 0) {
+                               request_id = tw_dev->pending_queue[tw_dev->pending_head];
+                               if (tw_dev->state[request_id] != TW_S_PENDING) {
+                                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+                                       TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                                       goto twa_interrupt_bail;
+                               }
+                               if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+                                       tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+                                       tw_dev->pending_request_count--;
+                               } else {
+                                       /* If we get here, we will continue re-posting on the next command interrupt */
+                                       break;
+                               }
+                       }
+               }
+
+               /* Handle response interrupt */
+               if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+
+                       /* Drain the response queue from the board */
+                       while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+                               /* Complete the response */
+                               response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+                               request_id = TW_RESID_OUT(response_que.response_id);
+                               full_command_packet = tw_dev->command_packet_virt[request_id];
+                               error = 0;
+                               command_packet = &full_command_packet->command.oldcommand;
+                               /* Check for command packet errors */
+                               if (full_command_packet->command.newcommand.status != 0) {
+                                       if (tw_dev->srb[request_id] != 0) {
+                                               error = twa_fill_sense(tw_dev, request_id, 1, 1);
+                                       } else {
+                                               /* Skip ioctl error prints */
+                                               if (request_id != tw_dev->chrdev_request_id) {
+                                                       error = twa_fill_sense(tw_dev, request_id, 0, 1);
+                                               }
+                                       }
+                               }
+
+                               /* Check for correct state */
+                               if (tw_dev->state[request_id] != TW_S_POSTED) {
+                                       if (tw_dev->srb[request_id] != 0) {
+                                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
+                                               TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                                               goto twa_interrupt_bail;
+                                       }
+                               }
+
+                               /* Check for internal command completion */
+                               if (tw_dev->srb[request_id] == 0) {
+                                       if (request_id != tw_dev->chrdev_request_id) {
+                                               if (twa_aen_complete(tw_dev, request_id))
+                                                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+                                       } else {
+                                               tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+                                               wake_up(&tw_dev->ioctl_wqueue);
+                                       }
+                               } else {
+                                       twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+                                       /* If no error command was a success */
+                                       if (error == 0) {
+                                               tw_dev->srb[request_id]->result = (DID_OK << 16);
+                                       }
+
+                                       /* If error, command failed */
+                                       if (error == 1) {
+                                               /* Ask for a host reset */
+                                               tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                                       }
+
+                                       /* Now complete the io */
+                                       tw_dev->state[request_id] = TW_S_COMPLETED;
+                                       twa_free_request_id(tw_dev, request_id);
+                                       tw_dev->posted_request_count--;
+                                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+                                       twa_unmap_scsi_data(tw_dev, request_id);
+                               }
+
+                               /* Check for valid status after each drain */
+                               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+                               if (twa_check_bits(status_reg_value)) {
+                                       if (twa_decode_bits(tw_dev, status_reg_value)) {
+                                               TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                                               goto twa_interrupt_bail;
+                                       }
+                               }
+                       }
+               }
+       }
+twa_interrupt_bail:
+       spin_unlock(tw_dev->host->host_lock);
+       return IRQ_RETVAL(handled);
+} /* End twa_interrupt() */
+
+/* This function will load the request id and various sgls for ioctls */
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+{
+       TW_Command *oldcommand;
+       TW_Command_Apache *newcommand;
+       TW_SG_Entry *sgl;
+
+       if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+               newcommand = &full_command_packet->command.newcommand;
+               newcommand->request_id = request_id;
+               newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+               newcommand->sg_list[0].length = length;
+       } else {
+               oldcommand = &full_command_packet->command.oldcommand;
+               oldcommand->request_id = request_id;
+
+               if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
+                       /* Load the sg list */
+                       sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+                       sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+                       sgl->length = length;
+               }
+       }
+} /* End twa_load_sgl() */
+
+/* This function will perform a pci-dma mapping for a scatter gather list */
+static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
+{
+       int use_sg;
+       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+       struct pci_dev *pdev = tw_dev->tw_pci_dev;
+       int retval = 0;
+
+       if (cmd->use_sg == 0)
+               goto out;
+
+       use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+       if (use_sg == 0) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
+               goto out;
+       }
+
+       cmd->SCp.phase = TW_PHASE_SGLIST;
+       cmd->SCp.have_data_in = use_sg;
+       retval = use_sg;
+out:
+       return retval;
+} /* End twa_map_scsi_sg_data() */
+
+/* This function will perform a pci-dma map for a single buffer */
+static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
+{
+       dma_addr_t mapping;
+       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+       struct pci_dev *pdev = tw_dev->tw_pci_dev;
+       int retval = 0;
+
+       if (cmd->request_bufflen == 0) {
+               retval = 0;
+               goto out;
+       }
+
+       mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+       if (mapping == 0) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
+               goto out;
+       }
+
+       cmd->SCp.phase = TW_PHASE_SINGLE;
+       cmd->SCp.have_data_in = mapping;
+       retval = mapping;
+out:
+       return retval;
+} /* End twa_map_scsi_single_data() */
+
+/* This function will poll for a response interrupt of a request */
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
+{
+       int retval = 1, found = 0, response_request_id;
+       TW_Response_Queue response_queue;
+       TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
+
+       if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
+               response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+               response_request_id = TW_RESID_OUT(response_queue.response_id);
+               if (request_id != response_request_id) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
+                       goto out;
+               }
+               if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+                       if (full_command_packet->command.newcommand.status != 0) {
+                               /* bad response */
+                               twa_fill_sense(tw_dev, request_id, 0, 0);
+                               goto out;
+                       }
+                       found = 1;
+               } else {
+                       if (full_command_packet->command.oldcommand.status != 0) {
+                               /* bad response */
+                               twa_fill_sense(tw_dev, request_id, 0, 0);
+                               goto out;
+                       }
+                       found = 1;
+               }
+       }
+
+       if (found)
+               retval = 0;
+out:
+       return retval;
+} /* End twa_poll_response() */
+
+/* This function will poll the status register for a flag */
+static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+       u32 status_reg_value; 
+       unsigned long before;
+       int retval = 1;
+
+       status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+       before = jiffies;
+
+       if (twa_check_bits(status_reg_value))
+               twa_decode_bits(tw_dev, status_reg_value);
+
+       while ((status_reg_value & flag) != flag) {
+               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+               if (twa_check_bits(status_reg_value))
+                       twa_decode_bits(tw_dev, status_reg_value);
+
+               if (time_after(jiffies, before + HZ * seconds))
+                       goto out;
+
+               msleep(50);
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_poll_status() */
+
+/* This function will poll the status register for disappearance of a flag */
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+       u32 status_reg_value;
+       unsigned long before;
+       int retval = 1;
+
+       status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+       before = jiffies;
+
+       if (twa_check_bits(status_reg_value))
+               twa_decode_bits(tw_dev, status_reg_value);
+
+       while ((status_reg_value & flag) != 0) {
+               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+               if (twa_check_bits(status_reg_value))
+                       twa_decode_bits(tw_dev, status_reg_value);
+
+               if (time_after(jiffies, before + HZ * seconds))
+                       goto out;
+
+               msleep(50);
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
+{
+       u32 status_reg_value;
+       unsigned long command_que_value;
+       int retval = 1;
+
+       command_que_value = tw_dev->command_packet_phys[request_id];
+       status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+       if (twa_check_bits(status_reg_value))
+               twa_decode_bits(tw_dev, status_reg_value);
+
+       if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
+
+               /* Only pend internal driver commands */
+               if (!internal) {
+                       retval = SCSI_MLQUEUE_HOST_BUSY;
+                       goto out;
+               }
+
+               /* Couldn't post the command packet, so we do it later */
+               if (tw_dev->state[request_id] != TW_S_PENDING) {
+                       tw_dev->state[request_id] = TW_S_PENDING;
+                       tw_dev->pending_request_count++;
+                       if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+                               tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+                       }
+                       tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+                       tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
+               }
+               TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
+               goto out;
+       } else {
+               /* We successfully posted the command packet */
+#if BITS_PER_LONG > 32
+               writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#else
+               writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#endif
+               tw_dev->state[request_id] = TW_S_POSTED;
+               tw_dev->posted_request_count++;
+               if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+                       tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+               }
+       }
+       retval = 0;
+out:
+       return retval;
+} /* End twa_post_command_packet() */
+
+/* This function will reset a device extension */
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
+{
+       int i = 0;
+       int retval = 1;
+
+       /* Abort all requests that are in progress */
+       for (i = 0; i < TW_Q_LENGTH; i++) {
+               if ((tw_dev->state[i] != TW_S_FINISHED) &&
+                   (tw_dev->state[i] != TW_S_INITIAL) &&
+                   (tw_dev->state[i] != TW_S_COMPLETED)) {
+                       if (tw_dev->srb[i]) {
+                               tw_dev->srb[i]->result = (DID_RESET << 16);
+                               tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+                               twa_unmap_scsi_data(tw_dev, i);
+                       }
+               }
+       }
+
+       /* Reset queues and counts */
+       for (i = 0; i < TW_Q_LENGTH; i++) {
+               tw_dev->free_queue[i] = i;
+               tw_dev->state[i] = TW_S_INITIAL;
+       }
+       tw_dev->free_head = TW_Q_START;
+       tw_dev->free_tail = TW_Q_START;
+       tw_dev->posted_request_count = 0;
+       tw_dev->pending_request_count = 0;
+       tw_dev->pending_head = TW_Q_START;
+       tw_dev->pending_tail = TW_Q_START;
+       tw_dev->reset_print = 0;
+       tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+       tw_dev->flags = 0;
+
+       TW_DISABLE_INTERRUPTS(tw_dev);
+
+       if (twa_reset_sequence(tw_dev, 1))
+               goto out;
+
+        TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+       retval = 0;
+out:
+       return retval;
+} /* End twa_reset_device_extension() */
+
+/* This function will reset a controller */
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
+{
+       int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
+
+       while (tries < TW_MAX_RESET_TRIES) {
+               if (do_soft_reset)
+                       TW_SOFT_RESET(tw_dev);
+
+               /* Make sure controller is in a good state */
+               if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
+                       do_soft_reset = 1;
+                       tries++;
+                       continue;
+               }
+
+               /* Empty response queue */
+               if (twa_empty_response_queue(tw_dev)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
+                       do_soft_reset = 1;
+                       tries++;
+                       continue;
+               }
+
+               flashed = 0;
+
+               /* Check for compatibility/flash */
+               if (twa_check_srl(tw_dev, &flashed)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
+                       do_soft_reset = 1;
+                       tries++;
+                       continue;
+               } else {
+                       if (flashed) {
+                               tries++;
+                               continue;
+                       }
+               }
+
+               /* Drain the AEN queue */
+               if (twa_aen_drain_queue(tw_dev, soft_reset)) {
+                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
+                       do_soft_reset = 1;
+                       tries++;
+                       continue;
+               }
+
+               /* If we got here, controller is in a good state */
+               retval = 0;
+               goto out;
+       }
+out:
+       return retval;
+} /* End twa_reset_sequence() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
+{
+       int heads, sectors, cylinders;
+       TW_Device_Extension *tw_dev;
+
+       tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+       if (capacity >= 0x200000) {
+               heads = 255;
+               sectors = 63;
+               cylinders = sector_div(capacity, heads * sectors);
+       } else {
+               heads = 64;
+               sectors = 32;
+               cylinders = sector_div(capacity, heads * sectors);
+       }
+
+       geom[0] = heads;
+       geom[1] = sectors;
+       geom[2] = cylinders;
+
+       return 0;
+} /* End twa_scsi_biosparam() */
+
+/* This is the new scsi eh abort function */
+static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt)
+{
+       int i;
+       TW_Device_Extension *tw_dev = NULL;
+       int retval = FAILED;
+
+       tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+       spin_unlock_irq(tw_dev->host->host_lock);
+
+       tw_dev->num_aborts++;
+
+       /* If we find any IO's in process, we have to reset the card */
+       for (i = 0; i < TW_Q_LENGTH; i++) {
+               if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) {
+                       printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n",
+                              tw_dev->host->host_no, TW_DRIVER, 0x2c,
+                              SCpnt->device->id, SCpnt->cmnd[0]);
+                       if (twa_reset_device_extension(tw_dev)) {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort");
+                               goto out;
+                       }
+                       break;
+               }
+       }
+       retval = SUCCESS;
+out:
+       spin_lock_irq(tw_dev->host->host_lock);
+       return retval;
+} /* End twa_scsi_eh_abort() */
+
+/* This is the new scsi eh reset function */
+static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
+{
+       TW_Device_Extension *tw_dev = NULL;
+       int retval = FAILED;
+
+       tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+       spin_unlock_irq(tw_dev->host->host_lock);
+
+       tw_dev->num_resets++;
+
+       printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no);
+
+       /* Now reset the card and some of the device extension data */
+       if (twa_reset_device_extension(tw_dev)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
+               goto out;
+       }
+       printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no);
+       retval = SUCCESS;
+out:
+       spin_lock_irq(tw_dev->host->host_lock);
+       return retval;
+} /* End twa_scsi_eh_reset() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+       int request_id, retval;
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+       /* Save done function into scsi_cmnd struct */
+       SCpnt->scsi_done = done;
+               
+       /* Get a free request id */
+       twa_get_request_id(tw_dev, &request_id);
+
+       /* Save the scsi command for use by the ISR */
+       tw_dev->srb[request_id] = SCpnt;
+
+       /* Initialize phase to zero */
+       SCpnt->SCp.phase = TW_PHASE_INITIAL;
+
+       retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
+       switch (retval) {
+       case SCSI_MLQUEUE_HOST_BUSY:
+               twa_free_request_id(tw_dev, request_id);
+               break;
+       case 1:
+               tw_dev->state[request_id] = TW_S_COMPLETED;
+               twa_free_request_id(tw_dev, request_id);
+               SCpnt->result = (DID_ERROR << 16);
+               done(SCpnt);
+       }
+
+       return retval;
+} /* End twa_scsi_queue() */
+
+/* This function hands scsi cdb's to the firmware */
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg)
+{
+       TW_Command_Full *full_command_packet;
+       TW_Command_Apache *command_packet;
+       u32 num_sectors = 0x0;
+       int i, sg_count;
+       struct scsi_cmnd *srb = NULL;
+       struct scatterlist *sglist = NULL;
+       u32 buffaddr = 0x0;
+       int retval = 1;
+
+       if (tw_dev->srb[request_id]) {
+               if (tw_dev->srb[request_id]->request_buffer) {
+                       sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+               }
+               srb = tw_dev->srb[request_id];
+       }
+
+       /* Initialize command packet */
+       full_command_packet = tw_dev->command_packet_virt[request_id];
+       full_command_packet->header.header_desc.size_header = 128;
+       full_command_packet->header.status_block.error = 0;
+       full_command_packet->header.status_block.severity__reserved = 0;
+
+       command_packet = &full_command_packet->command.newcommand;
+       command_packet->status = 0;
+       command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
+
+       /* We forced 16 byte cdb use earlier */
+       if (!cdb)
+               memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
+       else
+               memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
+
+       if (srb)
+               command_packet->unit = srb->device->id;
+       else
+               command_packet->unit = 0;
+
+       command_packet->request_id = request_id;
+       command_packet->sgl_offset = 16;
+
+       if (!sglistarg) {
+               /* Map sglist from scsi layer to cmd packet */
+               if (tw_dev->srb[request_id]->use_sg == 0) {
+                       if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
+                               command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+                               command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+                       } else {
+                               buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
+                               if (buffaddr == 0)
+                                       goto out;
+
+                               command_packet->sg_list[0].address = buffaddr;
+                               command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
+                       }
+                       command_packet->sgl_entries = 1;
+
+                       if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
+                               goto out;
+                       }
+               }
+
+               if (tw_dev->srb[request_id]->use_sg > 0) {
+                       sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+                       if (sg_count == 0)
+                               goto out;
+
+                       for (i = 0; i < sg_count; i++) {
+                               command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+                               command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+                               if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+                                       TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+                                       goto out;
+                               }
+                       }
+                       command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg;
+               }
+       } else {
+               /* Internal cdb post */
+               for (i = 0; i < use_sg; i++) {
+                       command_packet->sg_list[i].address = sglistarg[i].address;
+                       command_packet->sg_list[i].length = sglistarg[i].length;
+                       if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
+                               goto out;
+                       }
+               }
+               command_packet->sgl_entries = use_sg;
+       }
+
+       if (srb) {
+               if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
+                       num_sectors = (u32)srb->cmnd[4];
+
+               if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
+                       num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+       }
+
+       /* Update sector statistic */
+       tw_dev->sector_count = num_sectors;
+       if (tw_dev->sector_count > tw_dev->max_sector_count)
+               tw_dev->max_sector_count = tw_dev->sector_count;
+
+       /* Update SG statistics */
+       if (srb) {
+               tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+               if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+                       tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+       }
+
+       /* Now post the command to the board */
+       if (srb) {
+               retval = twa_post_command_packet(tw_dev, request_id, 0);
+       } else {
+               twa_post_command_packet(tw_dev, request_id, 1);
+               retval = 0;
+       }
+out:
+       return retval;
+} /* End twa_scsiop_execute_scsi() */
+
+/* This function completes an execute scsi operation */
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+       /* Copy the response if too small */
+       if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+               memcpy(tw_dev->srb[request_id]->request_buffer,
+                      tw_dev->generic_buffer_virt[request_id],
+                      tw_dev->srb[request_id]->request_bufflen);
+       }
+} /* End twa_scsiop_execute_scsi_complete() */
+
+/* This function tells the controller to shut down */
+static void __twa_shutdown(TW_Device_Extension *tw_dev)
+{
+       /* Disable interrupts */
+       TW_DISABLE_INTERRUPTS(tw_dev);
+
+       printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
+
+       /* Tell the card we are shutting down */
+       if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
+       } else {
+               printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
+       }
+
+       /* Clear all interrupts just before exit */
+       TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+} /* End __twa_shutdown() */
+
+/* Wrapper for __twa_shutdown */
+static void twa_shutdown(struct device *dev)
+{
+       struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+       __twa_shutdown(tw_dev);
+} /* End twa_shutdown() */
+
+/* This function will look up a string */
+static char *twa_string_lookup(twa_message_type *table, unsigned int code)
+{
+       int index;
+
+       for (index = 0; ((code != table[index].code) &&
+                     (table[index].text != (char *)0)); index++);
+       return(table[index].text);
+} /* End twa_string_lookup() */
+
+/* This function will perform a pci-dma unmap */
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
+{
+       struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+       struct pci_dev *pdev = tw_dev->tw_pci_dev;
+
+       switch(cmd->SCp.phase) {
+       case TW_PHASE_SINGLE:
+               pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+               break;
+       case TW_PHASE_SGLIST:
+               pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+               break;
+       }
+} /* End twa_unmap_scsi_data() */
+
+/* scsi_host_template initializer */
+static struct scsi_host_template driver_template = {
+       .module                 = THIS_MODULE,
+       .name                   = "3ware 9000 Storage Controller",
+       .queuecommand           = twa_scsi_queue,
+       .eh_abort_handler       = twa_scsi_eh_abort,
+       .eh_host_reset_handler  = twa_scsi_eh_reset,
+       .bios_param             = twa_scsi_biosparam,
+       .can_queue              = TW_Q_LENGTH-2,
+       .this_id                = -1,
+       .sg_tablesize           = TW_APACHE_MAX_SGL_LENGTH,
+       .max_sectors            = TW_MAX_SECTORS,
+       .cmd_per_lun            = TW_MAX_CMDS_PER_LUN,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .shost_attrs            = twa_host_attrs,
+       .sdev_attrs             = twa_dev_attrs,
+       .emulated               = 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+       struct Scsi_Host *host = NULL;
+       TW_Device_Extension *tw_dev;
+       u32 mem_addr;
+       int retval = -ENODEV;
+
+       retval = pci_enable_device(pdev);
+       if (retval) {
+               TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
+               goto out_disable_device;
+       }
+
+       pci_set_master(pdev);
+
+       retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+       if (retval) {
+               TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+               goto out_disable_device;
+       }
+
+       host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+       if (!host) {
+               TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
+               retval = -ENOMEM;
+               goto out_disable_device;
+       }
+       tw_dev = (TW_Device_Extension *)host->hostdata;
+
+       memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+       /* Save values to device extension */
+       tw_dev->host = host;
+       tw_dev->tw_pci_dev = pdev;
+
+       if (twa_initialize_device_extension(tw_dev)) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
+               goto out_free_device_extension;
+       }
+
+       /* Request IO regions */
+       retval = pci_request_regions(pdev, "3w-9xxx");
+       if (retval) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
+               goto out_free_device_extension;
+       }
+
+       mem_addr = pci_resource_start(pdev, 1);
+
+       /* Save base address */
+       tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+       if (!tw_dev->base_addr) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
+               goto out_release_mem_region;
+       }
+
+       /* Disable interrupts on the card */
+       TW_DISABLE_INTERRUPTS(tw_dev);
+
+       /* Initialize the card */
+       if (twa_reset_sequence(tw_dev, 0))
+               goto out_release_mem_region;
+
+       /* Set host specific parameters */
+       host->max_id = TW_MAX_UNITS;
+       host->max_cmd_len = TW_MAX_CDB_LEN;
+
+       /* Luns and channels aren't supported by adapter */
+       host->max_lun = 0;
+       host->max_channel = 0;
+
+       /* Register the card with the kernel SCSI layer */
+       retval = scsi_add_host(host, &pdev->dev);
+       if (retval) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
+               goto out_release_mem_region;
+       }
+
+       pci_set_drvdata(pdev, host);
+
+       printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
+              host->host_no, mem_addr, pdev->irq);
+       printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
+              host->host_no,
+              (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
+                                    TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
+              (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
+                                    TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
+              *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
+                                    TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH));
+
+       /* Now setup the interrupt handler */
+       retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev);
+       if (retval) {
+               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
+               goto out_remove_host;
+       }
+
+       twa_device_extension_list[twa_device_extension_count] = tw_dev;
+       twa_device_extension_count++;
+
+       /* Re-enable interrupts on the card */
+       TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+       /* Finally, scan the host */
+       scsi_scan_host(host);
+
+       if (twa_major == -1) {
+               if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
+                       TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
+       }
+       return 0;
+
+out_remove_host:
+       scsi_remove_host(host);
+out_release_mem_region:
+       pci_release_regions(pdev);
+out_free_device_extension:
+       twa_free_device_extension(tw_dev);
+       scsi_host_put(host);
+out_disable_device:
+       pci_disable_device(pdev);
+
+       return retval;
+} /* End twa_probe() */
+
+/* This function is called to remove a device */
+static void twa_remove(struct pci_dev *pdev)
+{
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+       scsi_remove_host(tw_dev->host);
+
+       __twa_shutdown(tw_dev);
+
+       /* Free up the IRQ */
+       free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+       /* Free up the mem region */
+       pci_release_regions(pdev);
+
+       /* Free up device extension resources */
+       twa_free_device_extension(tw_dev);
+
+       /* Unregister character device */
+       if (twa_major >= 0) {
+               unregister_chrdev(twa_major, "twa");
+               twa_major = -1;
+       }
+
+       scsi_host_put(tw_dev->host);
+       pci_disable_device(pdev);
+       twa_device_extension_count--;
+} /* End twa_remove() */
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id twa_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { }
+};
+MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver twa_driver = {
+       .name           = "3w-9xxx",
+       .id_table       = twa_pci_tbl,
+       .probe          = twa_probe,
+       .remove         = twa_remove,
+       .driver         = {
+               .shutdown = twa_shutdown
+       }
+};
+
+/* This function is called on driver initialization */
+static int __init twa_init(void)
+{
+       printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version);
+
+       return pci_module_init(&twa_driver);
+} /* End twa_init() */
+
+/* This function is called on driver exit */
+static void __exit twa_exit(void)
+{
+       pci_unregister_driver(&twa_driver);
+} /* End twa_exit() */
+
+module_init(twa_init);
+module_exit(twa_exit);
+
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
new file mode 100644 (file)
index 0000000..29248d6
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ *  sata_nv.c - NVIDIA nForce SATA
+ *
+ *  Copyright 2004 NVIDIA Corp.  All rights reserved.
+ *  Copyright 2004 Andrew Chew
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ *  0.02
+ *     - Added support for CK804 SATA controller.
+ *
+ *  0.01
+ *     - Initial revision.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME                       "sata_nv"
+#define DRV_VERSION                    "0.02"
+
+#define NV_PORTS                       2
+#define NV_PIO_MASK                    0x1f
+#define NV_UDMA_MASK                   0x7f
+#define NV_PORT0_BMDMA_REG_OFFSET      0x00
+#define NV_PORT1_BMDMA_REG_OFFSET      0x08
+#define NV_PORT0_SCR_REG_OFFSET                0x00
+#define NV_PORT1_SCR_REG_OFFSET                0x40
+
+#define NV_INT_STATUS                  0x10
+#define NV_INT_STATUS_CK804            0x440
+#define NV_INT_STATUS_PDEV_INT         0x01
+#define NV_INT_STATUS_PDEV_PM          0x02
+#define NV_INT_STATUS_PDEV_ADDED       0x04
+#define NV_INT_STATUS_PDEV_REMOVED     0x08
+#define NV_INT_STATUS_SDEV_INT         0x10
+#define NV_INT_STATUS_SDEV_PM          0x20
+#define NV_INT_STATUS_SDEV_ADDED       0x40
+#define NV_INT_STATUS_SDEV_REMOVED     0x80
+#define NV_INT_STATUS_PDEV_HOTPLUG     (NV_INT_STATUS_PDEV_ADDED | \
+                                       NV_INT_STATUS_PDEV_REMOVED)
+#define NV_INT_STATUS_SDEV_HOTPLUG     (NV_INT_STATUS_SDEV_ADDED | \
+                                       NV_INT_STATUS_SDEV_REMOVED)
+#define NV_INT_STATUS_HOTPLUG          (NV_INT_STATUS_PDEV_HOTPLUG | \
+                                       NV_INT_STATUS_SDEV_HOTPLUG)
+
+#define NV_INT_ENABLE                  0x11
+#define NV_INT_ENABLE_CK804            0x441
+#define NV_INT_ENABLE_PDEV_MASK                0x01
+#define NV_INT_ENABLE_PDEV_PM          0x02
+#define NV_INT_ENABLE_PDEV_ADDED       0x04
+#define NV_INT_ENABLE_PDEV_REMOVED     0x08
+#define NV_INT_ENABLE_SDEV_MASK                0x10
+#define NV_INT_ENABLE_SDEV_PM          0x20
+#define NV_INT_ENABLE_SDEV_ADDED       0x40
+#define NV_INT_ENABLE_SDEV_REMOVED     0x80
+#define NV_INT_ENABLE_PDEV_HOTPLUG     (NV_INT_ENABLE_PDEV_ADDED | \
+                                       NV_INT_ENABLE_PDEV_REMOVED)
+#define NV_INT_ENABLE_SDEV_HOTPLUG     (NV_INT_ENABLE_SDEV_ADDED | \
+                                       NV_INT_ENABLE_SDEV_REMOVED)
+#define NV_INT_ENABLE_HOTPLUG          (NV_INT_ENABLE_PDEV_HOTPLUG | \
+                                       NV_INT_ENABLE_SDEV_HOTPLUG)
+
+#define NV_INT_CONFIG                  0x12
+#define NV_INT_CONFIG_METHD            0x01 // 0 = INT, 1 = SMI
+
+// For PCI config register 20
+#define NV_MCP_SATA_CFG_20             0x50
+#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN       0x04
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void nv_host_stop (struct ata_host_set *host_set);
+static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
+static void nv_disable_hotplug(struct ata_host_set *host_set);
+static void nv_check_hotplug(struct ata_host_set *host_set);
+static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
+static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
+static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+
+enum nv_host_type
+{
+       NFORCE2,
+       NFORCE3,
+       CK804
+};
+
+static struct pci_device_id nv_pci_tbl[] = {
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { 0, } /* terminate list */
+};
+
+#define NV_HOST_FLAGS_SCR_MMIO 0x00000001
+
+struct nv_host_desc
+{
+       enum nv_host_type       host_type;
+       unsigned long           host_flags;
+       void                    (*enable_hotplug)(struct ata_probe_ent *probe_ent);
+       void                    (*disable_hotplug)(struct ata_host_set *host_set);
+       void                    (*check_hotplug)(struct ata_host_set *host_set);
+
+};
+static struct nv_host_desc nv_device_tbl[] = {
+       {
+               .host_type      = NFORCE2,
+               .host_flags     = 0x00000000,
+               .enable_hotplug = nv_enable_hotplug,
+               .disable_hotplug= nv_disable_hotplug,
+               .check_hotplug  = nv_check_hotplug,
+       },
+       {
+               .host_type      = NFORCE3,
+               .host_flags     = 0x00000000,
+               .enable_hotplug = nv_enable_hotplug,
+               .disable_hotplug= nv_disable_hotplug,
+               .check_hotplug  = nv_check_hotplug,
+       },
+       {       .host_type      = CK804,
+               .host_flags     = NV_HOST_FLAGS_SCR_MMIO,
+               .enable_hotplug = nv_enable_hotplug_ck804,
+               .disable_hotplug= nv_disable_hotplug_ck804,
+               .check_hotplug  = nv_check_hotplug_ck804,
+       },
+};
+
+struct nv_host
+{
+       struct nv_host_desc     *host_desc;
+};
+
+static struct pci_driver nv_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = nv_pci_tbl,
+       .probe                  = nv_init_one,
+       .remove                 = ata_pci_remove_one,
+};
+
+static Scsi_Host_Template nv_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .queuecommand           = ata_scsi_queuecmd,
+       .eh_strategy_handler    = ata_scsi_error,
+       .can_queue              = ATA_DEF_QUEUE,
+       .this_id                = ATA_SHT_THIS_ID,
+       .sg_tablesize           = ATA_MAX_PRD,
+       .max_sectors            = ATA_MAX_SECTORS,
+       .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
+       .emulated               = ATA_SHT_EMULATED,
+       .use_clustering         = ATA_SHT_USE_CLUSTERING,
+       .proc_name              = DRV_NAME,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .slave_configure        = ata_scsi_slave_config,
+       .bios_param             = ata_std_bios_param,
+};
+
+static struct ata_port_operations nv_ops = {
+       .port_disable           = ata_port_disable,
+       .tf_load                = ata_tf_load_pio,
+       .tf_read                = ata_tf_read_pio,
+       .exec_command           = ata_exec_command_pio,
+       .check_status           = ata_check_status_pio,
+       .phy_reset              = sata_phy_reset,
+       .bmdma_setup            = ata_bmdma_setup_pio,
+       .bmdma_start            = ata_bmdma_start_pio,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+       .irq_handler            = nv_interrupt,
+       .irq_clear              = ata_bmdma_irq_clear,
+       .scr_read               = nv_scr_read,
+       .scr_write              = nv_scr_write,
+       .port_start             = ata_port_start,
+       .port_stop              = ata_port_stop,
+       .host_stop              = nv_host_stop,
+};
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+
+irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+       struct ata_host_set *host_set = dev_instance;
+       struct nv_host *host = host_set->private_data;
+       unsigned int i;
+       unsigned int handled = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host_set->lock, flags);
+
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap;
+
+               ap = host_set->ports[i];
+               if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+                       struct ata_queued_cmd *qc;
+
+                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+                               handled += ata_host_intr(ap, qc);
+               }
+
+       }
+
+       if (host->host_desc->check_hotplug)
+               host->host_desc->check_hotplug(host_set);
+
+       spin_unlock_irqrestore(&host_set->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+       struct ata_host_set *host_set = ap->host_set;
+       struct nv_host *host = host_set->private_data;
+
+       if (sc_reg > SCR_CONTROL)
+               return 0xffffffffU;
+
+       if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+               return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       else
+               return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+       struct ata_host_set *host_set = ap->host_set;
+       struct nv_host *host = host_set->private_data;
+
+       if (sc_reg > SCR_CONTROL)
+               return;
+
+       if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+               writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       else
+               outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_host_stop (struct ata_host_set *host_set)
+{
+       struct nv_host *host = host_set->private_data;
+
+       // Disable hotplug event interrupts.
+       if (host->host_desc->disable_hotplug)
+               host->host_desc->disable_hotplug(host_set);
+
+       kfree(host);
+}
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int printed_version = 0;
+       struct nv_host *host;
+       struct ata_probe_ent *probe_ent = NULL;
+       int rc;
+
+       if (!printed_version++)
+               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc)
+               goto err_out;
+
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               goto err_out_regions;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               goto err_out_regions;
+
+       probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+       if (!probe_ent) {
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       host = kmalloc(sizeof(struct nv_host), GFP_KERNEL);
+       if (!host) {
+               rc = -ENOMEM;
+               goto err_out_free_ent;
+       }
+
+       host->host_desc = &nv_device_tbl[ent->driver_data];
+
+       memset(probe_ent, 0, sizeof(*probe_ent));
+       INIT_LIST_HEAD(&probe_ent->node);
+
+       probe_ent->pdev = pdev;
+       probe_ent->sht = &nv_sht;
+       probe_ent->host_flags = ATA_FLAG_SATA |
+                               ATA_FLAG_SATA_RESET |
+                               ATA_FLAG_SRST |
+                               ATA_FLAG_NO_LEGACY;
+
+       probe_ent->port_ops = &nv_ops;
+       probe_ent->n_ports = NV_PORTS;
+       probe_ent->irq = pdev->irq;
+       probe_ent->irq_flags = SA_SHIRQ;
+       probe_ent->pio_mask = NV_PIO_MASK;
+       probe_ent->udma_mask = NV_UDMA_MASK;
+
+       probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+       ata_std_ports(&probe_ent->port[0]);
+       probe_ent->port[0].altstatus_addr =
+       probe_ent->port[0].ctl_addr =
+               pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+       probe_ent->port[0].bmdma_addr =
+               pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET;
+
+       probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+       ata_std_ports(&probe_ent->port[1]);
+       probe_ent->port[1].altstatus_addr =
+       probe_ent->port[1].ctl_addr =
+               pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+       probe_ent->port[1].bmdma_addr =
+               pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET;
+
+       probe_ent->private_data = host;
+
+       if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
+               unsigned long base;
+
+               probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
+                               pci_resource_len(pdev, 5));
+               if (probe_ent->mmio_base == NULL)
+                       goto err_out_free_ent;
+
+               base = (unsigned long)probe_ent->mmio_base;
+
+               probe_ent->port[0].scr_addr =
+                       base + NV_PORT0_SCR_REG_OFFSET;
+               probe_ent->port[1].scr_addr =
+                       base + NV_PORT1_SCR_REG_OFFSET;
+       } else {
+
+               probe_ent->port[0].scr_addr =
+                       pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET;
+               probe_ent->port[1].scr_addr =
+                       pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET;
+       }
+
+       pci_set_master(pdev);
+
+       // Enable hotplug event interrupts.
+       if (host->host_desc->enable_hotplug)
+               host->host_desc->enable_hotplug(probe_ent);
+
+       rc = ata_device_add(probe_ent);
+       if (rc != NV_PORTS)
+               goto err_out_free_ent;
+
+       kfree(probe_ent);
+
+       return 0;
+
+err_out_free_ent:
+       kfree(probe_ent);
+
+err_out_regions:
+       pci_release_regions(pdev);
+
+err_out:
+       pci_disable_device(pdev);
+       return rc;
+}
+
+static void nv_enable_hotplug(struct ata_probe_ent *probe_ent)
+{
+       u8 intr_mask;
+
+       outb(NV_INT_STATUS_HOTPLUG,
+               (unsigned long)probe_ent->mmio_base + NV_INT_STATUS);
+
+       intr_mask = inb((unsigned long)probe_ent->mmio_base + NV_INT_ENABLE);
+       intr_mask |= NV_INT_ENABLE_HOTPLUG;
+
+       outb(intr_mask, (unsigned long)probe_ent->mmio_base + NV_INT_ENABLE);
+}
+
+static void nv_disable_hotplug(struct ata_host_set *host_set)
+{
+       u8 intr_mask;
+
+       intr_mask = inb((unsigned long)host_set->mmio_base + NV_INT_ENABLE);
+
+       intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
+
+       outb(intr_mask, (unsigned long)host_set->mmio_base + NV_INT_ENABLE);
+}
+
+static void nv_check_hotplug(struct ata_host_set *host_set)
+{
+       u8 intr_status;
+
+       intr_status = inb((unsigned long)host_set->mmio_base + NV_INT_STATUS);
+
+       // Clear interrupt status.
+       outb(0xff, (unsigned long)host_set->mmio_base + NV_INT_STATUS);
+
+       if (intr_status & NV_INT_STATUS_HOTPLUG) {
+               if (intr_status & NV_INT_STATUS_PDEV_ADDED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Primary device added\n");
+
+               if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Primary device removed\n");
+
+               if (intr_status & NV_INT_STATUS_SDEV_ADDED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Secondary device added\n");
+
+               if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Secondary device removed\n");
+       }
+}
+
+static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
+{
+       u8 intr_mask;
+       u8 regval;
+
+       pci_read_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, &regval);
+       regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+       pci_write_config_byte(probe_ent->pdev, NV_MCP_SATA_CFG_20, regval);
+
+       writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804);
+
+       intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_CK804);
+       intr_mask |= NV_INT_ENABLE_HOTPLUG;
+
+       writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
+{
+       u8 intr_mask;
+       u8 regval;
+
+       intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804);
+
+       intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
+
+       writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804);
+
+       pci_read_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, &regval);
+       regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+       pci_write_config_byte(host_set->pdev, NV_MCP_SATA_CFG_20, regval);
+}
+
+static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+{
+       u8 intr_status;
+
+       intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
+
+       // Clear interrupt status.
+       writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804);
+
+       if (intr_status & NV_INT_STATUS_HOTPLUG) {
+               if (intr_status & NV_INT_STATUS_PDEV_ADDED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Primary device added\n");
+
+               if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Primary device removed\n");
+
+               if (intr_status & NV_INT_STATUS_SDEV_ADDED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Secondary device added\n");
+
+               if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
+                       printk(KERN_WARNING "nv_sata: "
+                               "Secondary device removed\n");
+       }
+}
+
+static int __init nv_init(void)
+{
+       return pci_module_init(&nv_pci_driver);
+}
+
+static void __exit nv_exit(void)
+{
+       pci_unregister_driver(&nv_pci_driver);
+}
+
+module_init(nv_init);
+module_exit(nv_exit);
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
new file mode 100644 (file)
index 0000000..34f4c67
--- /dev/null
@@ -0,0 +1,1156 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; core driver
+ *
+ *  Based on arch/ppc/cpm2_io/uart.c by Dan Malek
+ *  Based on ppc8xx.c by Thomas Gleixner
+ *  Based on drivers/serial/amba.c by Russell King
+ *
+ *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ * 
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *
+ * This program is free software; 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+
+#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+/***********************************************************************/
+
+/* Track which ports are configured as uarts */
+int cpm_uart_port_map[UART_NR];
+/* How many ports did we config as uarts */
+int cpm_uart_nr;
+
+/**************************************************************/
+
+static int  cpm_uart_tx_pump(struct uart_port *port);
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo);
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo);
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
+
+/**************************************************************/
+
+/*
+ * Check, if transmit buffers are processed            
+*/
+static unsigned int cpm_uart_tx_empty(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile cbd_t *bdp = pinfo->tx_bd_base;
+       int ret = 0;
+
+       while (1) {
+               if (bdp->cbd_sc & BD_SC_READY)
+                       break;
+
+               if (bdp->cbd_sc & BD_SC_WRAP) {
+                       ret = TIOCSER_TEMT;
+                       break;
+               }
+               bdp++;
+       }
+
+       pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret);
+
+       return ret;
+}
+
+static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* Whee. Do nothing. */
+}
+
+static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
+{
+       /* Whee. Do nothing. */
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/*
+ * Stop transmitter
+ */
+static void cpm_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile smc_t *smcp = pinfo->smcp;
+       volatile scc_t *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop tx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               smcp->smc_smcm &= ~SMCM_TX;
+       else
+               sccp->scc_sccm &= ~UART_SCCM_TX;
+}
+
+/*
+ * Start transmitter
+ */
+static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile smc_t *smcp = pinfo->smcp;
+       volatile scc_t *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:start tx\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               if (smcp->smc_smcm & SMCM_TX)
+                       return;
+       } else {
+               if (sccp->scc_sccm & UART_SCCM_TX)
+                       return;
+       }
+
+       if (cpm_uart_tx_pump(port) != 0) {
+               if (IS_SMC(pinfo))
+                       smcp->smc_smcm |= SMCM_TX;
+               else
+                       sccp->scc_sccm |= UART_SCCM_TX;
+       }
+}
+
+/*
+ * Stop receiver 
+ */
+static void cpm_uart_stop_rx(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile smc_t *smcp = pinfo->smcp;
+       volatile scc_t *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:stop rx\n", port->line);
+
+       if (IS_SMC(pinfo))
+               smcp->smc_smcm &= ~SMCM_RX;
+       else
+               sccp->scc_sccm &= ~UART_SCCM_RX;
+}
+
+/*
+ * Enable Modem status interrupts
+ */
+static void cpm_uart_enable_ms(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:enable ms\n", port->line);
+}
+
+/*
+ * Generate a break. 
+ */
+static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       int line = pinfo - cpm_uart_ports;
+
+       pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
+               break_state);
+
+       if (break_state)
+               cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+       else
+               cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs)
+{
+       pr_debug("CPM uart[%d]:TX INT\n", port->line);
+
+       cpm_uart_tx_pump(port);
+}
+
+/*
+ * Receive characters
+ */
+static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
+{
+       int i;
+       unsigned char ch, *cp;
+       struct tty_struct *tty = port->info->tty;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile cbd_t *bdp;
+       u16 status;
+       unsigned int flg;
+
+       pr_debug("CPM uart[%d]:RX INT\n", port->line);
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = pinfo->rx_cur;
+       for (;;) {
+               /* get status */
+               status = bdp->cbd_sc;
+               /* If this one is empty, return happy */
+               if (status & BD_SC_EMPTY)
+                       break;
+
+               /* get number of characters, and check spce in flip-buffer */
+               i = bdp->cbd_datlen;
+
+               /* If we have not enough room in tty flip buffer, then we try 
+                * later, which will be the next rx-interrupt or a timeout
+                */
+               if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
+                       tty->flip.work.func((void *)tty);
+                       if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
+                               printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+                               return;
+                       }
+               }
+
+               /* get pointer */
+               cp = (unsigned char *)bus_to_virt(bdp->cbd_bufaddr);
+
+               /* loop through the buffer */
+               while (i-- > 0) {
+                       ch = *cp++;
+                       port->icount.rx++;
+                       flg = TTY_NORMAL;
+
+                       if (status &
+                           (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
+                               goto handle_error;
+                       if (uart_handle_sysrq_char(port, ch, regs))
+                               continue;
+
+                     error_return:
+                       *tty->flip.char_buf_ptr++ = ch;
+                       *tty->flip.flag_buf_ptr++ = flg;
+                       tty->flip.count++;
+
+               }               /* End while (i--) */
+
+               /* This BD is ready to be used again. Clear status. get next */
+               bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+               bdp->cbd_sc |= BD_SC_EMPTY;
+
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = pinfo->rx_bd_base;
+               else
+                       bdp++;
+       } /* End for (;;) */
+
+       /* Write back buffer pointer */
+       pinfo->rx_cur = (volatile cbd_t *) bdp;
+
+       /* activate BH processing */
+       tty_flip_buffer_push(tty);
+
+       return;
+
+       /* Error processing */
+
+      handle_error:
+       /* Statistics */
+       if (status & BD_SC_BR)
+               port->icount.brk++;
+       if (status & BD_SC_PR)
+               port->icount.parity++;
+       if (status & BD_SC_FR)
+               port->icount.frame++;
+       if (status & BD_SC_OV)
+               port->icount.overrun++;
+
+       /* Mask out ignored conditions */
+       status &= port->read_status_mask;
+
+       /* Handle the remaining ones */
+       if (status & BD_SC_BR)
+               flg = TTY_BREAK;
+       else if (status & BD_SC_PR)
+               flg = TTY_PARITY;
+       else if (status & BD_SC_FR)
+               flg = TTY_FRAME;
+
+       /* overrun does not affect the current character ! */
+       if (status & BD_SC_OV) {
+               ch = 0;
+               flg = TTY_OVERRUN;
+               /* We skip this buffer */
+               /* CHECK: Is really nothing senseful there */
+               /* ASSUMPTION: it contains nothing valid */
+               i = 0;
+       }
+#ifdef SUPPORT_SYSRQ
+       port->sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/*
+ * Asynchron mode interrupt handler
+ */
+static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs)
+{
+       u8 events;
+       struct uart_port *port = (struct uart_port *)data;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile smc_t *smcp = pinfo->smcp;
+       volatile scc_t *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:IRQ\n", port->line);
+
+       if (IS_SMC(pinfo)) {
+               events = smcp->smc_smce;
+               if (events & SMCM_BRKE)
+                       uart_handle_break(port);
+               if (events & SMCM_RX)
+                       cpm_uart_int_rx(port, regs);
+               if (events & SMCM_TX)
+                       cpm_uart_int_tx(port, regs);
+               smcp->smc_smce = events;
+       } else {
+               events = sccp->scc_scce;
+               if (events & UART_SCCM_BRKE)
+                       uart_handle_break(port);
+               if (events & UART_SCCM_RX)
+                       cpm_uart_int_rx(port, regs);
+               if (events & UART_SCCM_TX)
+                       cpm_uart_int_tx(port, regs);
+               sccp->scc_scce = events;
+       }
+       return (events) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int cpm_uart_startup(struct uart_port *port)
+{
+       int retval;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       pr_debug("CPM uart[%d]:startup\n", port->line);
+
+       /* Install interrupt handler. */
+       retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
+       if (retval)
+               return retval;
+
+       /* Startup rx-int */
+       if (IS_SMC(pinfo)) {
+               pinfo->smcp->smc_smcm |= SMCM_RX;
+               pinfo->smcp->smc_smcmr |= SMCMR_REN;
+       } else {
+               pinfo->sccp->scc_sccm |= UART_SCCM_RX;
+       }
+
+       return 0;
+}
+
+/*
+ * Shutdown the uart
+ */
+static void cpm_uart_shutdown(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       int line = pinfo - cpm_uart_ports;
+
+       pr_debug("CPM uart[%d]:shutdown\n", port->line);
+
+       /* free interrupt handler */
+       free_irq(port->irq, port);
+
+       /* If the port is not the console, disable Rx and Tx. */
+       if (!(pinfo->flags & FLAG_CONSOLE)) {
+               /* Stop uarts */
+               if (IS_SMC(pinfo)) {
+                       volatile smc_t *smcp = pinfo->smcp;
+                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+                       smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+               } else {
+                       volatile scc_t *sccp = pinfo->sccp;
+                       sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+                       sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+               }
+
+               /* Shut them really down and reinit buffer descriptors */
+               cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+               cpm_uart_initbd(pinfo);
+       }
+}
+
+static void cpm_uart_set_termios(struct uart_port *port,
+                                struct termios *termios, struct termios *old)
+{
+       int baud;
+       unsigned long flags;
+       u16 cval, scval, prev_mode;
+       int bits, sbits;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       volatile smc_t *smcp = pinfo->smcp;
+       volatile scc_t *sccp = pinfo->sccp;
+
+       pr_debug("CPM uart[%d]:set_termios\n", port->line);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+       scval = 0;
+
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               bits = 5;
+               break;
+       case CS6:
+               bits = 6;
+               break;
+       case CS7:
+               bits = 7;
+               break;
+       case CS8:
+               bits = 8;
+               break;
+               /* Never happens, but GCC is too dumb to figure it out */
+       default:
+               bits = 8;
+               break;
+       }
+       sbits = bits - 5;
+
+       if (termios->c_cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               scval |= SCU_PSMR_SL;
+               bits++;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               scval |= SCU_PSMR_PEN;
+               bits++;
+               if (!(termios->c_cflag & PARODD)) {
+                       cval |= SMCMR_PM_EVEN;
+                       scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
+               }
+       }
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
+               port->read_status_mask |= BD_SC_BR;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->read_status_mask &= ~BD_SC_EMPTY;
+       
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Start bit has not been added (so don't, because we would just
+        * subtract it later), and we need to add one for the number of
+        * stops bits (there is always at least one).
+        */
+       bits++;
+       if (IS_SMC(pinfo)) {
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = smcp->smc_smcmr;
+               smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
+               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+       } else {
+               sccp->scc_psmr = (sbits << 12) | scval;
+       }
+
+       cpm_set_brg(pinfo->brg - 1, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+}
+
+static const char *cpm_uart_type(struct uart_port *port)
+{
+       pr_debug("CPM uart[%d]:uart_type\n", port->line);
+
+       return port->type == PORT_CPM ? "CPM UART" : NULL;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int cpm_uart_verify_port(struct uart_port *port,
+                               struct serial_struct *ser)
+{
+       int ret = 0;
+
+       pr_debug("CPM uart[%d]:verify_port\n", port->line);
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
+               ret = -EINVAL;
+       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+               ret = -EINVAL;
+       if (ser->baud_base < 9600)
+               ret = -EINVAL;
+       return ret;
+}
+
+/*
+ * Transmit characters, refill buffer descriptor, if possible
+ */
+static int cpm_uart_tx_pump(struct uart_port *port)
+{
+       volatile cbd_t *bdp;
+       unsigned char *p;
+       int count;
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       struct circ_buf *xmit = &port->info->xmit;
+
+       /* Handle xon/xoff */
+       if (port->x_char) {
+               /* Pick next descriptor and fill from buffer */
+               bdp = pinfo->tx_cur;
+
+               p = bus_to_virt(bdp->cbd_bufaddr);
+               *p++ = xmit->buf[xmit->tail];
+               bdp->cbd_datlen = 1;
+               bdp->cbd_sc |= BD_SC_READY;
+               /* Get next BD. */
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+               pinfo->tx_cur = bdp;
+
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               cpm_uart_stop_tx(port, 0);
+               return 0;
+       }
+
+       /* Pick next descriptor and fill from buffer */
+       bdp = pinfo->tx_cur;
+
+       while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
+               count = 0;
+               p = bus_to_virt(bdp->cbd_bufaddr);
+               while (count < pinfo->tx_fifosize) {
+                       *p++ = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+                       port->icount.tx++;
+                       count++;
+                       if (xmit->head == xmit->tail)
+                               break;
+               }
+               bdp->cbd_datlen = count;
+               bdp->cbd_sc |= BD_SC_READY;
+               /* Get next BD. */
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = pinfo->tx_bd_base;
+               else
+                       bdp++;
+       }
+       pinfo->tx_cur = bdp;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit)) {
+               cpm_uart_stop_tx(port, 0);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * init buffer descriptors
+ */
+static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
+{
+       int i;
+       u8 *mem_addr;
+       volatile cbd_t *bdp;
+
+       pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr;
+       bdp = pinfo->rx_cur = pinfo->rx_bd_base;
+       for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
+               bdp->cbd_bufaddr = virt_to_bus(mem_addr);
+               bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+               mem_addr += pinfo->rx_fifosize;
+       }
+       
+       bdp->cbd_bufaddr = virt_to_bus(mem_addr);
+       bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+       /* Set the physical address of the host memory
+        * buffers in the buffer descriptors, and the
+        * virtual address for us to work with.
+        */
+       mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
+       bdp = pinfo->tx_cur = pinfo->tx_bd_base;
+       for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
+               bdp->cbd_bufaddr = virt_to_bus(mem_addr);
+               bdp->cbd_sc = BD_SC_INTRPT;
+               mem_addr += pinfo->tx_fifosize;
+       }
+       
+       bdp->cbd_bufaddr = virt_to_bus(mem_addr);
+       bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
+}
+
+static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
+{
+       int line = pinfo - cpm_uart_ports;
+       volatile scc_t *scp;
+       volatile scc_uart_t *sup;
+
+       pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
+
+       scp = pinfo->sccp;
+       sup = pinfo->sccup;
+
+       /* Store address */
+       pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE;
+       pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE;
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+
+       cpm_set_scc_fcr(sup);
+
+       sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize;
+       sup->scc_maxidl = pinfo->rx_fifosize;
+       sup->scc_brkcr = 1;
+       sup->scc_parec = 0;
+       sup->scc_frmec = 0;
+       sup->scc_nosec = 0;
+       sup->scc_brkec = 0;
+       sup->scc_uaddr1 = 0;
+       sup->scc_uaddr2 = 0;
+       sup->scc_toseq = 0;
+       sup->scc_char1 = 0x8000;
+       sup->scc_char2 = 0x8000;
+       sup->scc_char3 = 0x8000;
+       sup->scc_char4 = 0x8000;
+       sup->scc_char5 = 0x8000;
+       sup->scc_char6 = 0x8000;
+       sup->scc_char7 = 0x8000;
+       sup->scc_char8 = 0x8000;
+       sup->scc_rccm = 0xc0ff;
+
+       /* Send the CPM an initialize command.
+        */
+       cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       scp->scc_gsmrh = 0;
+       scp->scc_gsmrl =
+           (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+       /* Enable rx interrupts  and clear all pending events.  */
+       scp->scc_sccm = 0;
+       scp->scc_scce = 0xffff;
+       scp->scc_dsr = 0x7e7e;
+       scp->scc_psmr = 0x3000;
+
+       scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+
+static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
+{
+       int line = pinfo - cpm_uart_ports;
+       volatile smc_t *sp;
+       volatile smc_uart_t *up;
+
+       pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
+
+       sp = pinfo->smcp;
+       up = pinfo->smcup;
+
+       /* Store address */
+       pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
+       pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
+
+       /* Set up the uart parameters in the
+        * parameter ram.
+        */
+       cpm_set_smc_fcr(up);
+
+       /* Using idle charater time requires some additional tuning.  */
+       up->smc_mrblr = pinfo->rx_fifosize;
+       up->smc_maxidl = pinfo->rx_fifosize;
+       up->smc_brkcr = 1;
+
+       cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+       /* Enable only rx interrupts clear all pending events. */
+       sp->smc_smcm = 0;
+       sp->smc_smce = 0xff;
+
+       sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+}
+
+/*
+ * Initialize port. This is called from early_console stuff
+ * so we have to be careful here !
+ */
+static int cpm_uart_request_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+       int ret;
+
+       pr_debug("CPM uart[%d]:request port\n", port->line);
+
+       if (pinfo->flags & FLAG_CONSOLE)
+               return 0;
+
+       /*
+        * Setup any port IO, connect any baud rate generators,
+        * etc.  This is expected to be handled by board
+        * dependant code 
+        */
+       if (pinfo->set_lineif)
+               pinfo->set_lineif(pinfo);
+
+       if (IS_SMC(pinfo)) {
+               pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+               pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       } else {
+               pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+               pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 0);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+
+       return 0;
+}
+
+static void cpm_uart_release_port(struct uart_port *port)
+{
+       struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+       if (!(pinfo->flags & FLAG_CONSOLE))
+               cpm_uart_freebuf(pinfo);
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void cpm_uart_config_port(struct uart_port *port, int flags)
+{
+       pr_debug("CPM uart[%d]:config_port\n", port->line);
+
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_CPM;
+               cpm_uart_request_port(port);
+       }
+}
+static struct uart_ops cpm_uart_pops = {
+       .tx_empty       = cpm_uart_tx_empty,
+       .set_mctrl      = cpm_uart_set_mctrl,
+       .get_mctrl      = cpm_uart_get_mctrl,
+       .stop_tx        = cpm_uart_stop_tx,
+       .start_tx       = cpm_uart_start_tx,
+       .stop_rx        = cpm_uart_stop_rx,
+       .enable_ms      = cpm_uart_enable_ms,
+       .break_ctl      = cpm_uart_break_ctl,
+       .startup        = cpm_uart_startup,
+       .shutdown       = cpm_uart_shutdown,
+       .set_termios    = cpm_uart_set_termios,
+       .type           = cpm_uart_type,
+       .release_port   = cpm_uart_release_port,
+       .request_port   = cpm_uart_request_port,
+       .config_port    = cpm_uart_config_port,
+       .verify_port    = cpm_uart_verify_port,
+};
+
+struct uart_cpm_port cpm_uart_ports[UART_NR] = {
+       [UART_SMC1] = {
+               .port = {
+                       .irq            = SMC1_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .flags = FLAG_SMC,
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = smc1_lineif,
+       },
+       [UART_SMC2] = {
+               .port = {
+                       .irq            = SMC2_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .flags = FLAG_SMC,
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = smc2_lineif,
+       },
+       [UART_SCC1] = {
+               .port = {
+                       .irq            = SCC1_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = scc1_lineif,
+       },
+       [UART_SCC2] = {
+               .port = {
+                       .irq            = SCC2_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = scc2_lineif,
+       },
+       [UART_SCC3] = {
+               .port = {
+                       .irq            = SCC3_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = scc3_lineif,
+       },
+       [UART_SCC4] = {
+               .port = {
+                       .irq            = SCC4_IRQ,
+                       .ops            = &cpm_uart_pops,
+                       .iotype         = SERIAL_IO_MEM,
+               },
+               .tx_nrfifos = TX_NUM_FIFO,
+               .tx_fifosize = TX_BUF_SIZE,
+               .rx_nrfifos = RX_NUM_FIFO, 
+               .rx_fifosize = RX_BUF_SIZE,
+               .set_lineif = scc4_lineif,
+       },
+};
+
+#ifdef CONFIG_SERIAL_CPM_CONSOLE
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     Note that this is called with interrupts already disabled
+ */
+static void cpm_uart_console_write(struct console *co, const char *s,
+                                  u_int count)
+{
+       struct uart_cpm_port *pinfo =
+           &cpm_uart_ports[cpm_uart_port_map[co->index]];
+       unsigned int i;
+       volatile cbd_t *bdp, *bdbase;
+       volatile unsigned char *cp;
+
+       /* Get the address of the host memory buffer.
+        */
+       bdp = pinfo->tx_cur;
+       bdbase = pinfo->tx_bd_base;
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, s++) {
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while ((bdp->cbd_sc & BD_SC_READY) != 0)
+                       ;
+
+               /* Send the character out.
+                * If the buffer address is in the CPM DPRAM, don't
+                * convert it.
+                */
+               if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR)
+                       cp = (unsigned char *) (bdp->cbd_bufaddr);
+               else
+                       cp = bus_to_virt(bdp->cbd_bufaddr);
+               
+               *cp = *s;
+
+               bdp->cbd_datlen = 1;
+               bdp->cbd_sc |= BD_SC_READY;
+
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*s == 10) {
+                       while ((bdp->cbd_sc & BD_SC_READY) != 0)
+                               ;
+
+                       if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR)
+                               cp = (unsigned char *) (bdp->cbd_bufaddr);
+                       else
+                               cp = bus_to_virt(bdp->cbd_bufaddr);
+
+                       *cp = 13;
+                       bdp->cbd_datlen = 1;
+                       bdp->cbd_sc |= BD_SC_READY;
+
+                       if (bdp->cbd_sc & BD_SC_WRAP)
+                               bdp = bdbase;
+                       else
+                               bdp++;
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while ((bdp->cbd_sc & BD_SC_READY) != 0)
+               ;
+
+       pinfo->tx_cur = (volatile cbd_t *) bdp;
+}
+
+/*
+ * Setup console. Be careful is called early !
+ */
+static int __init cpm_uart_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       struct uart_cpm_port *pinfo;
+       int baud = 38400;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+
+       port =
+           (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]];
+       pinfo = (struct uart_cpm_port *)port;
+       
+       pinfo->flags |= FLAG_CONSOLE;
+
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       } else {
+               bd_t *bd = (bd_t *) __res;
+
+               if (bd->bi_baudrate)
+                       baud = bd->bi_baudrate;
+               else
+                       baud = 9600;
+       }
+
+       /*
+        * Setup any port IO, connect any baud rate generators,
+        * etc.  This is expected to be handled by board
+        * dependant code 
+        */
+       if (pinfo->set_lineif)
+               pinfo->set_lineif(pinfo);
+
+       if (IS_SMC(pinfo)) {
+               pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+               pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       } else {
+               pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+               pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       }
+
+       ret = cpm_uart_allocbuf(pinfo, 1);
+
+       if (ret)
+               return ret;
+
+       cpm_uart_initbd(pinfo);
+
+       if (IS_SMC(pinfo))
+               cpm_uart_init_smc(pinfo);
+       else
+               cpm_uart_init_scc(pinfo);
+
+       uart_set_options(port, co, baud, parity, bits, flow);
+
+       return 0;
+}
+
+extern struct uart_driver cpm_reg;
+static struct console cpm_scc_uart_console = {
+       .name           "ttyCPM",
+       .write          cpm_uart_console_write,
+       .device         uart_console_device,
+       .setup          cpm_uart_console_setup,
+       .flags          CON_PRINTBUFFER,
+       .index          -1,
+       .data           = &cpm_reg,
+};
+
+int __init cpm_uart_console_init(void)
+{
+       int ret = cpm_uart_init_portdesc();
+
+       if (!ret)
+               register_console(&cpm_scc_uart_console);
+       return ret;
+}
+
+console_initcall(cpm_uart_console_init);
+
+#define CPM_UART_CONSOLE       &cpm_scc_uart_console
+#else
+#define CPM_UART_CONSOLE       NULL
+#endif
+
+static struct uart_driver cpm_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ttyCPM",
+       .dev_name       = "ttyCPM",
+       .major          = SERIAL_CPM_MAJOR,
+       .minor          = SERIAL_CPM_MINOR,
+       .cons           = CPM_UART_CONSOLE,
+};
+
+static int __init cpm_uart_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n");
+
+#ifndef CONFIG_SERIAL_CPM_CONSOLE
+       ret = cpm_uart_init_portdesc();
+       if (ret)
+               return ret;
+#endif
+
+       cpm_reg.nr = cpm_uart_nr;
+       ret = uart_register_driver(&cpm_reg);
+
+       if (ret)
+               return ret;
+
+       for (i = 0; i < cpm_uart_nr; i++) {
+               int con = cpm_uart_port_map[i];
+               cpm_uart_ports[con].port.line = i;
+               cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
+               uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
+       }
+
+       return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+       int i;
+
+       for (i = 0; i < cpm_uart_nr; i++) {
+               int con = cpm_uart_port_map[i];
+               uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port);
+       }
+
+       uart_unregister_driver(&cpm_reg);
+}
+
+module_init(cpm_uart_init);
+module_exit(cpm_uart_exit);
+
+MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");
+MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
new file mode 100644 (file)
index 0000000..a9ab047
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  linux/drivers/serial/cpm_uart.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
+ *
+ *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ * 
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *
+ * This program is free software; 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(int line, int cmd)
+{
+       ushort val;
+       volatile cpm8xx_t *cp = cpmp;
+
+       switch (line) {
+       case UART_SMC1:
+               val = mk_cr_cmd(CPM_CR_CH_SMC1, cmd) | CPM_CR_FLG;
+               break;
+       case UART_SMC2:
+               val = mk_cr_cmd(CPM_CR_CH_SMC2, cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC1:
+               val = mk_cr_cmd(CPM_CR_CH_SCC1, cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC2:
+               val = mk_cr_cmd(CPM_CR_CH_SCC2, cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC3:
+               val = mk_cr_cmd(CPM_CR_CH_SCC3, cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC4:
+               val = mk_cr_cmd(CPM_CR_CH_SCC4, cmd) | CPM_CR_FLG;
+               break;
+       default:
+               return;
+
+       }
+       cp->cp_cpcr = val;
+       while (cp->cp_cpcr & CPM_CR_FLG) ;
+}
+
+void smc1_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile cpm8xx_t *cp = cpmp;
+
+       cp->cp_pbpar |= 0x000000c0;
+       cp->cp_pbdir &= ~0x000000c0;
+       cp->cp_pbodr &= ~0x000000c0;
+
+       pinfo->brg = 1;
+}
+
+void smc2_lineif(struct uart_cpm_port *pinfo)
+{
+       /* XXX SMC2: insert port configuration here */
+       pinfo->brg = 2;
+}
+
+void scc1_lineif(struct uart_cpm_port *pinfo)
+{
+       /* XXX SCC1: insert port configuration here */
+       pinfo->brg = 1;
+}
+
+void scc2_lineif(struct uart_cpm_port *pinfo)
+{
+       /* XXX SCC2: insert port configuration here */
+       pinfo->brg = 2;
+}
+
+void scc3_lineif(struct uart_cpm_port *pinfo)
+{
+       /* XXX SCC3: insert port configuration here */
+       pinfo->brg = 3;
+}
+
+void scc4_lineif(struct uart_cpm_port *pinfo)
+{
+       /* XXX SCC4: insert port configuration here */
+       pinfo->brg = 4;
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and 
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 *dp_mem;
+       uint dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_DPERR(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con) {
+               mem_addr = (u8 *) m8xx_cpm_hostalloc(memsz);
+               dma_addr = 0;
+       } else
+               mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm1.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;
+       pinfo->dma_addr = dma_addr;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                              pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
+
+/* Setup any dynamic params in the uart desc */
+int cpm_uart_init_portdesc(void)
+{
+       pr_debug("CPM uart[-]:init portdesc\n");
+
+       cpm_uart_nr = 0;
+#ifdef CONFIG_SERIAL_CPM_SMC1
+       cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0];
+       cpm_uart_ports[UART_SMC1].smcup =
+           (smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1];
+       cpm_uart_ports[UART_SMC1].port.mapbase =
+           (unsigned long)&cpmp->cp_smc[0];
+       cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+       cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+       cpm_uart_ports[UART_SMC2].smcp = &cpmp->cp_smc[1];
+       cpm_uart_ports[UART_SMC2].smcup =
+           (smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC2];
+       cpm_uart_ports[UART_SMC2].port.mapbase =
+           (unsigned long)&cpmp->cp_smc[1];
+       cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+       cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC1
+       cpm_uart_ports[UART_SCC1].sccp = &cpmp->cp_scc[0];
+       cpm_uart_ports[UART_SCC1].sccup =
+           (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC1];
+       cpm_uart_ports[UART_SCC1].port.mapbase =
+           (unsigned long)&cpmp->cp_scc[0];
+       cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC2
+       cpm_uart_ports[UART_SCC2].sccp = &cpmp->cp_scc[1];
+       cpm_uart_ports[UART_SCC2].sccup =
+           (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC2];
+       cpm_uart_ports[UART_SCC2].port.mapbase =
+           (unsigned long)&cpmp->cp_scc[1];
+       cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC3
+       cpm_uart_ports[UART_SCC3].sccp = &cpmp->cp_scc[2];
+       cpm_uart_ports[UART_SCC3].sccup =
+           (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC3];
+       cpm_uart_ports[UART_SCC3].port.mapbase =
+           (unsigned long)&cpmp->cp_scc[2];
+       cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC4
+       cpm_uart_ports[UART_SCC4].sccp = &cpmp->cp_scc[3];
+       cpm_uart_ports[UART_SCC4].sccup =
+           (scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC4];
+       cpm_uart_ports[UART_SCC4].port.mapbase =
+           (unsigned long)&cpmp->cp_scc[3];
+       cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
+#endif
+       return 0;
+}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
new file mode 100644 (file)
index 0000000..5d867ab
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/drivers/serial/cpm_uart_cpm1.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ * 
+ * definitions for cpm1
+ *
+ */
+
+#ifndef CPM_UART_CPM1_H
+#define CPM_UART_CPM1_H
+
+#include <asm/commproc.h>
+
+/* defines for IRQs */
+#define SMC1_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SMC1)
+#define SMC2_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SMC2)
+#define SCC1_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SCC1)
+#define SCC2_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SCC2)
+#define SCC3_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SCC3)
+#define SCC4_IRQ       (CPM_IRQ_OFFSET + CPMVEC_SCC4)
+
+/* the CPM address */
+#define CPM_ADDR       IMAP_ADDR
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+{
+       sup->scc_genscc.scc_rfcr = SMC_EB;
+       sup->scc_genscc.scc_tfcr = SMC_EB;
+}
+
+static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+{
+       up->smc_rfcr = SMC_EB;
+       up->smc_tfcr = SMC_EB;
+}
+
+#define DPRAM_BASE     ((unsigned char *)&cpmp->cp_dpmem[0])
+
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
new file mode 100644 (file)
index 0000000..0c12f28
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *  linux/drivers/serial/cpm_uart_cpm2.c
+ *
+ *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
+ *
+ *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
+ * 
+ *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *            (C) 2004 Intracom, S.A.
+ *
+ * This program is free software; 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/serial_core.h>
+#include <linux/kernel.h>
+
+#include "cpm_uart.h"
+
+/**************************************************************/
+
+void cpm_line_cr_cmd(int line, int cmd)
+{
+       volatile cpm_cpm2_t *cp = cpmp;
+       ulong val;
+
+       switch (line) {
+       case UART_SMC1:
+               val = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       case UART_SMC2:
+               val = mk_cr_cmd(CPM_CR_SMC2_PAGE, CPM_CR_SMC2_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC1:
+               val = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC2:
+               val = mk_cr_cmd(CPM_CR_SCC2_PAGE, CPM_CR_SCC2_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC3:
+               val = mk_cr_cmd(CPM_CR_SCC3_PAGE, CPM_CR_SCC3_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       case UART_SCC4:
+               val = mk_cr_cmd(CPM_CR_SCC4_PAGE, CPM_CR_SCC4_SBLOCK, 0,
+                               cmd) | CPM_CR_FLG;
+               break;
+       default:
+               return;
+
+       }
+       cp->cp_cpcr = val;
+       while (cp->cp_cpcr & CPM_CR_FLG) ;
+}
+
+void smc1_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+
+       /* SMC1 is only on port D */
+       io->iop_ppard |= 0x00c00000;
+       io->iop_pdird |= 0x00400000;
+       io->iop_pdird &= ~0x00800000;
+       io->iop_psord &= ~0x00c00000;
+
+       /* Wire BRG1 to SMC1 */
+       cpm2_immr->im_cpmux.cmx_smr &= 0x0f;
+       pinfo->brg = 1;
+}
+
+void smc2_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+
+       /* SMC2 is only on port A */
+       io->iop_ppara |= 0x00c00000;
+       io->iop_pdira |= 0x00400000;
+       io->iop_pdira &= ~0x00800000;
+       io->iop_psora &= ~0x00c00000;
+
+       /* Wire BRG2 to SMC2 */
+       cpm2_immr->im_cpmux.cmx_smr &= 0xf0;
+       pinfo->brg = 2;
+}
+
+void scc1_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+
+       /* Use Port D for SCC1 instead of other functions.  */
+       io->iop_ppard |= 0x00000003;
+       io->iop_psord &= ~0x00000001;   /* Rx */
+       io->iop_psord |= 0x00000002;    /* Tx */
+       io->iop_pdird &= ~0x00000001;   /* Rx */
+       io->iop_pdird |= 0x00000002;    /* Tx */
+
+       /* Wire BRG1 to SCC1 */
+       cpm2_immr->im_cpmux.cmx_scr &= ~0x00ffffff;
+       cpm2_immr->im_cpmux.cmx_scr |= 0x00000000;
+       pinfo->brg = 1;
+}
+
+void scc2_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+       io->iop_pparb |= 0x008b0000;
+       io->iop_pdirb |= 0x00880000;
+       io->iop_psorb |= 0x00880000;
+       io->iop_pdirb &= ~0x00030000;
+       io->iop_psorb &= ~0x00030000;
+       cpm2_immr->im_cpmux.cmx_scr &= ~0xff00ffff;
+       cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
+       pinfo->brg = 2;
+}
+
+void scc3_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+       io->iop_pparb |= 0x008b0000;
+       io->iop_pdirb |= 0x00880000;
+       io->iop_psorb |= 0x00880000;
+       io->iop_pdirb &= ~0x00030000;
+       io->iop_psorb &= ~0x00030000;
+       cpm2_immr->im_cpmux.cmx_scr &= ~0xffff00ff;
+       cpm2_immr->im_cpmux.cmx_scr |= 0x00001200;
+       pinfo->brg = 3;
+}
+
+void scc4_lineif(struct uart_cpm_port *pinfo)
+{
+       volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+
+       io->iop_ppard |= 0x00000600;
+       io->iop_psord &= ~0x00000600;   /* Tx/Rx */
+       io->iop_pdird &= ~0x00000200;   /* Rx */
+       io->iop_pdird |= 0x00000400;    /* Tx */
+
+       cpm2_immr->im_cpmux.cmx_scr &= ~0xffffff00;
+       cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b;
+       pinfo->brg = 4;
+}
+
+/*
+ * Allocate DP-Ram and memory buffers. We need to allocate a transmit and 
+ * receive buffer descriptors from dual port ram, and a character
+ * buffer area from host mem. If we are allocating for the console we need
+ * to do it from bootmem
+ */
+int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
+{
+       int dpmemsz, memsz;
+       u8 *dp_mem;
+       uint dp_offset;
+       u8 *mem_addr;
+       dma_addr_t dma_addr = 0;
+
+       pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
+
+       dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
+       dp_offset = cpm_dpalloc(dpmemsz, 8);
+       if (IS_DPERR(dp_offset)) {
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
+               return -ENOMEM;
+       }
+
+       dp_mem = cpm_dpram_addr(dp_offset);
+
+       memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
+           L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
+       if (is_con)
+               mem_addr = alloc_bootmem(memsz);
+       else
+               mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+                                             GFP_KERNEL);
+
+       if (mem_addr == NULL) {
+               cpm_dpfree(dp_offset);
+               printk(KERN_ERR
+                      "cpm_uart_cpm.c: could not allocate coherent memory\n");
+               return -ENOMEM;
+       }
+
+       pinfo->dp_addr = dp_offset;
+       pinfo->mem_addr = mem_addr;
+       pinfo->dma_addr = dma_addr;
+
+       pinfo->rx_buf = mem_addr;
+       pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
+                                                      * pinfo->rx_fifosize);
+
+       pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+       pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
+
+       return 0;
+}
+
+void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
+{
+       dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+                                              pinfo->rx_fifosize) +
+                         L1_CACHE_ALIGN(pinfo->tx_nrfifos *
+                                        pinfo->tx_fifosize), pinfo->mem_addr,
+                         pinfo->dma_addr);
+
+       cpm_dpfree(pinfo->dp_addr);
+}
+
+/* Setup any dynamic params in the uart desc */
+int cpm_uart_init_portdesc(void)
+{
+       pr_debug("CPM uart[-]:init portdesc\n");
+
+       cpm_uart_nr = 0;
+#ifdef CONFIG_SERIAL_CPM_SMC1
+       cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
+       cpm_uart_ports[UART_SMC1].smcup =
+           (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
+       cpm_uart_ports[UART_SMC1].port.mapbase =
+           (unsigned long)&cpm2_immr->im_smc[0];
+       cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+       cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+       cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
+       cpm_uart_ports[UART_SMC2].smcup =
+           (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
+       cpm_uart_ports[UART_SMC2].port.mapbase =
+           (unsigned long)&cpm2_immr->im_smc[1];
+       cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+       cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC1
+       cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0];
+       cpm_uart_ports[UART_SCC1].sccup =
+           (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1];
+       cpm_uart_ports[UART_SCC1].port.mapbase =
+           (unsigned long)&cpm2_immr->im_scc[0];
+       cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC2
+       cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1];
+       cpm_uart_ports[UART_SCC2].sccup =
+           (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2];
+       cpm_uart_ports[UART_SCC2].port.mapbase =
+           (unsigned long)&cpm2_immr->im_scc[1];
+       cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC3
+       cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2];
+       cpm_uart_ports[UART_SCC3].sccup =
+           (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3];
+       cpm_uart_ports[UART_SCC3].port.mapbase =
+           (unsigned long)&cpm2_immr->im_scc[2];
+       cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC4
+       cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3];
+       cpm_uart_ports[UART_SCC4].sccup =
+           (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4];
+       cpm_uart_ports[UART_SCC4].port.mapbase =
+           (unsigned long)&cpm2_immr->im_scc[3];
+       cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
+           ~(UART_SCCM_TX | UART_SCCM_RX);
+       cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
+           ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+       cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+       cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
+#endif
+
+       return 0;
+}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
new file mode 100644 (file)
index 0000000..4793fec
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/drivers/serial/cpm_uart_cpm2.h
+ *
+ * Driver for CPM (SCC/SMC) serial ports
+ * 
+ * definitions for cpm2
+ *
+ */
+
+#ifndef CPM_UART_CPM2_H
+#define CPM_UART_CPM2_H
+
+#include <asm/cpm2.h>
+
+/* defines for IRQs */
+#define SMC1_IRQ       SIU_INT_SMC1
+#define SMC2_IRQ       SIU_INT_SMC2
+#define SCC1_IRQ       SIU_INT_SCC1
+#define SCC2_IRQ       SIU_INT_SCC2
+#define SCC3_IRQ       SIU_INT_SCC3
+#define SCC4_IRQ       SIU_INT_SCC4
+
+/* the CPM address */
+#define CPM_ADDR       CPM_MAP_ADDR
+
+static inline void cpm_set_brg(int brg, int baud)
+{
+       cpm_setbrg(brg, baud);
+}
+
+static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+{
+       sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+       sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+}
+
+static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+{
+       up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+       up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+}
+
+#define DPRAM_BASE     ((unsigned char *)&cpm2_immr->im_dprambase[0])
+
+#endif
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
new file mode 100644 (file)
index 0000000..3feba05
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * drivers/serial/mpc52xx_uart.c
+ *
+ * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
+ *
+ * FIXME According to the usermanual the status bits in the status register
+ * are only updated when the peripherals access the FIFO and not when the
+ * CPU access them. So since we use this bits to know when we stop writing
+ * and reading, they may not be updated in-time and a race condition may
+ * exists. But I haven't be able to prove this and I don't care. But if
+ * any problem arises, it might worth checking. The TX/RX FIFO Stats
+ * registers should be used in addition.
+ * Update: Actually, they seem updated ... At least the bits we use.
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ * 
+ * Some of the code has been inspired/copied from the 2.4 code written
+ * by Dale Farnsworth <dfarnsworth@mvista.com>.
+ * 
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ * 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+/* OCP Usage :
+ *
+ * This drivers uses the OCP model. To load the serial driver for one of the
+ * PSCs, just add this to the core_ocp table :
+ *
+ * {
+ *     .vendor         = OCP_VENDOR_FREESCALE,
+ *     .function       = OCP_FUNC_PSC_UART,
+ *     .index          = 0,
+ *     .paddr          = MPC52xx_PSC1,
+ *     .irq            = MPC52xx_PSC1_IRQ,
+ *     .pm             = OCP_CPM_NA,
+ * },
+ *
+ * This is for PSC1, replace the paddr and irq according to the PSC you want to
+ * use. The driver all necessary registers to place the PSC in uart mode without
+ * DCD. However, the pin multiplexing aren't changed and should be set either
+ * by the bootloader or in the platform init code.
+ * The index field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2,
+ * and so on). So the PSC1 is mapped to /dev/ttyS0, PSC2 to /dev/ttyS1 and so
+ * on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly for
+ * the console code : without this 1:1 mapping, at early boot time, when we are
+ * parsing the kernel args console=ttyS?, we wouldn't know wich PSC it will be
+ * mapped to because OCP stuff is not yet initialized.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+
+#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
+
+
+static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
+       /* Rem: - We use the read_status_mask as a shadow of
+        *        psc->mpc52xx_psc_imr
+        *      - It's important that is array is all zero on start as we
+        *        use it to know if it's initialized or not ! If it's not sure
+        *        it's cleared, then a memset(...,0,...) should be added to
+        *        the console_init
+        */
+
+#define PSC(port) ((struct mpc52xx_psc *)((port)->membase))
+
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs);
+
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port)     ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port)     (0)
+#endif
+
+
+/* ======================================================================== */
+/* UART operations                                                          */
+/* ======================================================================== */
+
+static unsigned int 
+mpc52xx_uart_tx_empty(struct uart_port *port)
+{
+       int status = in_be16(&PSC(port)->mpc52xx_psc_status);
+       return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
+}
+
+static void 
+mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* Not implemented */
+}
+
+static unsigned int 
+mpc52xx_uart_get_mctrl(struct uart_port *port)
+{
+       /* Not implemented */
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void 
+mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       /* port->lock taken by caller */
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+}
+
+static void 
+mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+       /* port->lock taken by caller */
+       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+}
+
+static void 
+mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+       
+       port->x_char = ch;
+       if (ch) {
+               /* Make sure tx interrupts are on */
+               /* Truly necessary ??? They should be anyway */
+               port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+               out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+       }
+       
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+mpc52xx_uart_stop_rx(struct uart_port *port)
+{
+       /* port->lock taken by caller */
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+}
+
+static void
+mpc52xx_uart_enable_ms(struct uart_port *port)
+{
+       /* Not implemented */
+}
+
+static void
+mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+
+       if ( ctl == -1 )
+               out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
+       else
+               out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
+       
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int
+mpc52xx_uart_startup(struct uart_port *port)
+{
+       struct mpc52xx_psc *psc = PSC(port);
+
+       /* Reset/activate the port, clear and enable interrupts */
+       out_8(&psc->command,MPC52xx_PSC_RST_RX);
+       out_8(&psc->command,MPC52xx_PSC_RST_TX);
+       
+       out_be32(&psc->sicr,0); /* UART mode DCD ignored */
+
+       out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
+       
+       out_8(&psc->rfcntl, 0x00);
+       out_be16(&psc->rfalarm, 0x1ff);
+       out_8(&psc->tfcntl, 0x07);
+       out_be16(&psc->tfalarm, 0x80);
+
+       port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+       
+       out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
+               
+       return 0;
+}
+
+static void
+mpc52xx_uart_shutdown(struct uart_port *port)
+{
+       struct mpc52xx_psc *psc = PSC(port);
+       
+       /* Shut down the port, interrupt and all */
+       out_8(&psc->command,MPC52xx_PSC_RST_RX);
+       out_8(&psc->command,MPC52xx_PSC_RST_TX);
+       
+       port->read_status_mask = 0; 
+       out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+}
+
+static void 
+mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
+                         struct termios *old)
+{
+       struct mpc52xx_psc *psc = PSC(port);
+       unsigned long flags;
+       unsigned char mr1, mr2;
+       unsigned short ctr;
+       unsigned int j, baud, quot;
+       
+       /* Prepare what we're gonna write */
+       mr1 = 0;
+       
+       switch (new->c_cflag & CSIZE) {
+               case CS5:       mr1 |= MPC52xx_PSC_MODE_5_BITS;
+                               break;
+               case CS6:       mr1 |= MPC52xx_PSC_MODE_6_BITS;
+                               break;
+               case CS7:       mr1 |= MPC52xx_PSC_MODE_7_BITS;
+                               break;
+               case CS8:
+               default:        mr1 |= MPC52xx_PSC_MODE_8_BITS;
+       }
+
+       if (new->c_cflag & PARENB) {
+               mr1 |= (new->c_cflag & PARODD) ?
+                       MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
+       } else
+               mr1 |= MPC52xx_PSC_MODE_PARNONE;
+       
+       
+       mr2 = 0;
+
+       if (new->c_cflag & CSTOPB)
+               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
+       else
+               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
+                       MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
+                       MPC52xx_PSC_MODE_ONE_STOP;
+
+
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+       ctr = quot & 0xffff;
+       
+       /* Get the lock */
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Update the per-port timeout */
+       uart_update_timeout(port, new->c_cflag, baud);
+
+       /* Do our best to flush TX & RX, so we don't loose anything */
+       /* But we don't wait indefinitly ! */
+       j = 5000000;    /* Maximum wait */
+       /* FIXME Can't receive chars since set_termios might be called at early
+        * boot for the console, all stuff is not yet ready to receive at that
+        * time and that just makes the kernel oops */
+       /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
+       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && 
+              --j)
+               udelay(1);
+
+       if (!j)
+               printk( KERN_ERR "mpc52xx_uart.c: "
+                       "Unable to flush RX & TX fifos in-time in set_termios."
+                       "Some chars may have been lost.\n" ); 
+
+       /* Reset the TX & RX */
+       out_8(&psc->command,MPC52xx_PSC_RST_RX);
+       out_8(&psc->command,MPC52xx_PSC_RST_TX);
+
+       /* Send new mode settings */
+       out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->mode,mr1);
+       out_8(&psc->mode,mr2);
+       out_8(&psc->ctur,ctr >> 8);
+       out_8(&psc->ctlr,ctr & 0xff);
+       
+       /* Reenable TX & RX */
+       out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
+       out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
+
+       /* We're all set, release the lock */
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *
+mpc52xx_uart_type(struct uart_port *port)
+{
+       return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
+}
+
+static void
+mpc52xx_uart_release_port(struct uart_port *port)
+{
+       if (port->flags & UPF_IOREMAP) { /* remapped by us ? */
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+}
+
+static int
+mpc52xx_uart_request_port(struct uart_port *port)
+{
+       if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+               port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
+       
+       return port->membase != NULL ? 0 : -EBUSY;
+}
+
+static void
+mpc52xx_uart_config_port(struct uart_port *port, int flags)
+{
+       if ( (flags & UART_CONFIG_TYPE) &&
+            (mpc52xx_uart_request_port(port) == 0) )
+               port->type = PORT_MPC52xx;
+}
+
+static int
+mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx )
+               return -EINVAL;
+
+       if ( (ser->irq != port->irq) ||
+            (ser->io_type != SERIAL_IO_MEM) ||
+            (ser->baud_base != port->uartclk)  || 
+            // FIXME Should check addresses/irq as well ?
+            (ser->hub6 != 0 ) )
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static struct uart_ops mpc52xx_uart_ops = {
+       .tx_empty       = mpc52xx_uart_tx_empty,
+       .set_mctrl      = mpc52xx_uart_set_mctrl,
+       .get_mctrl      = mpc52xx_uart_get_mctrl,
+       .stop_tx        = mpc52xx_uart_stop_tx,
+       .start_tx       = mpc52xx_uart_start_tx,
+       .send_xchar     = mpc52xx_uart_send_xchar,
+       .stop_rx        = mpc52xx_uart_stop_rx,
+       .enable_ms      = mpc52xx_uart_enable_ms,
+       .break_ctl      = mpc52xx_uart_break_ctl,
+       .startup        = mpc52xx_uart_startup,
+       .shutdown       = mpc52xx_uart_shutdown,
+       .set_termios    = mpc52xx_uart_set_termios,
+/*     .pm             = mpc52xx_uart_pm,              Not supported yet */
+/*     .set_wake       = mpc52xx_uart_set_wake,        Not supported yet */
+       .type           = mpc52xx_uart_type,
+       .release_port   = mpc52xx_uart_release_port,
+       .request_port   = mpc52xx_uart_request_port,
+       .config_port    = mpc52xx_uart_config_port,
+       .verify_port    = mpc52xx_uart_verify_port
+};
+
+       
+/* ======================================================================== */
+/* Interrupt handling                                                       */
+/* ======================================================================== */
+       
+static inline int
+mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
+{
+       struct tty_struct *tty = port->info->tty;
+       unsigned char ch;
+       unsigned short status;
+
+       /* While we can read, do so ! */
+       while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
+               MPC52xx_PSC_SR_RXRDY) {
+
+               /* If we are full, just stop reading */
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                       break;
+               
+               /* Get the char */
+               ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
+
+               /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+               if (uart_handle_sysrq_char(port, ch, regs)) {
+                       port->sysrq = 0;
+                       continue;
+               }
+#endif
+
+               /* Store it */
+               *tty->flip.char_buf_ptr = ch;
+               *tty->flip.flag_buf_ptr = 0;
+               port->icount.rx++;
+       
+               if ( status & (MPC52xx_PSC_SR_PE |
+                              MPC52xx_PSC_SR_FE |
+                              MPC52xx_PSC_SR_RB |
+                              MPC52xx_PSC_SR_OE) ) {
+                       
+                       if (status & MPC52xx_PSC_SR_RB) {
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               uart_handle_break(port);
+                       } else if (status & MPC52xx_PSC_SR_PE)
+                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                       else if (status & MPC52xx_PSC_SR_FE)
+                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                       if (status & MPC52xx_PSC_SR_OE) {
+                               /*
+                                * Overrun is special, since it's
+                                * reported immediately, and doesn't
+                                * affect the current character
+                                */
+                               if (tty->flip.count < (TTY_FLIPBUF_SIZE-1)) {
+                                       tty->flip.flag_buf_ptr++;
+                                       tty->flip.char_buf_ptr++;
+                                       tty->flip.count++;
+                               }
+                               *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                       }
+
+                       /* Clear error condition */
+                       out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT);
+
+               }
+
+               tty->flip.char_buf_ptr++;
+               tty->flip.flag_buf_ptr++;
+               tty->flip.count++;
+
+       }
+
+       tty_flip_buffer_push(tty);
+       
+       return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
+}
+
+static inline int
+mpc52xx_uart_int_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->info->xmit;
+
+       /* Process out of band chars */
+       if (port->x_char) {
+               out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               return 1;
+       }
+
+       /* Nothing to do ? */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               mpc52xx_uart_stop_tx(port,0);
+               return 0;
+       }
+
+       /* Send chars */
+       while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
+               out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       /* Wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       /* Maybe we're done after all */
+       if (uart_circ_empty(xmit)) {
+               mpc52xx_uart_stop_tx(port,0);
+               return 0;
+       }
+
+       return 1;
+}
+
+static irqreturn_t 
+mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct uart_port *port = (struct uart_port *) dev_id;
+       unsigned long pass = ISR_PASS_LIMIT;
+       unsigned int keepgoing;
+       unsigned short status;
+       
+       if ( irq != port->irq ) {
+               printk( KERN_WARNING
+                       "mpc52xx_uart_int : " \
+                       "Received wrong int %d. Waiting for %d\n",
+                      irq, port->irq);
+               return IRQ_NONE;
+       }
+       
+       spin_lock(&port->lock);
+       
+       /* While we have stuff to do, we continue */
+       do {
+               /* If we don't find anything to do, we stop */
+               keepgoing = 0; 
+               
+               /* Read status */
+               status = in_be16(&PSC(port)->mpc52xx_psc_isr);
+               status &= port->read_status_mask;
+                       
+               /* Do we need to receive chars ? */
+               /* For this RX interrupts must be on and some chars waiting */
+               if ( status & MPC52xx_PSC_IMR_RXRDY )
+                       keepgoing |= mpc52xx_uart_int_rx_chars(port, regs);
+
+               /* Do we need to send chars ? */
+               /* For this, TX must be ready and TX interrupt enabled */
+               if ( status & MPC52xx_PSC_IMR_TXRDY )
+                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
+               
+               /* Limit number of iteration */
+               if ( !(--pass) )
+                       keepgoing = 0;
+
+       } while (keepgoing);
+       
+       spin_unlock(&port->lock);
+       
+       return IRQ_HANDLED;
+}
+
+
+/* ======================================================================== */
+/* Console ( if applicable )                                                */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
+
+static void __init
+mpc52xx_console_get_options(struct uart_port *port,
+                            int *baud, int *parity, int *bits, int *flow)
+{
+       struct mpc52xx_psc *psc = PSC(port);
+       unsigned char mr1;
+
+       /* Read the mode registers */
+       out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
+       mr1 = in_8(&psc->mode);
+       
+       /* CT{U,L}R are write-only ! */
+       *baud = __res.bi_baudrate ?
+               __res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+
+       /* Parse them */
+       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
+               case MPC52xx_PSC_MODE_5_BITS:   *bits = 5; break;
+               case MPC52xx_PSC_MODE_6_BITS:   *bits = 6; break;
+               case MPC52xx_PSC_MODE_7_BITS:   *bits = 7; break;
+               case MPC52xx_PSC_MODE_8_BITS:
+               default:                        *bits = 8;
+       }
+       
+       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
+               *parity = 'n';
+       else
+               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
+}
+
+static void  
+mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+       struct mpc52xx_psc *psc = PSC(port);
+       unsigned int i, j;
+       
+       /* Disable interrupts */
+       out_be16(&psc->mpc52xx_psc_imr, 0);
+
+       /* Wait the TX buffer to be empty */
+       j = 5000000;    /* Maximum wait */      
+       while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && 
+              --j)
+               udelay(1);
+
+       /* Write all the chars */
+       for ( i=0 ; i<count ; i++ ) {
+       
+               /* Send the char */
+               out_8(&psc->mpc52xx_psc_buffer_8, *s);
+
+               /* Line return handling */
+               if ( *s++ == '\n' )
+                       out_8(&psc->mpc52xx_psc_buffer_8, '\r');
+               
+               /* Wait the TX buffer to be empty */
+               j = 20000;      /* Maximum wait */      
+               while (!(in_be16(&psc->mpc52xx_psc_status) & 
+                        MPC52xx_PSC_SR_TXEMP) && --j)
+                       udelay(1);
+       }
+
+       /* Restore interrupt state */
+       out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static int __init
+mpc52xx_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port = &mpc52xx_uart_ports[co->index];
+
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
+               return -EINVAL;
+       
+       /* Basic port init. Needed since we use some uart_??? func before
+        * real init for early access */
+       port->lock      = SPIN_LOCK_UNLOCKED;
+       port->uartclk   = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
+       port->ops       = &mpc52xx_uart_ops;
+       port->mapbase   = MPC52xx_PSCx(co->index);
+
+               /* We ioremap ourself */
+       port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
+       if (port->membase == NULL) {
+               release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+               return -EBUSY;
+       }
+
+       /* Setup the port parameters accoding to options */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+extern struct uart_driver mpc52xx_uart_driver;
+
+static struct console mpc52xx_console = {
+       .name   = "ttyS",
+       .write  = mpc52xx_console_write,
+       .device = uart_console_device,
+       .setup  = mpc52xx_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,   /* Specified on the cmdline (e.g. console=ttyS0 ) */
+       .data   = &mpc52xx_uart_driver,
+};
+
+       
+static int __init 
+mpc52xx_console_init(void)
+{
+       register_console(&mpc52xx_console);
+       return 0;
+}
+
+console_initcall(mpc52xx_console_init);
+
+#define MPC52xx_PSC_CONSOLE &mpc52xx_console
+#else
+#define MPC52xx_PSC_CONSOLE NULL
+#endif
+
+
+/* ======================================================================== */
+/* UART Driver                                                              */
+/* ======================================================================== */
+
+static struct uart_driver mpc52xx_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "mpc52xx_psc_uart",
+       .dev_name       = "ttyS",
+       .devfs_name     = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = MPC52xx_PSC_MAXNUM,
+       .cons           = MPC52xx_PSC_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* OCP Driver                                                               */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_uart_probe(struct ocp_device *ocp)
+{
+       struct uart_port *port = NULL;
+       int idx, ret;
+
+       /* Get the corresponding port struct */
+       idx = ocp->def->index;
+       if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
+               return -EINVAL;
+       
+       port = &mpc52xx_uart_ports[idx];
+
+       /* Init the port structure */
+       port->lock      = SPIN_LOCK_UNLOCKED;
+       port->mapbase   = ocp->def->paddr;
+       port->irq       = ocp->def->irq;
+       port->uartclk   = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
+       port->fifosize  = 255; /* Should be 512 ! But it can't be */
+                              /* stored in a unsigned char       */
+       port->iotype    = UPIO_MEM;
+       port->flags     = UPF_BOOT_AUTOCONF |
+                         ( uart_console(port) ? 0 : UPF_IOREMAP );
+       port->line      = idx;
+       port->ops       = &mpc52xx_uart_ops;
+       port->read_status_mask = 0;
+       
+       /* Requests the mem & irqs */
+       /* Unlike other serial drivers, we reserve the resources here, so we
+        * can detect early if multiple drivers uses the same PSC. Special
+        * care must be taken with the console PSC
+        */
+       ret = request_irq(
+               port->irq, mpc52xx_uart_int,
+               SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
+       if (ret)
+               goto error;
+
+       ret = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
+                                "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+       if (ret)
+               goto free_irq;
+
+       /* Add the port to the uart sub-system */
+       ret = uart_add_one_port(&mpc52xx_uart_driver, port);
+       if (ret)
+               goto release_mem;
+
+       ocp_set_drvdata(ocp, (void*)port);
+
+       return 0;
+
+
+free_irq:
+       free_irq(port->irq, mpc52xx_uart_int);
+
+release_mem:
+       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+
+error:
+       if (uart_console(port))
+               printk( "mpc52xx_uart.c: Error during resource alloction for "
+                       "the console port !!! Check that the console PSC is "
+                       "not used by another OCP driver !!!\n" );
+
+       return ret;
+}
+
+static void
+mpc52xx_uart_remove(struct ocp_device *ocp)
+{
+       struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+
+       ocp_set_drvdata(ocp, NULL);
+
+       if (port) {
+               uart_remove_one_port(&mpc52xx_uart_driver, port);
+               release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+               free_irq(port->irq, mpc52xx_uart_int);
+       }
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_uart_suspend(struct ocp_device *ocp, u32 state)
+{
+       struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+
+       uart_suspend_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+
+static int
+mpc52xx_uart_resume(struct ocp_device *ocp)
+{
+       struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
+
+       uart_resume_port(&mpc52xx_uart_driver, port);
+
+       return 0;
+}
+#endif
+
+static struct ocp_device_id mpc52xx_uart_ids[] __devinitdata = {
+       { .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_PSC_UART },
+       { .vendor = OCP_VENDOR_INVALID /* Terminating entry */ }
+};
+
+MODULE_DEVICE_TABLE(ocp, mpc52xx_uart_ids);
+
+static struct ocp_driver mpc52xx_uart_ocp_driver = {
+       .name           = "mpc52xx_psc_uart",
+       .id_table       = mpc52xx_uart_ids,
+       .probe          = mpc52xx_uart_probe,
+       .remove         = mpc52xx_uart_remove,
+#ifdef CONFIG_PM
+       .suspend        = mpc52xx_uart_suspend,
+       .resume         = mpc52xx_uart_resume,
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_uart_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
+
+       ret = uart_register_driver(&mpc52xx_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = ocp_register_driver(&mpc52xx_uart_ocp_driver);
+
+       return ret;
+}
+
+static void __exit
+mpc52xx_uart_exit(void)
+{
+       ocp_unregister_driver(&mpc52xx_uart_ocp_driver);
+       uart_unregister_driver(&mpc52xx_uart_driver);
+}
+
+
+module_init(mpc52xx_uart_init);
+module_exit(mpc52xx_uart_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
new file mode 100644 (file)
index 0000000..98b96c5
--- /dev/null
@@ -0,0 +1,1194 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * 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., 1500 Crittenden Lane,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/sysrq.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h> /* for mdelay */
+#include <linux/miscdevice.h>
+#include <linux/serial_core.h>
+
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/sn_sal.h>
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SN_SAL_MAX_CHARS 120
+
+/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
+ * avoid losing chars, (always has to be a power of 2) */
+#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
+
+#define SN_SAL_UART_FIFO_DEPTH 16
+#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10
+
+/* sn_transmit_chars() calling args */
+#define TRANSMIT_BUFFERED      0
+#define TRANSMIT_RAW           1
+
+/* To use dynamic numbers only and not use the assigned major and minor,
+ * define the following.. */
+/* #define USE_DYNAMIC_MINOR 1 */ /* use dynamic minor number */
+#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */
+
+/* Device name we're using */
+#define DEVICE_NAME "ttySG"
+#define DEVICE_NAME_DYNAMIC "ttySG0"  /* need full name for misc_register */
+/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
+#define DEVICE_MAJOR 204
+#define DEVICE_MINOR 40
+
+/*
+ * Port definition - this kinda drives it all
+ */
+struct sn_cons_port {
+       struct timer_list sc_timer;
+       struct uart_port sc_port;
+       struct sn_sal_ops {
+               int (*sal_puts_raw) (const char *s, int len);
+               int (*sal_puts) (const char *s, int len);
+               int (*sal_getc) (void);
+               int (*sal_input_pending) (void);
+               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
+       } *sc_ops;
+       unsigned long sc_interrupt_timeout;
+       int sc_is_asynch;
+};
+
+static struct sn_cons_port sal_console_port;
+
+/* Only used if USE_DYNAMIC_MINOR is set to 1 */
+static struct miscdevice misc; /* used with misc_register for dynamic */
+
+extern u64 master_node_bedrock_address;
+extern void early_sn_setup(void);
+
+#undef DEBUG
+#ifdef DEBUG
+static int sn_debug_printf(const char *fmt, ...);
+#define DPRINTF(x...) sn_debug_printf(x)
+#else
+#define DPRINTF(x...) do { } while (0)
+#endif
+
+/* Prototypes */
+static int snt_hw_puts_raw(const char *, int);
+static int snt_hw_puts_buffered(const char *, int);
+static int snt_poll_getc(void);
+static int snt_poll_input_pending(void);
+static int snt_sim_puts(const char *, int);
+static int snt_sim_getc(void);
+static int snt_sim_input_pending(void);
+static int snt_intr_getc(void);
+static int snt_intr_input_pending(void);
+static void sn_transmit_chars(struct sn_cons_port *, int);
+
+/* A table for polling:
+ */
+static struct sn_sal_ops poll_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_raw,
+       .sal_getc = snt_poll_getc,
+       .sal_input_pending = snt_poll_input_pending
+};
+
+/* A table for the simulator */
+static struct sn_sal_ops sim_ops = {
+       .sal_puts_raw = snt_sim_puts,
+       .sal_puts = snt_sim_puts,
+       .sal_getc = snt_sim_getc,
+       .sal_input_pending = snt_sim_input_pending
+};
+
+/* A table for interrupts enabled */
+static struct sn_sal_ops intr_ops = {
+       .sal_puts_raw = snt_hw_puts_raw,
+       .sal_puts = snt_hw_puts_buffered,
+       .sal_getc = snt_intr_getc,
+       .sal_input_pending = snt_intr_input_pending,
+       .sal_wakeup_transmit = sn_transmit_chars
+};
+
+/* the console does output in two distinctly different ways:
+ * synchronous (raw) and asynchronous (buffered).  initally, early_printk
+ * does synchronous output.  any data written goes directly to the SAL
+ * to be output (incidentally, it is internally buffered by the SAL)
+ * after interrupts and timers are initialized and available for use,
+ * the console init code switches to asynchronous output.  this is
+ * also the earliest opportunity to begin polling for console input.
+ * after console initialization, console output and tty (serial port)
+ * output is buffered and sent to the SAL asynchronously (either by
+ * timer callback or by UART interrupt) */
+
+
+/* routines for running the console in polling mode */
+
+/**
+ * snt_poll_getc - Get a character from the console in polling mode
+ *
+ */
+static int
+snt_poll_getc(void)
+{
+       int ch;
+
+       ia64_sn_console_getc(&ch);
+       return ch;
+}
+
+/**
+ * snt_poll_input_pending - Check if any input is waiting - polling mode.
+ *
+ */
+static int
+snt_poll_input_pending(void)
+{
+       int status, input;
+
+       status = ia64_sn_console_check(&input);
+       return !status && input;
+}
+
+/* routines for running the console on the simulator */
+
+/**
+ * snt_sim_puts - send to the console, used in simulator mode
+ * @str: String to send
+ * @count: length of string
+ *
+ */
+static int
+snt_sim_puts(const char *str, int count)
+{
+       int counter = count;
+
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+       /* This is an easy way to pre-pend the output to know whether the output
+        * was done via sal or directly */
+       writeb('[', master_node_bedrock_address + (UART_TX << 3));
+       writeb('+', master_node_bedrock_address + (UART_TX << 3));
+       writeb(']', master_node_bedrock_address + (UART_TX << 3));
+       writeb(' ', master_node_bedrock_address + (UART_TX << 3));
+#endif                         /* FLAG_DIRECT_CONSOLE_WRITES */
+       while (counter > 0) {
+               writeb(*str, master_node_bedrock_address + (UART_TX << 3));
+               counter--;
+               str++;
+       }
+       return count;
+}
+
+/**
+ * snt_sim_getc - Get character from console in simulator mode
+ *
+ */
+static int
+snt_sim_getc(void)
+{
+       return readb(master_node_bedrock_address + (UART_RX << 3));
+}
+
+/**
+ * snt_sim_input_pending - Check if there is input pending in simulator mode
+ *
+ */
+static int
+snt_sim_input_pending(void)
+{
+       return readb(master_node_bedrock_address +
+                    (UART_LSR << 3)) & UART_LSR_DR;
+}
+
+/* routines for an interrupt driven console (normal) */
+
+/**
+ * snt_intr_getc - Get a character from the console, interrupt mode
+ *
+ */
+static int
+snt_intr_getc(void)
+{
+       return ia64_sn_console_readc();
+}
+
+/**
+ * snt_intr_input_pending - Check if input is pending, interrupt mode
+ *
+ */
+static int
+snt_intr_input_pending(void)
+{
+       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
+}
+
+/* these functions are polled and interrupt */
+
+/**
+ * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int
+snt_hw_puts_raw(const char *s, int len)
+{
+       /* this will call the PROM and not return until this is done */
+       return ia64_sn_console_putb(s, len);
+}
+
+/**
+ * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
+ * @s: String
+ * @len: Length
+ *
+ */
+static int
+snt_hw_puts_buffered(const char *s, int len)
+{
+       /* queue data to the PROM */
+       return ia64_sn_console_xmit_chars((char *)s, len);
+}
+
+/* uart interface structs
+ * These functions are associated with the uart_port that the serial core
+ * infrastructure calls.
+ *
+ * Note: Due to how the console works, many routines are no-ops.
+ */
+
+/**
+ * snp_type - What type of console are we?
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *
+snp_type(struct uart_port *port)
+{
+       return ("SGI SN L1");
+}
+
+/**
+ * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
+ * @port: Port to operate on (we ignore since we only have one port)
+ *
+ */
+static unsigned int
+snp_tx_empty(struct uart_port *port)
+{
+       return 1;
+}
+
+/**
+ * snp_stop_tx - stop the transmitter - no-op for us
+ * @port: Port to operat eon - we ignore - no-op function
+ * @tty_stop: Set to 1 if called via uart_stop
+ *
+ */
+static void
+snp_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+}
+
+/**
+ * snp_release_port - Free i/o and resources for port - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void
+snp_release_port(struct uart_port *port)
+{
+}
+
+/**
+ * snp_enable_ms - Force modem status interrupts on - no-op for us
+ * @port: Port to operate on - we ignore - no-op function
+ *
+ */
+static void
+snp_enable_ms(struct uart_port *port)
+{
+}
+
+/**
+ * snp_shutdown - shut down the port - free irq and disable - no-op for us
+ * @port: Port to shut down - we ignore
+ *
+ */
+static void
+snp_shutdown(struct uart_port *port)
+{
+}
+
+/**
+ * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
+ * @port: Port to operate on - we ignore
+ * @mctrl: Lines to set/unset - we ignore
+ *
+ */
+static void
+snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/**
+ * snp_get_mctrl - get contorl line info, we just return a static value
+ * @port: port to operate on - we only have one port so we ignore this
+ *
+ */
+static unsigned int
+snp_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
+}
+
+/**
+ * snp_stop_rx - Stop the receiver - we ignor ethis
+ * @port: Port to operate on - we ignore
+ *
+ */
+static void
+snp_stop_rx(struct uart_port *port)
+{
+}
+
+/**
+ * snp_start_tx - Start transmitter
+ * @port: Port to operate on
+ * @tty_stop: Set to 1 if called via uart_start
+ *
+ */
+static void
+snp_start_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       if (sal_console_port.sc_ops->sal_wakeup_transmit)
+               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port, TRANSMIT_BUFFERED);
+
+}
+
+/**
+ * snp_break_ctl - handle breaks - ignored by us
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void
+snp_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+/**
+ * snp_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int
+snp_startup(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_set_termios - set termios stuff - we ignore these
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+snp_set_termios(struct uart_port *port, struct termios *termios,
+               struct termios *old)
+{
+}
+
+/**
+ * snp_request_port - allocate resources for port - ignored by us
+ * @port: port to operate on
+ *
+ */
+static int
+snp_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/**
+ * snp_config_port - allocate resources, set up - we ignore,  we're always on
+ * @port: Port to operate on
+ * @flags: flags used for port setup
+ *
+ */
+static void
+snp_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* Associate the uart functions above - given to serial core */
+
+static struct uart_ops sn_console_ops = {
+       .tx_empty = snp_tx_empty,
+       .set_mctrl = snp_set_mctrl,
+       .get_mctrl = snp_get_mctrl,
+       .stop_tx = snp_stop_tx,
+       .start_tx = snp_start_tx,
+       .stop_rx = snp_stop_rx,
+       .enable_ms = snp_enable_ms,
+       .break_ctl = snp_break_ctl,
+       .startup = snp_startup,
+       .shutdown = snp_shutdown,
+       .set_termios = snp_set_termios,
+       .pm = NULL,
+       .type = snp_type,
+       .release_port = snp_release_port,
+       .request_port = snp_request_port,
+       .config_port = snp_config_port,
+       .verify_port = NULL,
+};
+
+/* End of uart struct functions and defines */
+
+#ifdef DEBUG
+
+/**
+ * sn_debug_printf - close to hardware debugging printf
+ * @fmt: printf format
+ *
+ * This is as "close to the metal" as we can get, used when the driver
+ * itself may be broken.
+ *
+ */
+static int
+sn_debug_printf(const char *fmt, ...)
+{
+       static char printk_buf[1024];
+       int printed_len;
+       va_list args;
+
+       va_start(args, fmt);
+       printed_len = vsnprintf(printk_buf, sizeof (printk_buf), fmt, args);
+
+       if (!sal_console_port.sc_ops) {
+               if (IS_RUNNING_ON_SIMULATOR())
+                       sal_console_port.sc_ops = &sim_ops;
+               else
+                       sal_console_port.sc_ops = &poll_ops;
+
+               early_sn_setup();
+       }
+       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
+
+       va_end(args);
+       return printed_len;
+}
+#endif /* DEBUG */
+
+/*
+ * Interrupt handling routines.
+ */
+
+
+/**
+ * sn_receive_chars - Grab characters, pass them to tty layer
+ * @port: Port to operate on
+ * @regs: Saved registers (needed by uart_handle_sysrq_char)
+ *
+ * Note: If we're not registered with the serial core infrastructure yet,
+ * we don't try to send characters to it...
+ *
+ */
+static void
+sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs)
+{
+       int ch;
+       struct tty_struct *tty;
+
+       if (!port) {
+               printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
+               return;
+       }
+
+       if (!port->sc_ops) {
+               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
+               return;
+       }
+
+       if (port->sc_port.info) {
+               /* The serial_core stuffs are initilized, use them */
+               tty = port->sc_port.info->tty;
+       }
+       else {
+               /* Not registered yet - can't pass to tty layer.  */
+               tty = NULL;
+       }
+
+       while (port->sc_ops->sal_input_pending()) {
+               ch = port->sc_ops->sal_getc();
+               if (ch < 0) {
+                       printk(KERN_ERR "sn_console: An error occured while "
+                              "obtaining data from the console (0x%0x)\n", ch);
+                       break;
+               }
+#if defined(CONFIG_SERIAL_SGI_L1_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+               if (uart_handle_sysrq_char(&port->sc_port, ch, regs))
+                       continue;
+#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+               /* record the character to pass up to the tty layer */
+               if (tty) {
+                       *tty->flip.char_buf_ptr = ch;
+                       *tty->flip.flag_buf_ptr = TTY_NORMAL;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
+                       if (tty->flip.count == TTY_FLIPBUF_SIZE)
+                               break;
+               }
+               else {
+               }
+               port->sc_port.icount.rx++;
+       }
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+}
+
+/**
+ * sn_transmit_chars - grab characters from serial core, send off
+ * @port: Port to operate on
+ * @raw: Transmit raw or buffered
+ *
+ * Note: If we're early, before we're registered with serial core, the
+ * writes are going through sn_sal_console_write because that's how
+ * register_console has been set up.  We currently could have asynch
+ * polls calling this function due to sn_sal_switch_to_asynch but we can
+ * ignore them until we register with the serial core stuffs.
+ *
+ */
+static void
+sn_transmit_chars(struct sn_cons_port *port, int raw)
+{
+       int xmit_count, tail, head, loops, ii;
+       int result;
+       char *start;
+       struct circ_buf *xmit;
+
+       if (!port)
+               return;
+
+       BUG_ON(!port->sc_is_asynch);
+
+       if (port->sc_port.info) {
+               /* We're initilized, using serial core infrastructure */
+               xmit = &port->sc_port.info->xmit;
+       }
+       else {
+               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
+                * initilized yet.  Just return.  Writes are going through
+                * sn_sal_console_write (due to register_console) at this time.
+                */
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
+               /* Nothing to do. */
+               return;
+       }
+
+       head = xmit->head;
+       tail = xmit->tail;
+       start = &xmit->buf[tail];
+
+       /* twice around gets the tail to the end of the buffer and
+        * then to the head, if needed */
+       loops = (head < tail) ? 2 : 1;
+
+       for (ii = 0; ii < loops; ii++) {
+               xmit_count = (head < tail) ?
+                   (UART_XMIT_SIZE - tail) : (head - tail);
+
+               if (xmit_count > 0) {
+                       if (raw == TRANSMIT_RAW)
+                               result =
+                                   port->sc_ops->sal_puts_raw(start,
+                                                              xmit_count);
+                       else
+                               result =
+                                   port->sc_ops->sal_puts(start, xmit_count);
+#ifdef DEBUG
+                       if (!result)
+                               DPRINTF("`");
+#endif
+                       if (result > 0) {
+                               xmit_count -= result;
+                               port->sc_port.icount.tx += result;
+                               tail += result;
+                               tail &= UART_XMIT_SIZE - 1;
+                               xmit->tail = tail;
+                               start = &xmit->buf[tail];
+                       }
+               }
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&port->sc_port);
+
+       if (uart_circ_empty(xmit))
+               snp_stop_tx(&port->sc_port, 0); /* no-op for us */
+}
+
+/**
+ * sn_sal_interrupt - Handle console interrupts
+ * @irq: irq #, useful for debug statements
+ * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
+ * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char
+ *
+ */
+static irqreturn_t
+sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *) dev_id;
+       unsigned long flags;
+       int status = ia64_sn_console_intr_status();
+
+       if (!port)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+       if (status & SAL_CONSOLE_INTR_RECV) {
+               sn_receive_chars(port, regs);
+       }
+       if (status & SAL_CONSOLE_INTR_XMIT) {
+               sn_transmit_chars(port, TRANSMIT_BUFFERED);
+       }
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+       return IRQ_HANDLED;
+}
+
+/**
+ * sn_sal_connect_interrupt - Request interrupt, handled by sn_sal_interrupt
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * returns the console irq if interrupt is successfully registered, else 0
+ *
+ */
+static int
+sn_sal_connect_interrupt(struct sn_cons_port *port)
+{
+       if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, SA_INTERRUPT,
+                       "SAL console driver", port) >= 0) {
+               return SGI_UART_VECTOR;
+       }
+
+       printk(KERN_INFO "sn_console: console proceeding in polled mode\n");
+       return 0;
+}
+
+/**
+ * sn_sal_timer_poll - this function handles polled console mode
+ * @data: A pointer to our sn_cons_port (which contains the uart port)
+ *
+ * data is the pointer that init_timer will store for us.  This function is
+ * associated with init_timer to see if there is any console traffic.
+ * Obviously not used in interrupt mode
+ *
+ */
+static void
+sn_sal_timer_poll(unsigned long data)
+{
+       struct sn_cons_port *port = (struct sn_cons_port *) data;
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       if (!port->sc_port.irq) {
+               spin_lock_irqsave(&port->sc_port.lock, flags);
+               sn_receive_chars(port, NULL);
+               sn_transmit_chars(port, TRANSMIT_RAW);
+               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+               mod_timer(&port->sc_timer,
+                         jiffies + port->sc_interrupt_timeout);
+       }
+}
+
+/*
+ * Boot-time initialization code
+ */
+
+/**
+ * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * So this is used by sn_sal_serial_console_init (early on, before we're
+ * registered with serial core).  It's also used by sn_sal_module_init
+ * right after we've registered with serial core.  The later only happens
+ * if we didn't already come through here via sn_sal_serial_console_init.
+ *
+ */
+static void __init
+sn_sal_switch_to_asynch(struct sn_cons_port *port)
+{
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       DPRINTF("sn_console: about to switch to asynchronous console\n");
+
+       /* without early_printk, we may be invoked late enough to race
+        * with other cpus doing console IO at this point, however
+        * console interrupts will never be enabled */
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+
+       /* early_printk invocation may have done this for us */
+       if (!port->sc_ops) {
+               if (IS_RUNNING_ON_SIMULATOR())
+                       port->sc_ops = &sim_ops;
+               else
+                       port->sc_ops = &poll_ops;
+       }
+
+       /* we can't turn on the console interrupt (as request_irq
+        * calls kmalloc, which isn't set up yet), so we rely on a
+        * timer to poll for input and push data from the console
+        * buffer.
+        */
+       init_timer(&port->sc_timer);
+       port->sc_timer.function = sn_sal_timer_poll;
+       port->sc_timer.data = (unsigned long) port;
+
+       if (IS_RUNNING_ON_SIMULATOR())
+               port->sc_interrupt_timeout = 6;
+       else {
+               /* 960cps / 16 char FIFO = 60HZ
+                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
+               port->sc_interrupt_timeout =
+                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
+       }
+       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
+
+       port->sc_is_asynch = 1;
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+}
+
+/**
+ * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
+ * @port: Our sn_cons_port (which contains the uart port)
+ *
+ * In sn_sal_module_init, after we're registered with serial core and
+ * the port is added, this function is called to switch us to interrupt
+ * mode.  We were previously in asynch/polling mode (using init_timer).
+ *
+ * We attempt to switch to interrupt mode here by calling
+ * sn_sal_connect_interrupt.  If that works out, we enable receive interrupts.
+ */
+static void __init
+sn_sal_switch_to_interrupts(struct sn_cons_port *port)
+{
+       int irq;
+       unsigned long flags;
+
+       if (!port)
+               return;
+
+       DPRINTF("sn_console: switching to interrupt driven console\n");
+
+       spin_lock_irqsave(&port->sc_port.lock, flags);
+
+       irq = sn_sal_connect_interrupt(port);
+
+       if (irq) {
+               port->sc_port.irq = irq;
+               port->sc_ops = &intr_ops;
+
+               /* turn on receive interrupts */
+               ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+       }
+       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+}
+
+/*
+ * Kernel console definitions
+ */
+
+#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
+static void sn_sal_console_write(struct console *, const char *, unsigned);
+static int __init sn_sal_console_setup(struct console *, char *);
+extern struct uart_driver sal_console_uart;
+extern struct tty_driver *uart_console_device(struct console *, int *);
+
+static struct console sal_console = {
+       .name = DEVICE_NAME,
+       .write = sn_sal_console_write,
+       .device = uart_console_device,
+       .setup = sn_sal_console_setup,
+       .index = -1, /* unspecified */
+       .data = &sal_console_uart,
+};
+
+#define SAL_CONSOLE    &sal_console
+#else
+#define SAL_CONSOLE    0
+#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE */
+
+static struct uart_driver sal_console_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "sn_console",
+       .dev_name = DEVICE_NAME,
+       .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */
+       .minor = 0,
+       .nr = 1,        /* one port */
+       .cons = SAL_CONSOLE,
+};
+
+/**
+ * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core
+ *
+ * Before this is called, we've been printing kernel messages in a special
+ * early mode not making use of the serial core infrastructure.  When our
+ * driver is loaded for real, we register the driver and port with serial
+ * core and try to enable interrupt driven mode.
+ *
+ */
+static int __init
+sn_sal_module_init(void)
+{
+       int retval;
+
+       printk(KERN_INFO "sn_console: Console driver init\n");
+
+       if (!ia64_platform_is("sn2"))
+               return -ENODEV;
+
+       if (USE_DYNAMIC_MINOR == 1) {
+               misc.minor = MISC_DYNAMIC_MINOR;
+               misc.name = DEVICE_NAME_DYNAMIC;
+               retval = misc_register(&misc);
+               if (retval != 0) {
+                       printk("Failed to register console device using misc_register.\n");
+                       return -ENODEV;
+               }
+               sal_console_uart.major = MISC_MAJOR;
+               sal_console_uart.minor = misc.minor;
+       }
+       else {
+               sal_console_uart.major = DEVICE_MAJOR;
+               sal_console_uart.minor = DEVICE_MINOR;
+       }
+
+       /* We register the driver and the port before switching to interrupts
+    * or async above so the proper uart structures are populated */
+
+       if (uart_register_driver(&sal_console_uart) < 0) {
+               printk("ERROR sn_sal_module_init failed uart_register_driver, line %d\n",
+                 __LINE__);
+               return -ENODEV;
+       }
+
+       sal_console_port.sc_port.lock = SPIN_LOCK_UNLOCKED;
+
+       /* Setup the port struct with the minimum needed */
+       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
+       sal_console_port.sc_port.type = PORT_16550A;
+       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
+       sal_console_port.sc_port.ops = &sn_console_ops;
+       sal_console_port.sc_port.line = 0;
+
+       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
+               /* error - not sure what I'd do - so I'll do nothing */
+               printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__);
+       }
+
+       /* when this driver is compiled in, the console initialization
+        * will have already switched us into asynchronous operation
+        * before we get here through the module initcalls */
+       if (!sal_console_port.sc_is_asynch) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+       }
+
+       /* at this point (module_init) we can try to turn on interrupts */
+       if (!IS_RUNNING_ON_SIMULATOR()) {
+               sn_sal_switch_to_interrupts(&sal_console_port);
+       }
+       return 0;
+}
+
+/**
+ * sn_sal_module_exit - When we're unloaded, remove the driver/port
+ *
+ */
+static void __exit
+sn_sal_module_exit(void)
+{
+       del_timer_sync(&sal_console_port.sc_timer);
+       uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port);
+       uart_unregister_driver(&sal_console_uart);
+       misc_deregister(&misc);
+}
+
+module_init(sn_sal_module_init);
+module_exit(sn_sal_module_exit);
+
+#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
+
+/**
+ * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
+ * @puts_raw : puts function to do the writing
+ * @s: input string
+ * @count: length
+ *
+ * We need a \r ahead of every \n for direct writes through
+ * ia64_sn_console_putb (what sal_puts_raw below actually does).
+ *
+ */
+
+static void puts_raw_fixed(int (*puts_raw) (const char *s, int len), const char *s, int count)
+{
+       const char *s1;
+
+       /* Output '\r' before each '\n' */
+       while ((s1 = memchr(s, '\n', count)) != NULL) {
+               puts_raw(s, s1 - s);
+               puts_raw("\r\n", 2);
+               count -= s1 + 1 - s;
+               s = s1 + 1;
+       }
+       puts_raw(s, count);
+}
+
+/**
+ * sn_sal_console_write - Print statements before serial core available
+ * @console: Console to operate on - we ignore since we have just one
+ * @s: String to send
+ * @count: length
+ *
+ * This is referenced in the console struct.  It is used for early
+ * console printing before we register with serial core and for things
+ * such as kdb.  The console_lock must be held when we get here.
+ *
+ * This function has some code for trying to print output even if the lock
+ * is held.  We try to cover the case where a lock holder could have died.
+ * We don't use this special case code if we're not registered with serial
+ * core yet.  After we're registered with serial core, the only time this
+ * function would be used is for high level kernel output like magic sys req,
+ * kdb, and printk's.
+ */
+static void
+sn_sal_console_write(struct console *co, const char *s, unsigned count)
+{
+       unsigned long flags = 0;
+       struct sn_cons_port *port = &sal_console_port;
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+       static int stole_lock = 0;
+#endif
+
+       BUG_ON(!port->sc_is_asynch);
+
+       /* We can't look at the xmit buffer if we're not registered with serial core
+        *  yet.  So only do the fancy recovery after registering
+        */
+       if (port->sc_port.info) {
+
+               /* somebody really wants this output, might be an
+               * oops, kdb, panic, etc.  make sure they get it. */
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+               if (spin_is_locked(&port->sc_port.lock)) {
+                       int lhead = port->sc_port.info->xmit.head;
+                       int ltail = port->sc_port.info->xmit.tail;
+                       int counter, got_lock = 0;
+
+                       /*
+                        * We attempt to determine if someone has died with the
+                        * lock. We wait ~20 secs after the head and tail ptrs
+                        * stop moving and assume the lock holder is not functional
+                        * and plow ahead. If the lock is freed within the time out
+                        * period we re-get the lock and go ahead normally. We also
+                        * remember if we have plowed ahead so that we don't have
+                        * to wait out the time out period again - the asumption
+                        * is that we will time out again.
+                        */
+
+                       for (counter = 0; counter < 150; mdelay(125), counter++) {
+                               if (!spin_is_locked(&port->sc_port.lock) || stole_lock) {
+                                       if (!stole_lock) {
+                                               spin_lock_irqsave(&port->sc_port.lock, flags);
+                                               got_lock = 1;
+                                       }
+                                       break;
+                               }
+                               else {
+                                       /* still locked */
+                                       if ((lhead != port->sc_port.info->xmit.head) || (ltail != port->sc_port.info->xmit.tail)) {
+                                               lhead = port->sc_port.info->xmit.head;
+                                               ltail = port->sc_port.info->xmit.tail;
+                                               counter = 0;
+                                       }
+                               }
+                       }
+                       /* flush anything in the serial core xmit buffer, raw */
+                       sn_transmit_chars(port, 1);
+                       if (got_lock) {
+                               spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                               stole_lock = 0;
+                       }
+                       else {
+                               /* fell thru */
+                               stole_lock = 1;
+                       }
+                       puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+               }
+               else {
+                       stole_lock = 0;
+#endif
+                       spin_lock_irqsave(&port->sc_port.lock, flags);
+                       sn_transmit_chars(port, 1);
+                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
+
+                       puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+               }
+       }
+       else {
+               /* Not yet registered with serial core - simple case */
+               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+       }
+}
+
+
+/**
+ * sn_sal_console_setup - Set up console for early printing
+ * @co: Console to work with
+ * @options: Options to set
+ *
+ * Altix console doesn't do anything with baud rates, etc, anyway.
+ *
+ * This isn't required since not providing the setup function in the
+ * console struct is ok.  However, other patches like KDB plop something
+ * here so providing it is easier.
+ *
+ */
+static int __init
+sn_sal_console_setup(struct console *co, char *options)
+{
+       return 0;
+}
+
+/**
+ * sn_sal_console_write_early - simple early output routine
+ * @co - console struct
+ * @s - string to print
+ * @count - count
+ *
+ * Simple function to provide early output, before even
+ * sn_sal_serial_console_init is called.  Referenced in the
+ * console struct registerd in sn_serial_console_early_setup.
+ *
+ */
+static void __init
+sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
+{
+       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
+}
+
+/* Used for very early console printing - again, before
+ * sn_sal_serial_console_init is run */
+static struct console sal_console_early __initdata = {
+       .name = "sn_sal",
+       .write = sn_sal_console_write_early,
+       .flags = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+/**
+ * sn_serial_console_early_setup - Sets up early console output support
+ *
+ * Register a console early on...  This is for output before even
+ * sn_sal_serial_cosnole_init is called.  This function is called from
+ * setup.c.  This allows us to do really early polled writes. When
+ * sn_sal_serial_console_init is called, this console is unregistered
+ * and a new one registered.
+ */
+int __init
+sn_serial_console_early_setup(void)
+{
+       if (!ia64_platform_is("sn2"))
+               return -1;
+
+       if (IS_RUNNING_ON_SIMULATOR())
+               sal_console_port.sc_ops = &sim_ops;
+       else
+               sal_console_port.sc_ops = &poll_ops;
+
+       early_sn_setup(); /* Find SAL entry points */
+       register_console(&sal_console_early);
+
+       return 0;
+}
+
+
+/**
+ * sn_sal_serial_console_init - Early console output - set up for register
+ *
+ * This function is called when regular console init happens.  Because we
+ * support even earlier console output with sn_serial_console_early_setup
+ * (called from setup.c directly), this function unregisters the really
+ * early console.
+ *
+ * Note: Even if setup.c doesn't register sal_console_early, unregistering
+ * it here doesn't hurt anything.
+ *
+ */
+static int __init
+sn_sal_serial_console_init(void)
+{
+       if (ia64_platform_is("sn2")) {
+               sn_sal_switch_to_asynch(&sal_console_port);
+               DPRINTF ("sn_sal_serial_console_init : register console\n");
+               register_console(&sal_console);
+               unregister_console(&sal_console_early);
+       }
+       return 0;
+}
+
+console_initcall(sn_sal_serial_console_init);
+
+#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE */
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
new file mode 100644 (file)
index 0000000..0a860dd
--- /dev/null
@@ -0,0 +1,1384 @@
+/*
+ *  linux/drivers/video/pxafb.c
+ *
+ *  Copyright (C) 1999 Eric A. Thomas.
+ *  Copyright (C) 2004 Jean-Frederic Clere.
+ *  Copyright (C) 2004 Ian Campbell.
+ *  Copyright (C) 2004 Jeff Lackey.
+ *   Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas
+ *  which in turn is
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ *             Intel PXA250/210 LCD Controller Frame Buffer Driver
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ *     linux-arm-kernel@lists.arm.linux.org.uk
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxafb.h>
+
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
+
+#include "pxafb.h"
+
+/* Bits which should not be set in machine configuration structures */
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+
+static void (*pxafb_backlight_power)(int);
+static void (*pxafb_lcd_power)(int);
+
+static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+#define PXAFB_OPTIONS_SIZE 256
+static char g_options[PXAFB_OPTIONS_SIZE] __initdata = "";
+#endif
+
+static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       /*
+        * We need to handle two requests being made at the same time.
+        * There are two important cases:
+        *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
+        *     We must perform the unblanking, which will do our REENABLE for us.
+        *  2. When we are blanking, but immediately unblank before we have
+        *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
+        */
+       if (fbi->task_state == C_ENABLE && state == C_REENABLE)
+               state = (u_int) -1;
+       if (fbi->task_state == C_DISABLE && state == C_ENABLE)
+               state = C_REENABLE;
+
+       if (state != (u_int)-1) {
+               fbi->task_state = state;
+               schedule_work(&fbi->task);
+       }
+       local_irq_restore(flags);
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+static int
+pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+                      u_int trans, struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       u_int val, ret = 1;
+
+       if (regno < fbi->palette_size) {
+               if (fbi->fb.var.grayscale) {
+                       val = ((blue >> 8) & 0x00ff);
+               } else {
+                       val  = ((red   >>  0) & 0xf800);
+                       val |= ((green >>  5) & 0x07e0);
+                       val |= ((blue  >> 11) & 0x001f);
+               }
+               fbi->palette_cpu[regno] = val;
+               ret = 0;
+       }
+       return ret;
+}
+
+static int
+pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                  u_int trans, struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       unsigned int val;
+       int ret = 1;
+
+       /*
+        * If inverse mode was selected, invert all the colours
+        * rather than the register number.  The register number
+        * is what you poke into the framebuffer to produce the
+        * colour you requested.
+        */
+       if (fbi->cmap_inverse) {
+               red   = 0xffff - red;
+               green = 0xffff - green;
+               blue  = 0xffff - blue;
+       }
+
+       /*
+        * If greyscale is true, then we convert the RGB value
+        * to greyscale no matter what visual we are using.
+        */
+       if (fbi->fb.var.grayscale)
+               red = green = blue = (19595 * red + 38470 * green +
+                                       7471 * blue) >> 16;
+
+       switch (fbi->fb.fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /*
+                * 16-bit True Colour.  We encode the RGB value
+                * according to the RGB bitfield information.
+                */
+               if (regno < 16) {
+                       u32 *pal = fbi->fb.pseudo_palette;
+
+                       val  = chan_to_field(red, &fbi->fb.var.red);
+                       val |= chan_to_field(green, &fbi->fb.var.green);
+                       val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+                       pal[regno] = val;
+                       ret = 0;
+               }
+               break;
+
+       case FB_VISUAL_STATIC_PSEUDOCOLOR:
+       case FB_VISUAL_PSEUDOCOLOR:
+               ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ *  pxafb_bpp_to_lccr3():
+ *    Convert a bits per pixel value to the correct bit pattern for LCCR3
+ */
+static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
+{
+        int ret = 0;
+        switch (var->bits_per_pixel) {
+        case 1:  ret = LCCR3_1BPP; break;
+        case 2:  ret = LCCR3_2BPP; break;
+        case 4:  ret = LCCR3_4BPP; break;
+        case 8:  ret = LCCR3_8BPP; break;
+        case 16: ret = LCCR3_16BPP; break;
+        }
+        return ret;
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ *  pxafb_display_dma_period()
+ *    Calculate the minimum period (in picoseconds) between two DMA
+ *    requests for the LCD controller.  If we hit this, it means we're
+ *    doing nothing but LCD DMA.
+ */
+static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
+{
+       /*
+        * Period = pixclock * bits_per_byte * bytes_per_transfer
+        *              / memory_bits_per_pixel;
+        */
+       return var->pixclock * 8 * 16 / var->bits_per_pixel;
+}
+
+extern unsigned int get_clk_frequency_khz(int info);
+#endif
+
+/*
+ *  pxafb_check_var():
+ *    Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *    if it's too big, return -EINVAL.
+ *
+ *    Round up in the following order: bits_per_pixel, xres,
+ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ *    bitfields, horizontal timing, vertical timing.
+ */
+static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+
+       if (var->xres < MIN_XRES)
+               var->xres = MIN_XRES;
+       if (var->yres < MIN_YRES)
+               var->yres = MIN_YRES;
+       if (var->xres > fbi->max_xres)
+               var->xres = fbi->max_xres;
+       if (var->yres > fbi->max_yres)
+               var->yres = fbi->max_yres;
+       var->xres_virtual =
+               max(var->xres_virtual, var->xres);
+       var->yres_virtual =
+               max(var->yres_virtual, var->yres);
+
+        /*
+        * Setup the RGB parameters for this display.
+        *
+        * The pixel packing format is described on page 7-11 of the
+        * PXA2XX Developer's Manual.
+         */
+       if (var->bits_per_pixel == 16) {
+               var->red.offset   = 11; var->red.length   = 5;
+               var->green.offset = 5;  var->green.length = 6;
+               var->blue.offset  = 0;  var->blue.length  = 5;
+               var->transp.offset = var->transp.length = 0;
+       } else {
+               var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+               var->red.length   = 8;
+               var->green.length = 8;
+               var->blue.length  = 8;
+               var->transp.length = 0;
+       }
+
+#ifdef CONFIG_CPU_FREQ
+       DPRINTK("dma period = %d ps, clock = %d kHz\n",
+               pxafb_display_dma_period(var),
+               get_clk_frequency_khz(0));
+#endif
+
+       return 0;
+}
+
+static inline void pxafb_set_truecolor(u_int is_true_color)
+{
+       DPRINTK("true_color = %d\n", is_true_color);
+       // do your machine-specific setup if needed
+}
+
+/*
+ * pxafb_set_par():
+ *     Set the user defined part of the display for the specified console
+ */
+static int pxafb_set_par(struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       struct fb_var_screeninfo *var = &info->var;
+       unsigned long palette_mem_size;
+
+       DPRINTK("set_par\n");
+
+       if (var->bits_per_pixel == 16)
+               fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+       else if (!fbi->cmap_static)
+               fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else {
+               /*
+                * Some people have weird ideas about wanting static
+                * pseudocolor maps.  I suspect their user space
+                * applications are broken.
+                */
+               fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+       }
+
+       fbi->fb.fix.line_length = var->xres_virtual *
+                                 var->bits_per_pixel / 8;
+       if (var->bits_per_pixel == 16)
+               fbi->palette_size = 0;
+       else
+               fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
+
+       palette_mem_size = fbi->palette_size * sizeof(u16);
+
+       DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+       fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+       fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+       /*
+        * Set (any) board control register to handle new color depth
+        */
+       pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+
+       if (fbi->fb.var.bits_per_pixel == 16)
+               fb_dealloc_cmap(&fbi->fb.cmap);
+       else
+               fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
+
+       pxafb_activate_var(var, fbi);
+
+       return 0;
+}
+
+/*
+ * Formal definition of the VESA spec:
+ *  On
+ *     This refers to the state of the display when it is in full operation
+ *  Stand-By
+ *     This defines an optional operating state of minimal power reduction with
+ *     the shortest recovery time
+ *  Suspend
+ *     This refers to a level of power management in which substantial power
+ *     reduction is achieved by the display.  The display can have a longer
+ *     recovery time from this state than from the Stand-by state
+ *  Off
+ *     This indicates that the display is consuming the lowest level of power
+ *     and is non-operational. Recovery from this state may optionally require
+ *     the user to manually power on the monitor
+ *
+ *  Now, the fbdev driver adds an additional state, (blank), where they
+ *  turn off the video (maybe by colormap tricks), but don't mess with the
+ *  video itself: think of it semantically between on and Stand-By.
+ *
+ *  So here's what we should do in our fbdev blank routine:
+ *
+ *     VESA_NO_BLANKING (mode 0)       Video on,  front/back light on
+ *     VESA_VSYNC_SUSPEND (mode 1)     Video on,  front/back light off
+ *     VESA_HSYNC_SUSPEND (mode 2)     Video on,  front/back light off
+ *     VESA_POWERDOWN (mode 3)         Video off, front/back light off
+ *
+ *  This will match the matrox implementation.
+ */
+
+/*
+ * pxafb_blank():
+ *     Blank the display by setting all palette values to zero.  Note, the
+ *     16 bpp mode does not really use the palette, so this will not
+ *      blank the display in all modes.
+ */
+static int pxafb_blank(int blank, struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       int i;
+
+       DPRINTK("pxafb_blank: blank=%d\n", blank);
+
+       switch (blank) {
+       case VESA_POWERDOWN:
+       case VESA_VSYNC_SUSPEND:
+       case VESA_HSYNC_SUSPEND:
+               if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+                   fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+                       for (i = 0; i < fbi->palette_size; i++)
+                               pxafb_setpalettereg(i, 0, 0, 0, 0, info);
+
+               pxafb_schedule_work(fbi, C_DISABLE);
+               //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+               break;
+
+       case VESA_NO_BLANKING:
+               //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+               if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+                   fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+                       fb_set_cmap(&fbi->fb.cmap, info);
+               pxafb_schedule_work(fbi, C_ENABLE);
+       }
+       return 0;
+}
+
+static struct fb_ops pxafb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = pxafb_check_var,
+       .fb_set_par     = pxafb_set_par,
+       .fb_setcolreg   = pxafb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_blank       = pxafb_blank,
+       .fb_cursor      = soft_cursor,
+};
+
+/*
+ * Calculate the PCD value from the clock rate (in picoseconds).
+ * We take account of the PPCR clock setting.
+ * From PXA Developer's Manual:
+ *
+ *   PixelClock =      LCLK
+ *                -------------
+ *                2 ( PCD + 1 )
+ *
+ *   PCD =      LCLK
+ *         ------------- - 1
+ *         2(PixelClock)
+ *
+ * Where:
+ *   LCLK = LCD/Memory Clock
+ *   PCD = LCCR3[7:0]
+ *
+ * PixelClock here is in Hz while the pixclock argument given is the
+ * period in picoseconds. Hence PixelClock = 1 / ( pixclock * 10^-12 )
+ *
+ * The function get_lclk_frequency_10khz returns LCLK in units of
+ * 10khz. Calling the result of this function lclk gives us the
+ * following
+ *
+ *    PCD = (lclk * 10^4 ) * ( pixclock * 10^-12 )
+ *          -------------------------------------- - 1
+ *                          2
+ *
+ * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
+ */
+static inline unsigned int get_pcd(unsigned int pixclock)
+{
+       unsigned long long pcd;
+
+       /* FIXME: Need to take into account Double Pixel Clock mode
+         * (DPC) bit? or perhaps set it based on the various clock
+         * speeds */
+
+       pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
+       pcd /= 100000000 * 2;
+       /* no need for this, since we should subtract 1 anyway. they cancel */
+       /* pcd += 1; */ /* make up for integer math truncations */
+       return (unsigned int)pcd;
+}
+
+/*
+ * pxafb_activate_var():
+ *     Configures LCD Controller based on entries in var parameter.  Settings are
+ *     only written to the controller if changes were made.
+ */
+static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
+{
+       struct pxafb_lcd_reg new_regs;
+       u_long flags;
+       u_int lines_per_panel, pcd = get_pcd(var->pixclock);
+
+       DPRINTK("Configuring PXA LCD\n");
+
+       DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+               var->xres, var->hsync_len,
+               var->left_margin, var->right_margin);
+       DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+               var->yres, var->vsync_len,
+               var->upper_margin, var->lower_margin);
+       DPRINTK("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+
+#if DEBUG_VAR
+       if (var->xres < 16        || var->xres > 1024)
+               printk(KERN_ERR "%s: invalid xres %d\n",
+                       fbi->fb.fix.id, var->xres);
+       switch(var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+       case 16:
+               break;
+       default:
+               printk(KERN_ERR "%s: invalid bit depth %d\n",
+                      fbi->fb.fix.id, var->bits_per_pixel);
+               break;
+       }
+       if (var->hsync_len < 1    || var->hsync_len > 64)
+               printk(KERN_ERR "%s: invalid hsync_len %d\n",
+                       fbi->fb.fix.id, var->hsync_len);
+       if (var->left_margin < 1  || var->left_margin > 255)
+               printk(KERN_ERR "%s: invalid left_margin %d\n",
+                       fbi->fb.fix.id, var->left_margin);
+       if (var->right_margin < 1 || var->right_margin > 255)
+               printk(KERN_ERR "%s: invalid right_margin %d\n",
+                       fbi->fb.fix.id, var->right_margin);
+       if (var->yres < 1         || var->yres > 1024)
+               printk(KERN_ERR "%s: invalid yres %d\n",
+                       fbi->fb.fix.id, var->yres);
+       if (var->vsync_len < 1    || var->vsync_len > 64)
+               printk(KERN_ERR "%s: invalid vsync_len %d\n",
+                       fbi->fb.fix.id, var->vsync_len);
+       if (var->upper_margin < 0 || var->upper_margin > 255)
+               printk(KERN_ERR "%s: invalid upper_margin %d\n",
+                       fbi->fb.fix.id, var->upper_margin);
+       if (var->lower_margin < 0 || var->lower_margin > 255)
+               printk(KERN_ERR "%s: invalid lower_margin %d\n",
+                       fbi->fb.fix.id, var->lower_margin);
+#endif
+
+       new_regs.lccr0 = fbi->lccr0 |
+               (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
+
+       new_regs.lccr1 =
+               LCCR1_DisWdth(var->xres) +
+               LCCR1_HorSnchWdth(var->hsync_len) +
+               LCCR1_BegLnDel(var->left_margin) +
+               LCCR1_EndLnDel(var->right_margin);
+
+       /*
+        * If we have a dual scan LCD, we need to halve
+        * the YRES parameter.
+        */
+       lines_per_panel = var->yres;
+       if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+               lines_per_panel /= 2;
+
+       new_regs.lccr2 =
+               LCCR2_DisHght(lines_per_panel) +
+               LCCR2_VrtSnchWdth(var->vsync_len) +
+               LCCR2_BegFrmDel(var->upper_margin) +
+               LCCR2_EndFrmDel(var->lower_margin);
+
+       new_regs.lccr3 = fbi->lccr3 |
+               pxafb_bpp_to_lccr3(var) |
+               (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
+               (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+
+       if (pcd)
+               new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+
+       DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+       DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+       DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
+       DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
+
+       /* Update shadow copy atomically */
+       local_irq_save(flags);
+
+       /* setup dma descriptors */
+       fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
+       fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
+       fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
+
+       fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
+       fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
+       fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
+
+#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
+
+       /* populate descriptors */
+       fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
+       fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
+       fbi->dmadesc_fblow_cpu->fidr  = 0;
+       fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
+
+       fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
+
+       fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
+       fbi->dmadesc_fbhigh_cpu->fidr = 0;
+       fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
+
+       fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
+       fbi->dmadesc_palette_cpu->fidr  = 0;
+       fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
+
+       if (var->bits_per_pixel == 16) {
+               /* palette shouldn't be loaded in true-color mode */
+               fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+               fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
+               /* init it to something, even though we won't be using it */
+               fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
+       } else {
+               fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+               fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
+               fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
+       }
+
+#if 0
+       DPRINTK("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
+       DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
+       DPRINTK("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
+       DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
+       DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
+       DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
+
+       DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
+       DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
+       DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
+
+       DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
+       DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
+       DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
+
+       DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
+       DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
+       DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
+#endif
+
+       fbi->reg_lccr0 = new_regs.lccr0;
+       fbi->reg_lccr1 = new_regs.lccr1;
+       fbi->reg_lccr2 = new_regs.lccr2;
+       fbi->reg_lccr3 = new_regs.lccr3;
+       local_irq_restore(flags);
+
+       /*
+        * Only update the registers if the controller is enabled
+        * and something has changed.
+        */
+       if ((LCCR0  != fbi->reg_lccr0) || (LCCR1  != fbi->reg_lccr1) ||
+           (LCCR2  != fbi->reg_lccr2) || (LCCR3  != fbi->reg_lccr3) ||
+           (FDADR0 != fbi->fdadr0)    || (FDADR1 != fbi->fdadr1))
+               pxafb_schedule_work(fbi, C_REENABLE);
+
+       return 0;
+}
+
+/*
+ * NOTE!  The following functions are purely helpers for set_ctrlr_state.
+ * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * to ensure that things happen in the right way 100% of time time.
+ *     -- rmk
+ */
+static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
+{
+       DPRINTK("backlight o%s\n", on ? "n" : "ff");
+
+       if (pxafb_backlight_power)
+               pxafb_backlight_power(on);
+}
+
+static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
+{
+       DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+
+       if (pxafb_lcd_power)
+               pxafb_lcd_power(on);
+}
+
+static void pxafb_setup_gpio(struct pxafb_info *fbi)
+{
+        unsigned int lccr0 = fbi->lccr0;
+
+       /*
+        * setup is based on type of panel supported
+        */
+
+       /* 4 bit interface */
+       if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+           (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
+           (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
+       {
+               // bits 58-61
+               GPDR1 |= (0xf << 26);
+               GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20);
+
+               // bits 74-77
+               GPDR2 |= (0xf << 10);
+               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
+       }
+
+       /* 8 bit interface */
+        else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+                 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+                 ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+                 (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+       {
+               // bits 58-65
+               GPDR1 |= (0x3f << 26);
+               GPDR2 |= (0x3);
+
+               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+               GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
+
+               // bits 74-77
+               GPDR2 |= (0xf << 10);
+               GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
+       }
+
+       /* 16 bit interface */
+       else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+                ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+       {
+               // bits 58-77
+               GPDR1 |= (0x3f << 26);
+               GPDR2 |= 0x00003fff;
+
+               GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
+               GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
+       }
+
+       else {
+               printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+        }
+}
+
+static void pxafb_enable_controller(struct pxafb_info *fbi)
+{
+       DPRINTK("Enabling LCD controller\n");
+       DPRINTK("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
+       DPRINTK("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+       DPRINTK("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
+       DPRINTK("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
+       DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
+       DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
+
+       /* Sequence from 11.7.10 */
+       LCCR3 = fbi->reg_lccr3;
+       LCCR2 = fbi->reg_lccr2;
+       LCCR1 = fbi->reg_lccr1;
+       LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
+
+       FDADR0 = fbi->fdadr0;
+       FDADR1 = fbi->fdadr1;
+       LCCR0 |= LCCR0_ENB;
+
+       DPRINTK("FDADR0 0x%08x\n", (unsigned int) FDADR0);
+       DPRINTK("FDADR1 0x%08x\n", (unsigned int) FDADR1);
+       DPRINTK("LCCR0 0x%08x\n", (unsigned int) LCCR0);
+       DPRINTK("LCCR1 0x%08x\n", (unsigned int) LCCR1);
+       DPRINTK("LCCR2 0x%08x\n", (unsigned int) LCCR2);
+       DPRINTK("LCCR3 0x%08x\n", (unsigned int) LCCR3);
+}
+
+static void pxafb_disable_controller(struct pxafb_info *fbi)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       DPRINTK("Disabling LCD controller\n");
+
+       add_wait_queue(&fbi->ctrlr_wait, &wait);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+
+       LCSR = 0xffffffff;      /* Clear LCD Status Register */
+       LCCR0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
+       LCCR0 |= LCCR0_DIS;     /* Disable LCD Controller */
+
+       schedule_timeout(20 * HZ / 1000);
+       remove_wait_queue(&fbi->ctrlr_wait, &wait);
+}
+
+/*
+ *  pxafb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct pxafb_info *fbi = dev_id;
+       unsigned int lcsr = LCSR;
+
+       if (lcsr & LCSR_LDD) {
+               LCCR0 |= LCCR0_LDM;
+               wake_up(&fbi->ctrlr_wait);
+       }
+
+       LCSR = lcsr;
+       return IRQ_HANDLED;
+}
+
+/*
+ * This function must be called from task context only, since it will
+ * sleep when disabling the LCD controller, or if we get two contending
+ * processes trying to alter state.
+ */
+static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
+{
+       u_int old_state;
+
+       down(&fbi->ctrlr_sem);
+
+       old_state = fbi->state;
+
+       /*
+        * Hack around fbcon initialisation.
+        */
+       if (old_state == C_STARTUP && state == C_REENABLE)
+               state = C_ENABLE;
+
+       switch (state) {
+       case C_DISABLE_CLKCHANGE:
+               /*
+                * Disable controller for clock change.  If the
+                * controller is already disabled, then do nothing.
+                */
+               if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
+                       fbi->state = state;
+                       //TODO __pxafb_lcd_power(fbi, 0);
+                       pxafb_disable_controller(fbi);
+               }
+               break;
+
+       case C_DISABLE_PM:
+       case C_DISABLE:
+               /*
+                * Disable controller
+                */
+               if (old_state != C_DISABLE) {
+                       fbi->state = state;
+                       __pxafb_backlight_power(fbi, 0);
+                       __pxafb_lcd_power(fbi, 0);
+                       if (old_state != C_DISABLE_CLKCHANGE)
+                               pxafb_disable_controller(fbi);
+               }
+               break;
+
+       case C_ENABLE_CLKCHANGE:
+               /*
+                * Enable the controller after clock change.  Only
+                * do this if we were disabled for the clock change.
+                */
+               if (old_state == C_DISABLE_CLKCHANGE) {
+                       fbi->state = C_ENABLE;
+                       pxafb_enable_controller(fbi);
+                       //TODO __pxafb_lcd_power(fbi, 1);
+               }
+               break;
+
+       case C_REENABLE:
+               /*
+                * Re-enable the controller only if it was already
+                * enabled.  This is so we reprogram the control
+                * registers.
+                */
+               if (old_state == C_ENABLE) {
+                       pxafb_disable_controller(fbi);
+                       pxafb_setup_gpio(fbi);
+                       pxafb_enable_controller(fbi);
+               }
+               break;
+
+       case C_ENABLE_PM:
+               /*
+                * Re-enable the controller after PM.  This is not
+                * perfect - think about the case where we were doing
+                * a clock change, and we suspended half-way through.
+                */
+               if (old_state != C_DISABLE_PM)
+                       break;
+               /* fall through */
+
+       case C_ENABLE:
+               /*
+                * Power up the LCD screen, enable controller, and
+                * turn on the backlight.
+                */
+               if (old_state != C_ENABLE) {
+                       fbi->state = C_ENABLE;
+                       pxafb_setup_gpio(fbi);
+                       pxafb_enable_controller(fbi);
+                       __pxafb_lcd_power(fbi, 1);
+                       __pxafb_backlight_power(fbi, 1);
+               }
+               break;
+       }
+       up(&fbi->ctrlr_sem);
+}
+
+/*
+ * Our LCD controller task (which is called when we blank or unblank)
+ * via keventd.
+ */
+static void pxafb_task(void *dummy)
+{
+       struct pxafb_info *fbi = dummy;
+       u_int state = xchg(&fbi->task_state, -1);
+
+       set_ctrlr_state(fbi, state);
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * CPU clock speed change handler.  We need to adjust the LCD timing
+ * parameters when the CPU clock is adjusted by the power management
+ * subsystem.
+ *
+ * TODO: Determine why f->new != 10*get_lclk_frequency_10khz()
+ */
+static int
+pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
+{
+       struct pxafb_info *fbi = TO_INF(nb, freq_transition);
+       //TODO struct cpufreq_freqs *f = data;
+       u_int pcd;
+
+       switch (val) {
+       case CPUFREQ_PRECHANGE:
+               set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+               break;
+
+       case CPUFREQ_POSTCHANGE:
+               pcd = get_pcd(fbi->fb.var.pixclock);
+               fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+               set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+               break;
+       }
+       return 0;
+}
+
+static int
+pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
+{
+       struct pxafb_info *fbi = TO_INF(nb, freq_policy);
+       struct fb_var_screeninfo *var = &fbi->fb.var;
+       struct cpufreq_policy *policy = data;
+
+       switch (val) {
+       case CPUFREQ_ADJUST:
+       case CPUFREQ_INCOMPATIBLE:
+               printk(KERN_DEBUG "min dma period: %d ps, "
+                       "new clock %d kHz\n", pxafb_display_dma_period(var),
+                       policy->max);
+               // TODO: fill in min/max values
+               break;
+#if 0
+       case CPUFREQ_NOTIFY:
+               printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
+               do {} while(0);
+               /* todo: panic if min/max values aren't fulfilled
+                * [can't really happen unless there's a bug in the
+                * CPU policy verification process *
+                */
+               break;
+#endif
+       }
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks.  Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int pxafb_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct pxafb_info *fbi = dev_get_drvdata(dev);
+
+       if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
+               set_ctrlr_state(fbi, C_DISABLE_PM);
+       return 0;
+}
+
+static int pxafb_resume(struct device *dev, u32 level)
+{
+       struct pxafb_info *fbi = dev_get_drvdata(dev);
+
+       if (level == RESUME_ENABLE)
+               set_ctrlr_state(fbi, C_ENABLE_PM);
+       return 0;
+}
+#else
+#define pxafb_suspend  NULL
+#define pxafb_resume   NULL
+#endif
+
+/*
+ * pxafb_map_video_memory():
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is
+ *     remapped into a non-cached, non-buffered, memory region to
+ *      allow palette and pixel writes to occur without flushing the
+ *      cache.  Once this area is remapped, all virtual memory
+ *      access to the video memory should occur at the new region.
+ */
+static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
+{
+       u_long palette_mem_size;
+
+       /*
+        * We reserve one page for the palette, plus the size
+        * of the framebuffer.
+        */
+       fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+       fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+                                             &fbi->map_dma, GFP_KERNEL);
+
+       if (fbi->map_cpu) {
+               /* prevent initial garbage on screen */
+               memset(fbi->map_cpu, 0, fbi->map_size);
+               fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
+               fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+               /*
+                * FIXME: this is actually the wrong thing to place in
+                * smem_start.  But fbdev suffers from the problem that
+                * it needs an API which doesn't exist (in this case,
+                * dma_writecombine_mmap)
+                */
+               fbi->fb.fix.smem_start = fbi->screen_dma;
+
+               fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
+
+               palette_mem_size = fbi->palette_size * sizeof(u16);
+               DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+               fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+               fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+       }
+
+       return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
+{
+       struct pxafb_info *fbi;
+       void *addr;
+       struct pxafb_mach_info *inf = dev->platform_data;
+
+       /* Alloc the pxafb_info and pseudo_palette in one step */
+       fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
+       if (!fbi)
+               return NULL;
+
+       memset(fbi, 0, sizeof(struct pxafb_info));
+       fbi->dev = dev;
+
+       strcpy(fbi->fb.fix.id, PXA_NAME);
+
+       fbi->fb.fix.type        = FB_TYPE_PACKED_PIXELS;
+       fbi->fb.fix.type_aux    = 0;
+       fbi->fb.fix.xpanstep    = 0;
+       fbi->fb.fix.ypanstep    = 0;
+       fbi->fb.fix.ywrapstep   = 0;
+       fbi->fb.fix.accel       = FB_ACCEL_NONE;
+
+       fbi->fb.var.nonstd      = 0;
+       fbi->fb.var.activate    = FB_ACTIVATE_NOW;
+       fbi->fb.var.height      = -1;
+       fbi->fb.var.width       = -1;
+       fbi->fb.var.accel_flags = 0;
+       fbi->fb.var.vmode       = FB_VMODE_NONINTERLACED;
+
+       fbi->fb.fbops           = &pxafb_ops;
+       fbi->fb.flags           = FBINFO_FLAG_DEFAULT;
+       fbi->fb.node            = -1;
+       fbi->fb.currcon         = -1;
+
+       addr = fbi;
+       addr = addr + sizeof(struct pxafb_info);
+       fbi->fb.pseudo_palette  = addr;
+
+       fbi->max_xres                   = inf->xres;
+       fbi->fb.var.xres                = inf->xres;
+       fbi->fb.var.xres_virtual        = inf->xres;
+       fbi->max_yres                   = inf->yres;
+       fbi->fb.var.yres                = inf->yres;
+       fbi->fb.var.yres_virtual        = inf->yres;
+       fbi->max_bpp                    = inf->bpp;
+       fbi->fb.var.bits_per_pixel      = inf->bpp;
+       fbi->fb.var.pixclock            = inf->pixclock;
+       fbi->fb.var.hsync_len           = inf->hsync_len;
+       fbi->fb.var.left_margin         = inf->left_margin;
+       fbi->fb.var.right_margin        = inf->right_margin;
+       fbi->fb.var.vsync_len           = inf->vsync_len;
+       fbi->fb.var.upper_margin        = inf->upper_margin;
+       fbi->fb.var.lower_margin        = inf->lower_margin;
+       fbi->fb.var.sync                = inf->sync;
+       fbi->fb.var.grayscale           = inf->cmap_greyscale;
+       fbi->cmap_inverse               = inf->cmap_inverse;
+       fbi->cmap_static                = inf->cmap_static;
+       fbi->lccr0                      = inf->lccr0;
+       fbi->lccr3                      = inf->lccr3;
+       fbi->state                      = C_STARTUP;
+       fbi->task_state                 = (u_char)-1;
+       fbi->fb.fix.smem_len            = fbi->max_xres * fbi->max_yres *
+                                         fbi->max_bpp / 8;
+
+       init_waitqueue_head(&fbi->ctrlr_wait);
+       INIT_WORK(&fbi->task, pxafb_task, fbi);
+       init_MUTEX(&fbi->ctrlr_sem);
+
+       return fbi;
+}
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+static int __init pxafb_parse_options(struct device *dev, char *options)
+{
+       struct pxafb_mach_info *inf = dev->platform_data;
+       char *this_opt;
+
+        if (!options || !*options)
+                return 0;
+
+       dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
+
+       /* could be made table driven or similar?... */
+        while ((this_opt = strsep(&options, ",")) != NULL) {
+                if (!strncmp(this_opt, "mode:", 5)) {
+                       const char *name = this_opt+5;
+                       unsigned int namelen = strlen(name);
+                       int res_specified = 0, bpp_specified = 0;
+                       unsigned int xres = 0, yres = 0, bpp = 0;
+                       int yres_specified = 0;
+                       int i;
+                       for (i = namelen-1; i >= 0; i--) {
+                               switch (name[i]) {
+                               case '-':
+                                       namelen = i;
+                                       if (!bpp_specified && !yres_specified) {
+                                               bpp = simple_strtoul(&name[i+1], NULL, 0);
+                                               bpp_specified = 1;
+                                       } else
+                                               goto done;
+                                       break;
+                               case 'x':
+                                       if (!yres_specified) {
+                                               yres = simple_strtoul(&name[i+1], NULL, 0);
+                                               yres_specified = 1;
+                                       } else
+                                               goto done;
+                                       break;
+                               case '0'...'9':
+                                       break;
+                               default:
+                                       goto done;
+                               }
+                       }
+                       if (i < 0 && yres_specified) {
+                               xres = simple_strtoul(name, NULL, 0);
+                               res_specified = 1;
+                       }
+               done:
+                       if (res_specified) {
+                               dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+                               inf->xres = xres; inf->yres = yres;
+                       }
+                       if (bpp_specified)
+                               switch (bpp) {
+                               case 1:
+                               case 2:
+                               case 4:
+                               case 8:
+                               case 16:
+                                       inf->bpp = bpp;
+                                       dev_info(dev, "overriding bit depth: %d\n", bpp);
+                                       break;
+                               default:
+                                       dev_err(dev, "Depth %d is not valid\n", bpp);
+                               }
+                } else if (!strncmp(this_opt, "pixclock:", 9)) {
+                        inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override pixclock: %ld\n", inf->pixclock);
+                } else if (!strncmp(this_opt, "left:", 5)) {
+                        inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+                       dev_info(dev, "override left: %u\n", inf->left_margin);
+                } else if (!strncmp(this_opt, "right:", 6)) {
+                        inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override right: %u\n", inf->right_margin);
+                } else if (!strncmp(this_opt, "upper:", 6)) {
+                        inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override upper: %u\n", inf->upper_margin);
+                } else if (!strncmp(this_opt, "lower:", 6)) {
+                        inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+                       dev_info(dev, "override lower: %u\n", inf->lower_margin);
+                } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+                        inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override hsynclen: %u\n", inf->hsync_len);
+                } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+                        inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+                       dev_info(dev, "override vsynclen: %u\n", inf->vsync_len);
+                } else if (!strncmp(this_opt, "hsync:", 6)) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+                               dev_info(dev, "override hsync: Active Low\n");
+                               inf->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+                       } else {
+                               dev_info(dev, "override hsync: Active High\n");
+                               inf->sync |= FB_SYNC_HOR_HIGH_ACT;
+                       }
+                } else if (!strncmp(this_opt, "vsync:", 6)) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+                               dev_info(dev, "override vsync: Active Low\n");
+                               inf->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+                       } else {
+                               dev_info(dev, "override vsync: Active High\n");
+                               inf->sync |= FB_SYNC_VERT_HIGH_ACT;
+                       }
+                } else if (!strncmp(this_opt, "dpc:", 4)) {
+                        if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
+                               dev_info(dev, "override double pixel clock: false\n");
+                               inf->lccr3 &= ~LCCR3_DPC;
+                       } else {
+                               dev_info(dev, "override double pixel clock: true\n");
+                               inf->lccr3 |= LCCR3_DPC;
+                       }
+                } else if (!strncmp(this_opt, "outputen:", 9)) {
+                        if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+                               dev_info(dev, "override output enable: active low\n");
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
+                       } else {
+                               dev_info(dev, "override output enable: active high\n");
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
+                       }
+                } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+                        if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+                               dev_info(dev, "override pixel clock polarity: falling edge\n");
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
+                       } else {
+                               dev_info(dev, "override pixel clock polarity: rising edge\n");
+                               inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
+                       }
+                } else if (!strncmp(this_opt, "color", 5)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+                } else if (!strncmp(this_opt, "mono", 4)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+                } else if (!strncmp(this_opt, "active", 6)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+                } else if (!strncmp(this_opt, "passive", 7)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+                } else if (!strncmp(this_opt, "single", 6)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+                } else if (!strncmp(this_opt, "dual", 4)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+                } else if (!strncmp(this_opt, "4pix", 4)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+                } else if (!strncmp(this_opt, "8pix", 4)) {
+                       inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+               } else {
+                       dev_err(dev, "unknown option: %s\n", this_opt);
+                       return -EINVAL;
+               }
+        }
+        return 0;
+
+}
+#endif
+
+int __init pxafb_probe(struct device *dev)
+{
+       struct pxafb_info *fbi;
+       struct pxafb_mach_info *inf;
+       int ret;
+
+       dev_dbg(dev, "pxafb_probe\n");
+
+       inf = dev->platform_data;
+       ret = -ENOMEM;
+       fbi = NULL;
+       if (!inf)
+               goto failed;
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+       ret = pxafb_parse_options(dev, g_options);
+       if (ret < 0)
+               goto failed;
+#endif
+
+#ifdef DEBUG_VAR
+        /* Check for various illegal bit-combinations. Currently only
+        * a warning is given. */
+
+        if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+                dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                        inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+        if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+                dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+                        inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+        if (inf->lccr0 & LCCR0_DPD &&
+           ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
+            (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
+            (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
+                dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
+                        " single panel mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+           (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+                dev_warn(dev, "Dual panel only valid in passive mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+             (inf->upper_margin || inf->lower_margin))
+                dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n");
+#endif
+
+       dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
+       if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
+               dev_err(dev, "Invalid resolution or bit depth\n");
+               ret = -EINVAL;
+               goto failed;
+       }
+       pxafb_backlight_power = inf->pxafb_backlight_power;
+       pxafb_lcd_power = inf->pxafb_lcd_power;
+       fbi = pxafb_init_fbinfo(dev);
+       if (!fbi) {
+               dev_err(dev, "Failed to initialize framebuffer device\n");
+               ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+               goto failed;
+       }
+
+       /* Initialize video memory */
+       ret = pxafb_map_video_memory(fbi);
+       if (ret) {
+               dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+               ret = -ENOMEM;
+               goto failed;
+       }
+       /* enable LCD controller clock */
+       pxa_set_cken(CKEN16_LCD, 1);
+
+       ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
+       if (ret) {
+               dev_err(dev, "request_irq failed: %d\n", ret);
+               ret = -EBUSY;
+               goto failed;
+       }
+
+       /*
+        * This makes sure that our colour bitfield
+        * descriptors are correctly initialised.
+        */
+       pxafb_check_var(&fbi->fb.var, &fbi->fb);
+       pxafb_set_par(&fbi->fb);
+
+       dev_set_drvdata(dev, fbi);
+
+       ret = register_framebuffer(&fbi->fb);
+       if (ret < 0) {
+               dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
+               goto failed;
+       }
+
+#ifdef CONFIG_PM
+       // TODO
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+       fbi->freq_transition.notifier_call = pxafb_freq_transition;
+       fbi->freq_policy.notifier_call = pxafb_freq_policy;
+       cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+       cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+#endif
+
+       /*
+        * Ok, now enable the LCD controller
+        */
+       set_ctrlr_state(fbi, C_ENABLE);
+
+       return 0;
+
+failed:
+       dev_set_drvdata(dev, NULL);
+       if (fbi)
+               kfree(fbi);
+       return ret;
+}
+
+static struct device_driver pxafb_driver = {
+       .name           = "pxa2xx-fb",
+       .bus            = &platform_bus_type,
+       .probe          = pxafb_probe,
+#ifdef CONFIG_PM
+       .suspend        = pxafb_suspend,
+       .resume         = pxafb_resume,
+#endif
+};
+
+int __devinit pxafb_init(void)
+{
+       return driver_register(&pxafb_driver);
+}
+
+#ifndef MODULE
+int __devinit pxafb_setup(char *options)
+{
+# ifdef CONFIG_FB_PXA_PARAMETERS
+       strlcpy(g_options, options, sizeof(g_options));
+# endif
+       return 0;
+}
+#else
+module_init(pxafb_init);
+# ifdef CONFIG_FB_PXA_PARAMETERS
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+# endif
+#endif
+
+MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
new file mode 100644 (file)
index 0000000..bdeb028
--- /dev/null
@@ -0,0 +1,31 @@
+menu "Dallas's 1-wire bus"
+
+config W1
+       tristate "Dallas's 1-wire support"
+       ---help---
+         Dallas's 1-wire bus is usefull to connect slow 1-pin devices 
+         such as iButtons and thermal sensors.
+         
+         If you want W1 support, you should say Y here.
+
+         This W1 support can also be built as a module.  If so, the module
+         will be called wire.ko.
+
+config W1_MATROX
+       tristate "Matrox G400 transport layer for 1-wire"
+       depends on W1 && PCI
+       help
+         Say Y here if you want to communicate with your 1-wire devices
+         using Matrox's G400 GPIO pins.
+         
+         This support is also available as a module.  If so, the module 
+         will be called matrox_w1.ko.
+
+config W1_THERM
+       tristate "Thermal family implementation"
+       depends on W1
+       help
+         Say Y here if you want to connect 1-wire thermal sensors to you
+         wire.
+
+endmenu
diff --git a/drivers/w1/matrox_w1.c b/drivers/w1/matrox_w1.c
new file mode 100644 (file)
index 0000000..bde1778
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ *     matrox_w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; 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 <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+#include "w1.h"
+#include "w1_int.h"
+#include "w1_log.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
+
+static struct pci_device_id matrox_w1_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
+
+static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit matrox_w1_remove(struct pci_dev *);
+
+static struct pci_driver matrox_w1_pci_driver = {
+       .name = "matrox_w1",
+       .id_table = matrox_w1_tbl,
+       .probe = matrox_w1_probe,
+       .remove = __devexit_p(matrox_w1_remove),
+};
+
+/* 
+ * Matrox G400 DDC registers.
+ */
+
+#define MATROX_G400_DDC_CLK            (1<<4)
+#define MATROX_G400_DDC_DATA           (1<<1)
+
+#define MATROX_BASE                    0x3C00
+#define MATROX_STATUS                  0x1e14
+
+#define MATROX_PORT_INDEX_OFFSET       0x00
+#define MATROX_PORT_DATA_OFFSET                0x0A
+
+#define MATROX_GET_CONTROL             0x2A
+#define MATROX_GET_DATA                        0x2B
+#define MATROX_CURSOR_CTL              0x06
+
+struct matrox_device
+{
+       unsigned long base_addr;
+       unsigned long port_index, port_data;
+       u8 data_mask;
+
+       unsigned long phys_addr, virt_addr;
+       unsigned long found;
+
+       struct w1_bus_master *bus_master;
+};
+
+static u8 matrox_w1_read_ddc_bit(unsigned long);
+static void matrox_w1_write_ddc_bit(unsigned long, u8);
+
+/*
+ * These functions read and write DDC Data bit.
+ *
+ * Using tristate pins, since i can't  fin any open-drain pin in whole motherboard.
+ * Unfortunately we can't connect to Intel's 82801xx IO controller
+ * since we don't know motherboard schema, wich has pretty unused(may be not) GPIO.
+ *
+ * I've heard that PIIX also has open drain pin.
+ *
+ * Port mapping.
+ */
+static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
+{
+       u8 ret;
+
+       writeb(reg, dev->port_index);
+       ret = readb(dev->port_data);
+       barrier();
+
+       return ret;
+}
+
+static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
+{
+       writeb(reg, dev->port_index);
+       writeb(val, dev->port_data);
+       wmb();
+}
+
+static void matrox_w1_write_ddc_bit(unsigned long data, u8 bit)
+{
+       u8 ret;
+       struct matrox_device *dev = (struct matrox_device *) data;
+
+       if (bit)
+               bit = 0;
+       else
+               bit = dev->data_mask;
+
+       ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
+       matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
+       matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
+}
+
+static u8 matrox_w1_read_ddc_bit(unsigned long data)
+{
+       u8 ret;
+       struct matrox_device *dev = (struct matrox_device *) data;
+
+       ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
+
+       return ret;
+}
+
+static void matrox_w1_hw_init(struct matrox_device *dev)
+{
+       matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
+       matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
+}
+
+static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct matrox_device *dev;
+       int err;
+
+       assert(pdev != NULL);
+       assert(ent != NULL);
+
+       if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
+               return -ENODEV;
+
+       dev = kmalloc(sizeof(struct matrox_device) +
+                      sizeof(struct w1_bus_master), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev,
+                       "%s: Failed to create new matrox_device object.\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
+
+       dev->bus_master = (struct w1_bus_master *)(dev + 1);
+
+       /* 
+        * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c 
+        */
+
+       dev->phys_addr = pci_resource_start(pdev, 1);
+
+       dev->virt_addr =
+               (unsigned long) ioremap_nocache(dev->phys_addr, 16384);
+       if (!dev->virt_addr) {
+               dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
+                       __func__, dev->phys_addr, 16384);
+               err = -EIO;
+               goto err_out_free_device;
+       }
+
+       dev->base_addr = dev->virt_addr + MATROX_BASE;
+       dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
+       dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
+       dev->data_mask = (MATROX_G400_DDC_DATA);
+
+       matrox_w1_hw_init(dev);
+
+       dev->bus_master->data = (unsigned long) dev;
+       dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
+       dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
+
+       err = w1_add_master_device(dev->bus_master);
+       if (err)
+               goto err_out_free_device;
+
+       pci_set_drvdata(pdev, dev);
+
+       dev->found = 1;
+
+       dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
+
+       return 0;
+
+err_out_free_device:
+       kfree(dev);
+
+       return err;
+}
+
+static void __devexit matrox_w1_remove(struct pci_dev *pdev)
+{
+       struct matrox_device *dev = pci_get_drvdata(pdev);
+
+       assert(dev != NULL);
+
+       if (dev->found) {
+               w1_remove_master_device(dev->bus_master);
+               iounmap((void *) dev->virt_addr);
+       }
+       kfree(dev);
+}
+
+static int __init matrox_w1_init(void)
+{
+       return pci_module_init(&matrox_w1_pci_driver);
+}
+
+static void __exit matrox_w1_fini(void)
+{
+       pci_unregister_driver(&matrox_w1_pci_driver);
+}
+
+module_init(matrox_w1_init);
+module_exit(matrox_w1_fini);
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
new file mode 100644 (file)
index 0000000..4f52422
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ *     w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; 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 <asm/atomic.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_log.h"
+#include "w1_int.h"
+#include "w1_family.h"
+#include "w1_netlink.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
+
+static int w1_timeout = 5 * HZ;
+int w1_max_slave_count = 10;
+
+module_param_named(timeout, w1_timeout, int, 0);
+module_param_named(max_slave_count, w1_max_slave_count, int, 0);
+
+spinlock_t w1_mlock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD(w1_masters);
+
+static pid_t control_thread;
+static int control_needs_exit;
+static DECLARE_COMPLETION(w1_control_complete);
+static DECLARE_WAIT_QUEUE_HEAD(w1_control_wait);
+
+static int w1_master_match(struct device *dev, struct device_driver *drv)
+{
+       return 1;
+}
+
+static int w1_master_probe(struct device *dev)
+{
+       return -ENODEV;
+}
+
+static int w1_master_remove(struct device *dev)
+{
+       return 0;
+}
+
+static void w1_master_release(struct device *dev)
+{
+       struct w1_master *md = container_of(dev, struct w1_master, dev);
+
+       complete(&md->dev_released);
+}
+
+static void w1_slave_release(struct device *dev)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       complete(&sl->dev_released);
+}
+
+static ssize_t w1_default_read_name(struct device *dev, char *buf)
+{
+       return sprintf(buf, "No family registered.\n");
+}
+
+static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off,
+                    size_t count)
+{
+       return sprintf(buf, "No family registered.\n");
+}
+
+struct bus_type w1_bus_type = {
+       .name = "w1",
+       .match = w1_master_match,
+};
+
+struct device_driver w1_driver = {
+       .name = "w1_driver",
+       .bus = &w1_bus_type,
+       .probe = w1_master_probe,
+       .remove = w1_master_remove,
+};
+
+struct device w1_device = {
+       .parent = NULL,
+       .bus = &w1_bus_type,
+       .bus_id = "w1 bus master",
+       .driver = &w1_driver,
+       .release = &w1_master_release
+};
+
+static struct device_attribute w1_slave_attribute = {
+       .attr = {
+                       .name = "name",
+                       .mode = S_IRUGO,
+                       .owner = THIS_MODULE
+       },
+       .show = &w1_default_read_name,
+};
+
+static struct device_attribute w1_slave_attribute_val = {
+       .attr = {
+                       .name = "value",
+                       .mode = S_IRUGO,
+                       .owner = THIS_MODULE
+       },
+       .show = &w1_default_read_name,
+};
+
+static ssize_t w1_master_attribute_show(struct device *dev, char *buf)
+{
+       return sprintf(buf, "please fix me\n");
+#if 0
+       struct w1_master *md = container_of(dev, struct w1_master, dev);
+       int c = PAGE_SIZE;
+
+       if (down_interruptible(&md->mutex))
+               return -EBUSY;
+
+       c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", md->name);
+       c -= snprintf(buf + PAGE_SIZE - c, c,
+                      "bus_master=0x%p, timeout=%d, max_slave_count=%d, attempts=%lu\n",
+                      md->bus_master, w1_timeout, md->max_slave_count,
+                      md->attempts);
+       c -= snprintf(buf + PAGE_SIZE - c, c, "%d slaves: ",
+                      md->slave_count);
+       if (md->slave_count == 0)
+               c -= snprintf(buf + PAGE_SIZE - c, c, "no.\n");
+       else {
+               struct list_head *ent, *n;
+               struct w1_slave *sl;
+
+               list_for_each_safe(ent, n, &md->slist) {
+                       sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+
+                       c -= snprintf(buf + PAGE_SIZE - c, c, "%s[%p] ",
+                                      sl->name, sl);
+               }
+               c -= snprintf(buf + PAGE_SIZE - c, c, "\n");
+       }
+
+       up(&md->mutex);
+
+       return PAGE_SIZE - c;
+#endif
+}
+
+struct device_attribute w1_master_attribute = {
+       .attr = {
+                       .name = "w1_master_stats",
+                       .mode = S_IRUGO,
+                       .owner = THIS_MODULE,
+       },
+       .show = &w1_master_attribute_show,
+};
+
+static struct bin_attribute w1_slave_bin_attribute = {
+       .attr = {
+                       .name = "w1_slave",
+                       .mode = S_IRUGO,
+                       .owner = THIS_MODULE,
+       },
+       .size = W1_SLAVE_DATA_SIZE,
+       .read = &w1_default_read_bin,
+};
+
+static int __w1_attach_slave_device(struct w1_slave *sl)
+{
+       int err;
+
+       sl->dev.parent = &sl->master->dev;
+       sl->dev.driver = sl->master->driver;
+       sl->dev.bus = &w1_bus_type;
+       sl->dev.release = &w1_slave_release;
+
+       snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id),
+                 "%x-%llx",
+                 (unsigned int) sl->reg_num.family,
+                 (unsigned long long) sl->reg_num.id);
+       snprintf (&sl->name[0], sizeof(sl->name),
+                 "%x-%llx",
+                 (unsigned int) sl->reg_num.family,
+                 (unsigned long long) sl->reg_num.id);
+
+       dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
+               &sl->dev.bus_id[0]);
+
+       err = device_register(&sl->dev);
+       if (err < 0) {
+               dev_err(&sl->dev,
+                        "Device registration [%s] failed. err=%d\n",
+                        sl->dev.bus_id, err);
+               return err;
+       }
+
+       w1_slave_bin_attribute.read = sl->family->fops->rbin;
+       w1_slave_attribute.show = sl->family->fops->rname;
+       w1_slave_attribute_val.show = sl->family->fops->rval;
+       w1_slave_attribute_val.attr.name = sl->family->fops->rvalname;
+
+       err = device_create_file(&sl->dev, &w1_slave_attribute);
+       if (err < 0) {
+               dev_err(&sl->dev,
+                        "sysfs file creation for [%s] failed. err=%d\n",
+                        sl->dev.bus_id, err);
+               device_unregister(&sl->dev);
+               return err;
+       }
+
+       err = device_create_file(&sl->dev, &w1_slave_attribute_val);
+       if (err < 0) {
+               dev_err(&sl->dev,
+                        "sysfs file creation for [%s] failed. err=%d\n",
+                        sl->dev.bus_id, err);
+               device_remove_file(&sl->dev, &w1_slave_attribute);
+               device_unregister(&sl->dev);
+               return err;
+       }
+
+       err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_bin_attribute);
+       if (err < 0) {
+               dev_err(&sl->dev,
+                        "sysfs file creation for [%s] failed. err=%d\n",
+                        sl->dev.bus_id, err);
+               device_remove_file(&sl->dev, &w1_slave_attribute);
+               device_remove_file(&sl->dev, &w1_slave_attribute_val);
+               device_unregister(&sl->dev);
+               return err;
+       }
+
+       list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
+
+       return 0;
+}
+
+static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+{
+       struct w1_slave *sl;
+       struct w1_family *f;
+       int err;
+
+       sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
+       if (!sl) {
+               dev_err(&dev->dev,
+                        "%s: failed to allocate new slave device.\n",
+                        __func__);
+               return -ENOMEM;
+       }
+
+       memset(sl, 0, sizeof(*sl));
+
+       sl->owner = THIS_MODULE;
+       sl->master = dev;
+
+       memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
+       atomic_set(&sl->refcnt, 0);
+       init_completion(&sl->dev_released);
+
+       spin_lock(&w1_flock);
+       f = w1_family_registered(rn->family);
+       if (!f) {
+               spin_unlock(&w1_flock);
+               dev_info(&dev->dev, "Family %x is not registered.\n",
+                         rn->family);
+               kfree(sl);
+               return -ENODEV;
+       }
+       __w1_family_get(f);
+       spin_unlock(&w1_flock);
+
+       sl->family = f;
+
+
+       err = __w1_attach_slave_device(sl);
+       if (err < 0) {
+               dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
+                        sl->name);
+               w1_family_put(sl->family);
+               kfree(sl);
+               return err;
+       }
+
+       dev->slave_count++;
+
+       return 0;
+}
+
+static void w1_slave_detach(struct w1_slave *sl)
+{
+       dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
+
+       while (atomic_read(&sl->refcnt))
+               schedule_timeout(10);
+
+       sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_bin_attribute);
+       device_remove_file(&sl->dev, &w1_slave_attribute);
+       device_unregister(&sl->dev);
+       w1_family_put(sl->family);
+}
+
+static void w1_search(struct w1_master *dev)
+{
+       u64 last, rn, tmp;
+       int i, count = 0, slave_count;
+       int last_family_desc, last_zero, last_device;
+       int search_bit, id_bit, comp_bit, desc_bit;
+       struct list_head *ent;
+       struct w1_slave *sl;
+       int family_found = 0;
+       struct w1_netlink_msg msg;
+
+       dev->attempts++;
+
+       memset(&msg, 0, sizeof(msg));
+
+       search_bit = id_bit = comp_bit = 0;
+       rn = tmp = last = 0;
+       last_device = last_zero = last_family_desc = 0;
+
+       desc_bit = 64;
+
+       while (!(id_bit && comp_bit) && !last_device
+               && count++ < dev->max_slave_count) {
+               last = rn;
+               rn = 0;
+
+               last_family_desc = 0;
+
+               /*
+                * Reset bus and all 1-wire device state machines
+                * so they can respond to our requests.
+                *
+                * Return 0 - device(s) present, 1 - no devices present.
+                */
+               if (w1_reset_bus(dev)) {
+                       dev_info(&dev->dev, "No devices present on the wire.\n");
+                       break;
+               }
+
+#if 1
+               memset(&msg, 0, sizeof(msg));
+
+               w1_write_8(dev, W1_SEARCH);
+               for (i = 0; i < 64; ++i) {
+                       /*
+                        * Read 2 bits from bus.
+                        * All who don't sleep must send ID bit and COMPLEMENT ID bit.
+                        * They actually are ANDed between all senders.
+                        */
+                       id_bit = w1_read_bit(dev);
+                       comp_bit = w1_read_bit(dev);
+
+                       if (id_bit && comp_bit)
+                               break;
+
+                       if (id_bit == 0 && comp_bit == 0) {
+                               if (i == desc_bit)
+                                       search_bit = 1;
+                               else if (i > desc_bit)
+                                       search_bit = 0;
+                               else
+                                       search_bit = ((last >> i) & 0x1);
+
+                               if (search_bit == 0) {
+                                       last_zero = i;
+                                       if (last_zero < 9)
+                                               last_family_desc = last_zero;
+                               }
+
+                       }
+                       else
+                               search_bit = id_bit;
+
+                       tmp = search_bit;
+                       rn |= (tmp << i);
+
+                       /*
+                        * Write 1 bit to bus
+                        * and make all who don't have "search_bit" in "i"'th position
+                        * in it's registration number sleep.
+                        */
+                       w1_write_bit(dev, search_bit);
+
+               }
+#endif
+               msg.id.w1_id = rn;
+               msg.val = w1_calc_crc8((u8 *) & rn, 7);
+               w1_netlink_send(dev, &msg);
+
+               if (desc_bit == last_zero)
+                       last_device = 1;
+
+               desc_bit = last_zero;
+
+               slave_count = 0;
+               list_for_each(ent, &dev->slist) {
+                       struct w1_reg_num *tmp;
+
+                       tmp = (struct w1_reg_num *) &rn;
+
+                       sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+
+                       if (sl->reg_num.family == tmp->family &&
+                           sl->reg_num.id == tmp->id &&
+                           sl->reg_num.crc == tmp->crc)
+                               break;
+                       else if (sl->reg_num.family == tmp->family) {
+                               family_found = 1;
+                               break;
+                       }
+
+                       slave_count++;
+               }
+
+               if (slave_count == dev->slave_count &&
+                   msg.val && (*((__u8 *) & msg.val) == msg.id.id.crc)) {
+                       w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
+               }
+       }
+}
+
+int w1_control(void *data)
+{
+       struct w1_slave *sl;
+       struct w1_master *dev;
+       struct list_head *ent, *ment, *n, *mn;
+       int err, have_to_wait = 0, timeout;
+
+       daemonize("w1_control");
+       allow_signal(SIGTERM);
+
+       while (!control_needs_exit || have_to_wait) {
+               have_to_wait = 0;
+
+               timeout = w1_timeout;
+               do {
+                       timeout = interruptible_sleep_on_timeout(&w1_control_wait, timeout);
+                       if (current->flags & PF_FREEZE)
+                               refrigerator(PF_FREEZE);
+               } while (!signal_pending(current) && (timeout > 0));
+
+               if (signal_pending(current))
+                       flush_signals(current);
+
+               list_for_each_safe(ment, mn, &w1_masters) {
+                       dev = list_entry(ment, struct w1_master, w1_master_entry);
+
+                       if (!control_needs_exit && !dev->need_exit)
+                               continue;
+                       /*
+                        * Little race: we can create thread but not set the flag.
+                        * Get a chance for external process to set flag up.
+                        */
+                       if (!dev->initialized) {
+                               have_to_wait = 1;
+                               continue;
+                       }
+
+                       spin_lock(&w1_mlock);
+                       list_del(&dev->w1_master_entry);
+                       spin_unlock(&w1_mlock);
+
+                       if (control_needs_exit) {
+                               dev->need_exit = 1;
+
+                               err = kill_proc(dev->kpid, SIGTERM, 1);
+                               if (err)
+                                       dev_err(&dev->dev,
+                                                "Failed to send signal to w1 kernel thread %d.\n",
+                                                dev->kpid);
+                       }
+
+                       wait_for_completion(&dev->dev_exited);
+
+                       list_for_each_safe(ent, n, &dev->slist) {
+                               sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+
+                               if (!sl)
+                                       dev_warn(&dev->dev,
+                                                 "%s: slave entry is NULL.\n",
+                                                 __func__);
+                               else {
+                                       list_del(&sl->w1_slave_entry);
+
+                                       w1_slave_detach(sl);
+                                       kfree(sl);
+                               }
+                       }
+                       device_remove_file(&dev->dev, &w1_master_attribute);
+                       atomic_dec(&dev->refcnt);
+               }
+       }
+
+       complete_and_exit(&w1_control_complete, 0);
+}
+
+int w1_process(void *data)
+{
+       struct w1_master *dev = (struct w1_master *) data;
+       unsigned long timeout;
+
+       daemonize("%s", dev->name);
+       allow_signal(SIGTERM);
+
+       while (!dev->need_exit) {
+               timeout = w1_timeout;
+               do {
+                       timeout = interruptible_sleep_on_timeout(&dev->kwait, timeout);
+                       if (current->flags & PF_FREEZE)
+                               refrigerator(PF_FREEZE);
+               } while (!signal_pending(current) && (timeout > 0));
+
+               if (signal_pending(current))
+                       flush_signals(current);
+
+               if (dev->need_exit)
+                       break;
+
+               if (!dev->initialized)
+                       continue;
+
+               if (down_interruptible(&dev->mutex))
+                       continue;
+               w1_search(dev);
+               up(&dev->mutex);
+       }
+
+       atomic_dec(&dev->refcnt);
+       complete_and_exit(&dev->dev_exited, 0);
+
+       return 0;
+}
+
+int w1_init(void)
+{
+       int retval;
+
+       printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n");
+
+       retval = bus_register(&w1_bus_type);
+       if (retval) {
+               printk(KERN_ERR "Failed to register bus. err=%d.\n", retval);
+               goto err_out_exit_init;
+       }
+
+       retval = driver_register(&w1_driver);
+       if (retval) {
+               printk(KERN_ERR
+                       "Failed to register master driver. err=%d.\n",
+                       retval);
+               goto err_out_bus_unregister;
+       }
+
+       control_thread = kernel_thread(&w1_control, NULL, 0);
+       if (control_thread < 0) {
+               printk(KERN_ERR "Failed to create control thread. err=%d\n",
+                       control_thread);
+               retval = control_thread;
+               goto err_out_driver_unregister;
+       }
+
+       return 0;
+
+err_out_driver_unregister:
+       driver_unregister(&w1_driver);
+
+err_out_bus_unregister:
+       bus_unregister(&w1_bus_type);
+
+err_out_exit_init:
+       return retval;
+}
+
+void w1_fini(void)
+{
+       struct w1_master *dev;
+       struct list_head *ent, *n;
+
+       list_for_each_safe(ent, n, &w1_masters) {
+               dev = list_entry(ent, struct w1_master, w1_master_entry);
+               __w1_remove_master_device(dev);
+       }
+
+       control_needs_exit = 1;
+
+       wait_for_completion(&w1_control_complete);
+
+       driver_unregister(&w1_driver);
+       bus_unregister(&w1_bus_type);
+}
+
+module_init(w1_init);
+module_exit(w1_fini);
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
new file mode 100644 (file)
index 0000000..c75e9f7
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *     w1_int.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; 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 <linux/kernel.h>
+#include <linux/list.h>
+
+#include "w1.h"
+#include "w1_log.h"
+
+static u32 w1_ids = 1;
+
+extern struct device_driver w1_driver;
+extern struct bus_type w1_bus_type;
+extern struct device w1_device;
+extern struct device_attribute w1_master_attribute;
+extern int w1_max_slave_count;
+extern struct list_head w1_masters;
+extern spinlock_t w1_mlock;
+
+extern int w1_process(void *);
+
+struct w1_master * w1_alloc_dev(u32 id, int slave_count,
+             struct device_driver *driver, struct device *device)
+{
+       struct w1_master *dev;
+       int err;
+
+       /*
+        * We are in process context(kernel thread), so can sleep.
+        */
+       dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+       if (!dev) {
+               printk(KERN_ERR
+                       "Failed to allocate %zd bytes for new w1 device.\n",
+                       sizeof(struct w1_master));
+               return NULL;
+       }
+
+       memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
+
+       dev->bus_master = (struct w1_bus_master *)(dev + 1);
+
+       dev->owner              = THIS_MODULE;
+       dev->max_slave_count    = slave_count;
+       dev->slave_count        = 0;
+       dev->attempts           = 0;
+       dev->kpid               = -1;
+       dev->initialized        = 0;
+       dev->id                 = id;
+
+       atomic_set(&dev->refcnt, 2);
+
+       INIT_LIST_HEAD(&dev->slist);
+       init_MUTEX(&dev->mutex);
+
+       init_waitqueue_head(&dev->kwait);
+       init_completion(&dev->dev_released);
+       init_completion(&dev->dev_exited);
+
+       memcpy(&dev->dev, device, sizeof(struct device));
+       snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
+                 "w1_bus_master%u", dev->id);
+       snprintf(dev->name, sizeof(dev->name), "w1_bus_master%u", dev->id);
+
+       dev->driver = driver;
+
+       dev->groups = 23;
+       dev->seq = 1;
+       dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
+       if (!dev->nls) {
+               printk(KERN_ERR "Failed to create new netlink socket(%u).\n",
+                       NETLINK_NFLOG);
+               memset(dev, 0, sizeof(struct w1_master));
+               kfree(dev);
+               dev = NULL;
+       }
+
+       err = device_register(&dev->dev);
+       if (err) {
+               printk(KERN_ERR "Failed to register master device. err=%d\n", err);
+               if (dev->nls->sk_socket)
+                       sock_release(dev->nls->sk_socket);
+               memset(dev, 0, sizeof(struct w1_master));
+               kfree(dev);
+               dev = NULL;
+       }
+
+       return dev;
+}
+
+void w1_free_dev(struct w1_master *dev)
+{
+       device_unregister(&dev->dev);
+       if (dev->nls->sk_socket)
+               sock_release(dev->nls->sk_socket);
+       memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
+       kfree(dev);
+}
+
+int w1_add_master_device(struct w1_bus_master *master)
+{
+       struct w1_master *dev;
+       int retval = 0;
+
+       dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, &w1_driver, &w1_device);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->kpid = kernel_thread(&w1_process, dev, 0);
+       if (dev->kpid < 0) {
+               dev_err(&dev->dev,
+                        "Failed to create new kernel thread. err=%d\n",
+                        dev->kpid);
+               retval = dev->kpid;
+               goto err_out_free_dev;
+       }
+
+       retval = device_create_file(&dev->dev, &w1_master_attribute);
+       if (retval)
+               goto err_out_kill_thread;
+
+       memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
+
+       dev->initialized = 1;
+
+       spin_lock(&w1_mlock);
+       list_add(&dev->w1_master_entry, &w1_masters);
+       spin_unlock(&w1_mlock);
+
+       return 0;
+
+err_out_kill_thread:
+       dev->need_exit = 1;
+       if (kill_proc(dev->kpid, SIGTERM, 1))
+               dev_err(&dev->dev,
+                        "Failed to send signal to w1 kernel thread %d.\n",
+                        dev->kpid);
+       wait_for_completion(&dev->dev_exited);
+
+err_out_free_dev:
+       w1_free_dev(dev);
+
+       return retval;
+}
+
+void __w1_remove_master_device(struct w1_master *dev)
+{
+       int err;
+
+       dev->need_exit = 1;
+       err = kill_proc(dev->kpid, SIGTERM, 1);
+       if (err)
+               dev_err(&dev->dev,
+                        "%s: Failed to send signal to w1 kernel thread %d.\n",
+                        __func__, dev->kpid);
+
+       while (atomic_read(&dev->refcnt))
+               schedule_timeout(10);
+
+       w1_free_dev(dev);
+}
+
+void w1_remove_master_device(struct w1_bus_master *bm)
+{
+       struct w1_master *dev = NULL;
+       struct list_head *ent, *n;
+
+       list_for_each_safe(ent, n, &w1_masters) {
+               dev = list_entry(ent, struct w1_master, w1_master_entry);
+               if (!dev->initialized)
+                       continue;
+
+               if (dev->bus_master->data == bm->data)
+                       break;
+       }
+
+       if (!dev) {
+               printk(KERN_ERR "Device doesn't exist.\n");
+               return;
+       }
+
+       __w1_remove_master_device(dev);
+}
+
+EXPORT_SYMBOL(w1_alloc_dev);
+EXPORT_SYMBOL(w1_free_dev);
+EXPORT_SYMBOL(w1_add_master_device);
+EXPORT_SYMBOL(w1_remove_master_device);
+EXPORT_SYMBOL(__w1_remove_master_device);
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
new file mode 100644 (file)
index 0000000..9baacee
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *     w1_io.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; 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 <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+
+#include "w1.h"
+#include "w1_log.h"
+#include "w1_io.h"
+
+int w1_delay_parm = 1;
+module_param_named(delay_coef, w1_delay_parm, int, 0);
+
+static u8 w1_crc8_table[] = {
+       0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
+       157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
+       35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
+       190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
+       70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
+       219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
+       101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
+       248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
+       140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
+       17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
+       175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
+       50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
+       202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
+       87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
+       233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
+       116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
+};
+
+void w1_delay(unsigned long tm)
+{
+       udelay(tm * w1_delay_parm);
+}
+
+void w1_write_bit(struct w1_master *dev, int bit)
+{
+       if (bit) {
+               dev->bus_master->write_bit(dev->bus_master->data, 0);
+               w1_delay(6);
+               dev->bus_master->write_bit(dev->bus_master->data, 1);
+               w1_delay(64);
+       } else {
+               dev->bus_master->write_bit(dev->bus_master->data, 0);
+               w1_delay(60);
+               dev->bus_master->write_bit(dev->bus_master->data, 1);
+               w1_delay(10);
+       }
+}
+
+void w1_write_8(struct w1_master *dev, u8 byte)
+{
+       int i;
+
+       for (i = 0; i < 8; ++i)
+               w1_write_bit(dev, (byte >> i) & 0x1);
+}
+
+u8 w1_read_bit(struct w1_master *dev)
+{
+       int result;
+
+       dev->bus_master->write_bit(dev->bus_master->data, 0);
+       w1_delay(6);
+       dev->bus_master->write_bit(dev->bus_master->data, 1);
+       w1_delay(9);
+
+       result = dev->bus_master->read_bit(dev->bus_master->data);
+       w1_delay(55);
+
+       return result & 0x1;
+}
+
+u8 w1_read_8(struct w1_master * dev)
+{
+       int i;
+       u8 res = 0;
+
+       for (i = 0; i < 8; ++i)
+               res |= (w1_read_bit(dev) << i);
+
+       return res;
+}
+
+int w1_reset_bus(struct w1_master *dev)
+{
+       int result;
+
+       dev->bus_master->write_bit(dev->bus_master->data, 0);
+       w1_delay(480);
+       dev->bus_master->write_bit(dev->bus_master->data, 1);
+       w1_delay(70);
+
+       result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
+       w1_delay(410);
+
+       return result;
+}
+
+u8 w1_calc_crc8(u8 * data, int len)
+{
+       u8 crc = 0;
+
+       while (len--)
+               crc = w1_crc8_table[crc ^ *data++];
+
+       return crc;
+}
+
+EXPORT_SYMBOL(w1_write_bit);
+EXPORT_SYMBOL(w1_write_8);
+EXPORT_SYMBOL(w1_read_bit);
+EXPORT_SYMBOL(w1_read_8);
+EXPORT_SYMBOL(w1_reset_bus);
+EXPORT_SYMBOL(w1_calc_crc8);
+EXPORT_SYMBOL(w1_delay);
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
new file mode 100644 (file)
index 0000000..a1b3c63
--- /dev/null
@@ -0,0 +1,17 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = 
+obj-$(CONFIG_EXTERNFS) += externfs.o
+obj-$(CONFIG_HOSTFS) += host_fs.o host_file.o
+obj-$(CONFIG_HUMFS) += humfs.o meta_fs.o
+
+SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+
+USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
diff --git a/fs/hostfs/externfs.c b/fs/hostfs/externfs.c
new file mode 100644 (file)
index 0000000..884c33c
--- /dev/null
@@ -0,0 +1,1317 @@
+/* 
+ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "user_util.h"
+#include "2_5compat.h"
+#include "mem.h"
+#include "filehandle.h"
+
+struct externfs {
+       struct list_head list;
+       struct externfs_mount_ops *mount_ops;
+       struct file_system_type type;
+};
+
+static inline struct externfs_inode *EXTERNFS_I(struct inode *inode)
+{
+       return(container_of(inode, struct externfs_inode, vfs_inode));
+}
+
+#define file_externfs_i(file) EXTERNFS_I((file)->f_dentry->d_inode)
+
+int externfs_d_delete(struct dentry *dentry)
+{
+       return(1);
+}
+
+struct dentry_operations externfs_dentry_ops = {
+};
+
+#define EXTERNFS_SUPER_MAGIC 0x00c0ffee
+
+static struct inode_operations externfs_iops;
+static struct inode_operations externfs_dir_iops;
+static struct address_space_operations externfs_link_aops;
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+       struct dentry *parent;
+       char *name;
+       int len;
+
+       len = 0;
+       parent = dentry;
+       while(parent->d_parent != parent){
+               len += parent->d_name.len + 1;
+               parent = parent->d_parent;
+       }
+       
+       name = kmalloc(len + extra + 1, GFP_KERNEL);
+       if(name == NULL) return(NULL);
+
+       name[len] = '\0';
+       parent = dentry;
+       while(parent->d_parent != parent){
+               len -= parent->d_name.len + 1;
+               name[len] = '/';
+               strncpy(&name[len + 1], parent->d_name.name, 
+                       parent->d_name.len);
+               parent = parent->d_parent;
+       }
+
+       return(name);
+}
+
+char *inode_name(struct inode *ino, int extra)
+{
+       struct dentry *dentry;
+
+       dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
+       return(dentry_name(dentry, extra));
+}
+
+char *inode_name_prefix(struct inode *inode, char *prefix)
+{
+       int len;
+       char *name;
+
+       len = strlen(prefix);
+       name = inode_name(inode, len);
+       if(name == NULL)
+               return(name);
+
+       memmove(&name[len], name, strlen(name) + 1);
+       memcpy(name, prefix, strlen(prefix));
+       return(name);
+}
+
+static int read_name(struct inode *ino, char *name)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       /* The non-int inode fields are copied into ints by stat_file and
+        * then copied into the inode because passing the actual pointers
+        * in and having them treated as int * breaks on big-endian machines
+        */
+       dev_t i_rdev;
+       int err;
+       int i_mode, i_nlink, i_blksize;
+       unsigned long atime, mtime, ctime;
+       unsigned long long i_size;
+       unsigned long long i_ino;
+       unsigned long long i_blocks;
+
+       err = (*ops->stat_file)(name, ino->i_sb->s_fs_info, &i_rdev, &i_ino,
+                               &i_mode, &i_nlink, &ino->i_uid, &ino->i_gid,
+                               &i_size, &atime, &mtime, &ctime, &i_blksize, 
+                               &i_blocks);
+       if(err) return(err);
+
+       ino->i_atime.tv_sec = atime;
+       ino->i_atime.tv_nsec = 0;
+       
+       ino->i_ctime.tv_sec = ctime;
+       ino->i_ctime.tv_nsec = 0;
+       
+       ino->i_mtime.tv_sec = mtime;
+       ino->i_mtime.tv_nsec = 0;
+
+       ino->i_ino = i_ino;
+       ino->i_rdev = i_rdev;
+       ino->i_mode = i_mode;
+       ino->i_nlink = i_nlink;
+       ino->i_size = i_size;
+       ino->i_blksize = i_blksize;
+       ino->i_blocks = i_blocks;
+       return(0);
+}
+
+static char *follow_link(char *link, 
+                        int (*do_read_link)(char *path, int uid, int gid,
+                                            char *buf, int size, 
+                                            struct externfs_data *ed),
+                        int uid, int gid, struct externfs_data *ed)
+{
+       int len, n;
+       char *name, *resolved, *end;
+
+       len = 64;
+       while(1){
+               n = -ENOMEM;
+               name = kmalloc(len, GFP_KERNEL);
+               if(name == NULL)
+                       goto out;
+
+               n = (*do_read_link)(link, uid, gid, name, len, ed);
+               if(n < len)
+                       break;
+               len *= 2;
+               kfree(name);
+       }
+       if(n < 0)
+               goto out_free;
+
+       if(*name == '/')
+               return(name);
+
+       end = strrchr(link, '/');
+       if(end == NULL)
+               return(name);
+
+       *(end + 1) = '\0';
+       len = strlen(link) + strlen(name) + 1;
+
+       resolved = kmalloc(len, GFP_KERNEL);
+       if(resolved == NULL){
+               n = -ENOMEM;
+               goto out_free;
+       }
+
+       sprintf(resolved, "%s%s", link, name);
+       kfree(name);
+       return(resolved);
+
+ out_free:
+       kfree(name);
+ out:
+       return(ERR_PTR(n));
+}
+
+static int read_inode(struct inode *ino)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *name, *new;
+       int err = 0, type;
+
+       /* Unfortunately, we are called from iget() when we don't have a dentry
+        * allocated yet.
+        */
+       if(list_empty(&ino->i_dentry))
+               goto out;
+       err = -ENOMEM;
+       name = inode_name(ino, 0);
+       if(name == NULL) 
+               goto out;
+
+       type = (*ops->file_type)(name, NULL, ed);
+       if(type < 0){
+               err = type;
+               goto out_free;
+       }
+
+       if(type == OS_TYPE_SYMLINK){
+               new = follow_link(name, ops->read_link, current->fsuid,
+                                 current->fsgid, ed);
+               if(IS_ERR(new)){
+                       err = PTR_ERR(new);
+                       goto out_free;
+               }
+               kfree(name);
+               name = new;
+       }
+       
+       err = read_name(ino, name);
+ out_free:
+       kfree(name);
+ out:
+       return(err);
+}
+
+int externfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+       /* do_statfs uses struct statfs64 internally, but the linux kernel
+        * struct statfs still has 32-bit versions for most of these fields,
+        * so we convert them here
+        */
+       int err;
+       long long f_blocks;
+       long long f_bfree;
+       long long f_bavail;
+       long long f_files;
+       long long f_ffree;
+       struct externfs_data *ed = sb->s_fs_info;
+       
+       err = (*ed->file_ops->statfs)(&sf->f_bsize, &f_blocks, &f_bfree, 
+                                     &f_bavail, &f_files, &f_ffree, 
+                                     &sf->f_fsid, sizeof(sf->f_fsid), 
+                                     &sf->f_namelen, sf->f_spare, ed);
+       if(err)
+               return(err);
+
+       sf->f_blocks = f_blocks;
+       sf->f_bfree = f_bfree;
+       sf->f_bavail = f_bavail;
+       sf->f_files = f_files;
+       sf->f_ffree = f_ffree;
+       sf->f_type = EXTERNFS_SUPER_MAGIC;
+       return(0);
+}
+
+static struct inode *externfs_alloc_inode(struct super_block *sb)
+{
+       struct externfs_data *ed = sb->s_fs_info;
+       struct externfs_inode *ext;
+
+       ext = (*ed->mount_ops->init_file)(ed);
+       if(ext == NULL) 
+               return(NULL);
+
+       *ext = ((struct externfs_inode) { .ops  = ed->file_ops });
+
+       inode_init_once(&ext->vfs_inode);
+       return(&ext->vfs_inode);
+}
+
+static void externfs_destroy_inode(struct inode *inode)
+{
+       struct externfs_inode *ext = EXTERNFS_I(inode);
+
+       (*ext->ops->close_file)(ext, inode->i_size);
+}
+
+static void externfs_read_inode(struct inode *inode)
+{
+       read_inode(inode);
+}
+
+static struct super_operations externfs_sbops = { 
+       .alloc_inode    = externfs_alloc_inode,
+       .destroy_inode  = externfs_destroy_inode,
+       .read_inode     = externfs_read_inode,
+       .statfs         = externfs_statfs,
+};
+
+int externfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+       void *dir;
+       char *name;
+       unsigned long long next, ino;
+       int error, len;
+       struct externfs_file_ops *ops = file_externfs_i(file)->ops;
+       struct externfs_data *ed = file->f_dentry->d_inode->i_sb->s_fs_info;
+
+       name = dentry_name(file->f_dentry, 0);
+       if(name == NULL) 
+               return(-ENOMEM);
+
+       dir = (*ops->open_dir)(name, current->fsuid, current->fsgid, ed);
+       kfree(name);
+       if(IS_ERR(dir)) 
+               return(PTR_ERR(dir));
+
+       next = file->f_pos;
+       while((name = (*ops->read_dir)(dir, &next, &ino, &len, ed)) != NULL){
+               error = (*filldir)(ent, name, len, file->f_pos, ino, 
+                                  DT_UNKNOWN);
+               if(error) 
+                       break;
+               file->f_pos = next;
+       }
+       (*ops->close_dir)(dir, ed);
+       return(0);
+}
+
+int externfs_file_open(struct inode *ino, struct file *file)
+{
+       ino->i_nlink++;
+       return(0);
+}
+
+int externfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       struct externfs_file_ops *ops = file_externfs_i(file)->ops;
+       struct inode *inode = dentry->d_inode;
+       struct externfs_data *ed = inode->i_sb->s_fs_info;
+
+       return((*ops->truncate_file)(EXTERNFS_I(inode), inode->i_size, ed));
+}
+
+static struct file_operations externfs_file_fops = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_file_read,
+       .write          = generic_file_write,
+       .mmap           = generic_file_mmap,
+       .open           = externfs_file_open,
+       .release        = NULL,
+       .fsync          = externfs_fsync,
+};
+
+static struct file_operations externfs_dir_fops = {
+       .readdir        = externfs_readdir,
+       .read           = generic_read_dir,
+};
+
+struct wp_info {
+       struct page *page;
+       int count;
+       unsigned long long start;
+       unsigned long long size;
+       int (*truncate)(struct externfs_inode *ext, __u64 size, 
+                       struct externfs_data *ed);
+       struct externfs_inode *ei;
+       struct externfs_data *ed;
+};
+
+static void externfs_finish_writepage(char *buffer, int res, void *arg)
+{
+       struct wp_info *wp = arg;
+
+       if(res == wp->count){
+               ClearPageError(wp->page);
+               if(wp->start + res > wp->size)
+                       (*wp->truncate)(wp->ei, wp->size, wp->ed);
+       }
+       else {
+               SetPageError(wp->page);
+               ClearPageUptodate(wp->page);
+       }               
+
+       kunmap(wp->page);
+       unlock_page(wp->page);
+       kfree(wp);
+}
+
+int externfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
+       struct wp_info *wp;
+       struct externfs_data *ed = inode->i_sb->s_fs_info;
+       char *buffer;
+       unsigned long long base;
+       int count = PAGE_CACHE_SIZE;
+       int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+       int err, offset;
+
+       base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
+
+       /* If we are entirely outside the file, then return an error */
+       err = -EIO;
+       offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+       if (page->index > end_index || 
+           ((page->index == end_index) && !offset))
+               goto out_unlock;
+
+       err = -ENOMEM;
+       wp = kmalloc(sizeof(*wp), GFP_KERNEL);
+       if(wp == NULL)
+               goto out_unlock;
+
+       *wp = ((struct wp_info) { .page         = page,
+                                 .count        = count,
+                                 .start        = base,
+                                 .size         = inode->i_size,
+                                 .truncate     = ops->truncate_file,
+                                 .ei           = EXTERNFS_I(inode),
+                                 .ed           = ed });
+
+       buffer = kmap(page);
+       err = (*ops->write_file)(EXTERNFS_I(inode), base, buffer, 0, 
+                                count, externfs_finish_writepage, wp, ed);
+
+       return err;
+
+ out_unlock:
+       unlock_page(page);
+       return(err);
+}
+
+static void externfs_finish_readpage(char *buffer, int res, void *arg)
+{
+       struct page *page = arg;
+       struct inode *inode;
+
+       if(res < 0){
+               SetPageError(page);
+               goto out;
+       }
+
+       inode = page->mapping->host;
+       if(inode->i_size >> PAGE_CACHE_SHIFT == page->index)
+               res = inode->i_size % PAGE_CACHE_SIZE;
+
+       memset(&buffer[res], 0, PAGE_CACHE_SIZE - res);
+
+       flush_dcache_page(page);
+       SetPageUptodate(page);
+       if (PageError(page)) 
+               ClearPageError(page);
+ out:
+       kunmap(page);
+       unlock_page(page);
+}
+
+static int externfs_readpage(struct file *file, struct page *page)
+{
+       struct inode *ino = page->mapping->host;
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *buffer;
+       long long start;
+       int err = 0;
+
+       start = (long long) page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+
+       if(ops->map_file_page != NULL){
+               /* XXX What happens when PAGE_SIZE != PAGE_CACHE_SIZE? */
+               err = (*ops->map_file_page)(file_externfs_i(file), start, 
+                                           buffer, file->f_mode & FMODE_WRITE,
+                                           ed);
+               if(!err)
+                       err = PAGE_CACHE_SIZE;
+       }
+       else err = (*ops->read_file)(file_externfs_i(file), start, buffer,
+                                    PAGE_CACHE_SIZE, 0, 0, 
+                                    externfs_finish_readpage, page, ed);
+
+       if(err > 0)
+               err = 0;
+       return(err);
+}
+
+struct writepage_info {
+       struct semaphore sem;
+       int res;
+};
+
+static void externfs_finish_prepare(char *buffer, int res, void *arg)
+{
+       struct writepage_info *wp = arg;
+
+       wp->res = res;
+       up(&wp->sem);
+}
+
+int externfs_prepare_write(struct file *file, struct page *page, 
+                        unsigned int from, unsigned int to)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
+       struct externfs_data *ed = inode->i_sb->s_fs_info;
+       char *buffer;
+       long long start;
+       int err;
+       struct writepage_info wp;
+
+       if(PageUptodate(page))
+               return(0);
+
+       start = (long long) page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+
+       if(ops->map_file_page != NULL){
+               err = (*ops->map_file_page)(file_externfs_i(file), start, 
+                                           buffer, file->f_mode & FMODE_WRITE,
+                                           ed);
+               goto out;
+               
+       }
+
+       init_MUTEX_LOCKED(&wp.sem);
+       err = (*ops->read_file)(file_externfs_i(file), start, buffer,
+                               PAGE_CACHE_SIZE, from, to, 
+                               externfs_finish_prepare, &wp, ed);
+       down(&wp.sem);
+       if(err < 0) 
+               goto out;
+
+       err = wp.res;
+       if(err < 0)
+               goto out;
+
+       if(from > 0)
+               memset(buffer, 0, from);
+       if(to < PAGE_CACHE_SIZE)
+               memset(buffer + to, 0, PAGE_CACHE_SIZE - to);
+
+       SetPageUptodate(page);
+       err = 0;
+ out:
+       kunmap(page);
+       return(err);
+}
+
+static int externfs_commit_write(struct file *file, struct page *page, 
+                              unsigned from, unsigned to)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
+       unsigned long long size;
+       long long start;
+       int err;
+
+       start = (long long) (page->index << PAGE_CACHE_SHIFT);
+
+       if(ops->map_file_page != NULL)
+               err = to - from;
+       else {
+               size = start + to;
+               if(size > inode->i_size){
+                       inode->i_size = size;
+                       mark_inode_dirty(inode);
+               }
+       }
+
+       set_page_dirty(page);
+       return(to - from);
+}
+
+static int externfs_removepage(struct page *page, int gfpmask)
+{
+       physmem_remove_mapping(page_address(page));
+       return(0);
+}
+
+static struct address_space_operations externfs_aops = {
+       .writepage      = externfs_writepage,
+       .readpage       = externfs_readpage,
+       .releasepage    = externfs_removepage,
+/*     .set_page_dirty = __set_page_dirty_nobuffers, */
+       .prepare_write  = externfs_prepare_write,
+       .commit_write   = externfs_commit_write
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+       char *name = NULL;
+       int type, err = -ENOMEM, rdev;
+       struct externfs_inode *ext = EXTERNFS_I(inode);
+       struct externfs_file_ops *ops = ext->ops;
+       struct externfs_data *ed = inode->i_sb->s_fs_info;      
+
+       if(dentry){
+               name = dentry_name(dentry, 0);
+               if(name == NULL)
+                       goto out;
+               type = (*ops->file_type)(name, &rdev, ed);
+       }
+       else type = OS_TYPE_DIR;
+
+       err = 0;
+       if(type == OS_TYPE_SYMLINK)
+               inode->i_op = &page_symlink_inode_operations;
+       else if(type == OS_TYPE_DIR)
+               inode->i_op = &externfs_dir_iops;
+       else inode->i_op = &externfs_iops;
+
+       if(type == OS_TYPE_DIR) inode->i_fop = &externfs_dir_fops;
+       else inode->i_fop = &externfs_file_fops;
+
+       if(type == OS_TYPE_SYMLINK) 
+               inode->i_mapping->a_ops = &externfs_link_aops;
+       else inode->i_mapping->a_ops = &externfs_aops;
+
+       switch (type) {
+       case OS_TYPE_CHARDEV:
+               init_special_inode(inode, S_IFCHR, rdev);
+               break;
+       case OS_TYPE_BLOCKDEV:
+               init_special_inode(inode, S_IFBLK, rdev);
+               break;
+       case OS_TYPE_FIFO:
+               init_special_inode(inode, S_IFIFO, 0);
+               break;
+       case OS_TYPE_SOCK:
+               init_special_inode(inode, S_IFSOCK, 0);
+               break;
+       case OS_TYPE_SYMLINK:
+               inode->i_mode = S_IFLNK | S_IRWXUGO;
+       }
+
+       err = (*ops->open_file)(ext, name, current->fsuid, current->fsgid, 
+                               inode, ed);
+       if((err != -EISDIR) && (err != -ENOENT) && (err != -ENXIO))
+               goto out_put;
+
+       err = 0;
+
+ out_free:
+       kfree(name);
+ out:
+       return(err);
+
+ out_put:
+       iput(inode);
+       goto out_free;
+}
+
+int externfs_create(struct inode *dir, struct dentry *dentry, int mode, 
+                 struct nameidata *nd)
+{
+       struct externfs_inode *ext = EXTERNFS_I(dir);
+       struct externfs_file_ops *ops = ext->ops;
+       struct inode *inode;
+       struct externfs_data *ed = dir->i_sb->s_fs_info;
+       char *name;
+       int err = -ENOMEM;
+
+       inode = iget(dir->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+       
+       err = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       err = (*ops->create_file)(ext, name, mode, current->fsuid, 
+                                 current->fsuid, inode, ed);
+       if(err)
+               goto out_free;
+
+       err = read_name(inode, name);
+       if(err)
+               goto out_rm;
+
+       inode->i_nlink++;
+       d_instantiate(dentry, inode);
+       kfree(name);
+ out:
+       return(err);
+
+ out_rm:
+       (*ops->unlink_file)(name, ed);
+ out_free:
+       kfree(name);
+ out_put:
+       inode->i_nlink = 0;
+       iput(inode);
+       goto out;
+}
+struct dentry *externfs_lookup(struct inode *ino, struct dentry *dentry, 
+                              struct nameidata *nd)
+{
+       struct inode *inode;
+       char *name;
+       int err = -ENOMEM;
+
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+       
+       err = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       err = read_name(inode, name);
+       kfree(name);
+       if(err){
+               if(err != -ENOENT)
+                       goto out_put;
+
+               inode->i_nlink = 0;
+               iput(inode);
+               inode = NULL;
+       }
+       d_add(dentry, inode);
+       dentry->d_op = &externfs_dentry_ops;
+       return(NULL);
+
+ out_put:
+       inode->i_nlink = 0;
+       iput(inode);
+ out:
+       return(ERR_PTR(err));
+}
+
+static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
+{
+        char *file;
+       int len;
+
+       file = inode_name(ino, dentry->d_name.len + 1);
+       if(file == NULL) return(NULL);
+        strcat(file, "/");
+       len = strlen(file);
+        strncat(file, dentry->d_name.name, dentry->d_name.len);
+       file[len + dentry->d_name.len] = '\0';
+        return(file);
+}
+
+int externfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+        char *from_name, *to_name;
+        int err = -ENOMEM;
+
+        from_name = inode_dentry_name(ino, from); 
+        if(from_name == NULL) 
+               goto out;
+
+        to_name = dentry_name(to, 0);
+       if(to_name == NULL)
+               goto out_free_from;
+
+        err = (*ops->link_file)(to_name, from_name, current->fsuid, 
+                               current->fsgid, ed);
+       if(err)
+               goto out_free_to;
+
+       d_instantiate(from, to->d_inode);
+       to->d_inode->i_nlink++;
+       atomic_inc(&to->d_inode->i_count);
+
+ out_free_to:
+        kfree(to_name);
+ out_free_from:
+        kfree(from_name);
+ out:
+        return(err);
+}
+
+int externfs_unlink(struct inode *ino, struct dentry *dentry)
+{
+       struct inode *inode;
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *file;
+       int err;
+
+       file = inode_dentry_name(ino, dentry);
+       if(file == NULL) 
+               return(-ENOMEM);
+
+       inode = dentry->d_inode;
+       if((inode->i_nlink == 1) && (ops->invisible != NULL))
+               (*ops->invisible)(EXTERNFS_I(inode));
+
+       err = (*ops->unlink_file)(file, ed);
+       kfree(file);
+
+       inode->i_nlink--;
+
+       return(err);
+}
+
+int externfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct inode *inode;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *file;
+       int err;
+
+       file = inode_dentry_name(ino, dentry);
+       if(file == NULL) 
+               return(-ENOMEM);
+       err = (*ops->make_symlink)(file, to, current->fsuid, current->fsgid,
+                                  ed);
+       kfree(file);
+       if(err) 
+               goto out;
+
+       err = -ENOMEM;
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+       
+       d_instantiate(dentry, inode);
+       inode->i_nlink++;
+ out:
+       return(err);
+
+ out_put:
+       iput(inode);
+       goto out;
+}
+
+int externfs_make_dir(struct inode *ino, struct dentry *dentry, int mode)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct inode *inode;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *file;
+       int err = -ENOMEM;
+
+       file = inode_dentry_name(ino, dentry);
+       if(file == NULL) 
+               goto out;
+       err = (*ops->make_dir)(file, mode, current->fsuid, current->fsgid, ed);
+
+       err = -ENOMEM;
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out_free;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+       
+       err = read_name(inode, file);
+       if(err)
+               goto out_put;
+
+       kfree(file);
+       d_instantiate(dentry, inode);
+       inode->i_nlink = 2;
+       inode->i_mode = S_IFDIR | mode;
+
+       ino->i_nlink++;
+ out:
+       return(err);
+ out_put:
+       inode->i_nlink = 0;
+       iput(inode);
+ out_free:
+       kfree(file);
+       goto out;       
+}
+
+int externfs_remove_dir(struct inode *ino, struct dentry *dentry)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *file;
+       int err;
+
+       file = inode_dentry_name(ino, dentry);
+       if(file == NULL) 
+               return(-ENOMEM);
+       err = (*ops->remove_dir)(file, current->fsuid, current->fsgid, ed);
+       kfree(file);
+
+       dentry->d_inode->i_nlink = 0;
+       ino->i_nlink--;
+       return(err);
+}
+
+int externfs_make_node(struct inode *dir, struct dentry *dentry, int mode, 
+                    dev_t dev)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops;
+       struct externfs_data *ed = dir->i_sb->s_fs_info;
+       struct inode *inode;
+       char *name;
+       int err = -ENOMEM;
+       inode = iget(dir->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+
+       err = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       init_special_inode(inode, mode, dev);
+       err = (*ops->make_node)(name, mode & S_IRWXUGO, current->fsuid, 
+                               current->fsgid, mode & S_IFMT, MAJOR(dev), 
+                               MINOR(dev), ed);
+       if(err)
+               goto out_free;
+       
+       err = read_name(inode, name);
+       if(err)
+               goto out_rm;
+
+       inode->i_nlink++;
+       d_instantiate(dentry, inode);
+       kfree(name);
+ out:
+       return(err);
+
+ out_rm:
+       (*ops->unlink_file)(name, ed);
+ out_free:
+       kfree(name);
+ out_put:
+       inode->i_nlink = 0;
+       iput(inode);
+       goto out;
+}
+
+int externfs_rename(struct inode *from_ino, struct dentry *from,
+                 struct inode *to_ino, struct dentry *to)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(from_ino)->ops;
+       struct externfs_data *ed = from_ino->i_sb->s_fs_info;
+       char *from_name, *to_name;
+       int err;
+
+       from_name = inode_dentry_name(from_ino, from);
+       if(from_name == NULL)
+               return(-ENOMEM);
+       to_name = inode_dentry_name(to_ino, to);
+       if(to_name == NULL){
+               kfree(from_name);
+               return(-ENOMEM);
+       }
+       err = (*ops->rename_file)(from_name, to_name, ed);
+       kfree(from_name);
+       kfree(to_name);
+
+       from_ino->i_nlink--;
+       to_ino->i_nlink++;
+       return(err);
+}
+
+void externfs_truncate(struct inode *ino)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+
+       (*ops->truncate_file)(EXTERNFS_I(ino), ino->i_size, ed);
+}
+
+int externfs_permission(struct inode *ino, int desired, struct nameidata *nd)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *name;
+       int r = 0, w = 0, x = 0, err;
+
+       if(ops->access_file == NULL)
+               return(vfs_permission(ino, desired));
+
+       if(desired & MAY_READ) r = 1;
+       if(desired & MAY_WRITE) w = 1;
+       if(desired & MAY_EXEC) x = 1;
+       name = inode_name(ino, 0);
+       if(name == NULL) 
+               return(-ENOMEM);
+
+       err = (*ops->access_file)(name, r, w, x, current->fsuid,
+                                 current->fsgid, ed);
+       kfree(name);
+
+       if(!err) 
+               err = vfs_permission(ino, desired);
+       return(err);
+}
+
+int externfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct externfs_file_ops *ops = EXTERNFS_I(dentry->d_inode)->ops;
+       struct externfs_data *ed = dentry->d_inode->i_sb->s_fs_info;
+       struct externfs_iattr attrs;
+       char *name;
+       int err;
+       
+       attrs.ia_valid = 0;
+       if(attr->ia_valid & ATTR_MODE){
+               attrs.ia_valid |= EXTERNFS_ATTR_MODE;
+               attrs.ia_mode = attr->ia_mode;
+       }
+       if(attr->ia_valid & ATTR_UID){
+               attrs.ia_valid |= EXTERNFS_ATTR_UID;
+               attrs.ia_uid = attr->ia_uid;
+       }
+       if(attr->ia_valid & ATTR_GID){
+               attrs.ia_valid |= EXTERNFS_ATTR_GID;
+               attrs.ia_gid = attr->ia_gid;
+       }
+       if(attr->ia_valid & ATTR_SIZE){
+               attrs.ia_valid |= EXTERNFS_ATTR_SIZE;
+               attrs.ia_size = attr->ia_size;
+       }
+       if(attr->ia_valid & ATTR_ATIME){
+               attrs.ia_valid |= EXTERNFS_ATTR_ATIME;
+               attrs.ia_atime = attr->ia_atime.tv_sec;
+       }
+       if(attr->ia_valid & ATTR_MTIME){
+               attrs.ia_valid |= EXTERNFS_ATTR_MTIME;
+               attrs.ia_mtime = attr->ia_mtime.tv_sec;
+       }
+       if(attr->ia_valid & ATTR_CTIME){
+               attrs.ia_valid |= EXTERNFS_ATTR_CTIME;
+               attrs.ia_ctime = attr->ia_ctime.tv_sec;
+       }
+       if(attr->ia_valid & ATTR_ATIME_SET){
+               attrs.ia_valid |= EXTERNFS_ATTR_ATIME_SET;
+               attrs.ia_atime = attr->ia_atime.tv_sec;
+       }
+       if(attr->ia_valid & ATTR_MTIME_SET){
+               attrs.ia_valid |= EXTERNFS_ATTR_MTIME_SET;
+       }
+       name = dentry_name(dentry, 0);
+       if(name == NULL) 
+               return(-ENOMEM);
+       err = (*ops->set_attr)(name, &attrs, ed);
+       kfree(name);
+       if(err)
+               return(err);
+
+       return(inode_setattr(dentry->d_inode, attr));
+}
+
+int externfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 
+                    struct kstat *stat)
+{
+       generic_fillattr(dentry->d_inode, stat);
+       return(0);
+}
+
+static struct inode_operations externfs_iops = {
+       .create         = externfs_create,
+       .link           = externfs_link,
+       .unlink         = externfs_unlink,
+       .symlink        = externfs_symlink,
+       .mkdir          = externfs_make_dir,
+       .rmdir          = externfs_remove_dir,
+       .mknod          = externfs_make_node,
+       .rename         = externfs_rename,
+       .truncate       = externfs_truncate,
+       .permission     = externfs_permission,
+       .setattr        = externfs_setattr,
+       .getattr        = externfs_getattr,
+};
+
+static struct inode_operations externfs_dir_iops = {
+       .create         = externfs_create,
+       .lookup         = externfs_lookup,
+       .link           = externfs_link,
+       .unlink         = externfs_unlink,
+       .symlink        = externfs_symlink,
+       .mkdir          = externfs_make_dir,
+       .rmdir          = externfs_remove_dir,
+       .mknod          = externfs_make_node,
+       .rename         = externfs_rename,
+       .truncate       = externfs_truncate,
+       .permission     = externfs_permission,
+       .setattr        = externfs_setattr,
+       .getattr        = externfs_getattr,
+};
+
+int externfs_link_readpage(struct file *file, struct page *page)
+{
+       struct inode *ino = page->mapping->host;
+       struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
+       struct externfs_data *ed = ino->i_sb->s_fs_info;
+       char *buffer, *name;
+       long long start;
+       int err;
+
+       start = page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+       name = inode_name(ino, 0);
+       if(name == NULL) 
+               return(-ENOMEM);
+
+       err = (*ops->read_link)(name, current->fsuid, current->fsgid, buffer, 
+                               PAGE_CACHE_SIZE, ed);
+
+       kfree(name);
+       if(err == PAGE_CACHE_SIZE)
+               err = -E2BIG;
+       else if(err > 0){
+               flush_dcache_page(page);
+               SetPageUptodate(page);
+               if (PageError(page)) ClearPageError(page);
+               err = 0;
+       }
+       kunmap(page);
+       unlock_page(page);
+       return(err);
+}
+
+static int externfs_flushpage(struct page *page, unsigned long offset)
+{
+       return(externfs_writepage(page, NULL));
+}
+
+struct externfs_data *inode_externfs_info(struct inode *inode)
+{
+       return(inode->i_sb->s_fs_info);
+}
+
+static struct address_space_operations externfs_link_aops = {
+       .readpage       = externfs_link_readpage,
+       .releasepage    = externfs_removepage,
+       .invalidatepage = externfs_flushpage,
+};
+
+DECLARE_MUTEX(externfs_sem);
+struct list_head externfses = LIST_HEAD_INIT(externfses);
+
+static struct externfs *find_externfs(struct file_system_type *type)
+{
+       struct list_head *ele;
+       struct externfs *fs;
+
+       down(&externfs_sem);
+       list_for_each(ele, &externfses){
+               fs = list_entry(ele, struct externfs, list);
+               if(&fs->type == type)
+                       goto out;
+       }
+       fs = NULL;
+ out:
+       up(&externfs_sem);
+       return(fs);
+}
+
+#define DEFAULT_ROOT "/"
+
+char *host_root_filename(char *mount_arg)
+{
+       char *root = DEFAULT_ROOT;
+
+       if((mount_arg != NULL) && (*mount_arg != '\0'))
+               root = mount_arg;
+
+       return(uml_strdup(root));
+}
+
+static int externfs_fill_sb(struct super_block *sb, void *data, int silent)
+{
+       struct externfs *fs;
+       struct inode *root_inode;
+       struct externfs_data *sb_data;
+       int err = -EINVAL;
+
+       sb->s_blocksize = 1024;
+       sb->s_blocksize_bits = 10;
+       sb->s_magic = EXTERNFS_SUPER_MAGIC;
+       sb->s_op = &externfs_sbops;
+
+       fs = find_externfs(sb->s_type);
+       if(fs == NULL){
+               printk("Couldn't find externfs for filesystem '%s'\n",
+                      sb->s_type->name);
+               goto out;
+       }
+
+       sb_data = (*fs->mount_ops->mount)(data);
+       if(IS_ERR(sb_data)){
+               err = PTR_ERR(sb_data);
+               goto out;
+       }
+               
+       sb->s_fs_info = sb_data;
+       sb_data->mount_ops = fs->mount_ops;
+
+       root_inode = iget(sb, 0);
+       if(root_inode == NULL)
+               goto out;
+
+       err = init_inode(root_inode, NULL);
+       if(err)
+               goto out_put;
+
+       err = -ENOMEM;
+       sb->s_root = d_alloc_root(root_inode);
+       if(sb->s_root == NULL)
+               goto out_put;
+
+       err = read_inode(root_inode);
+       if(err)
+               goto out_put;
+
+ out:
+       return(err);
+
+ out_put:
+       iput(root_inode);
+       goto out;
+}      
+
+struct super_block *externfs_read_super(struct file_system_type *type, 
+                                       int flags, const char *dev_name, 
+                                       void *data)
+{
+       return(get_sb_nodev(type, flags, data, externfs_fill_sb));
+}
+
+void init_externfs(struct externfs_data *ed, struct externfs_file_ops *ops)
+{
+       ed->file_ops = ops;
+}
+
+int register_externfs(char *name, struct externfs_mount_ops *mount_ops)
+{
+       struct externfs *new;
+       int err = -ENOMEM;
+
+       new = kmalloc(sizeof(*new), GFP_KERNEL);
+       if(new == NULL)
+               goto out;
+
+       memset(new, 0, sizeof(*new));
+       *new = ((struct externfs) { .list       = LIST_HEAD_INIT(new->list),
+                                   .mount_ops  = mount_ops,
+                                   .type = { .name     = name,
+                                             .get_sb   = externfs_read_super,
+                                             .kill_sb  = kill_anon_super,
+                                             .fs_flags = 0,
+                                             .owner    = THIS_MODULE } });
+       list_add(&new->list, &externfses);
+
+       err = register_filesystem(&new->type);
+       if(err)
+               goto out_del;
+       return(0);
+
+ out_del:
+       list_del(&new->list);
+       kfree(new);
+ out:
+       return(err);
+}
+
+void unregister_externfs(char *name)
+{
+       struct list_head *ele;
+       struct externfs *fs;
+
+       down(&externfs_sem);
+       list_for_each(ele, &externfses){
+               fs = list_entry(ele, struct externfs, list);
+               if(!strcmp(fs->type.name, name)){
+                       list_del(ele);
+                       up(&externfs_sem);
+                       return;
+               }
+       }
+       up(&externfs_sem);
+       printk("Unregister_externfs - filesystem '%s' not found\n", name);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/host_file.c b/fs/hostfs/host_file.c
new file mode 100644 (file)
index 0000000..e8eb901
--- /dev/null
@@ -0,0 +1,442 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/string.h"
+#include "linux/errno.h"
+#include "linux/types.h"
+#include "linux/slab.h"
+#include "linux/fs.h"
+#include "asm/fcntl.h"
+#include "hostfs.h"
+#include "filehandle.h"
+
+extern int append;
+
+char *get_path(const char *path[], char *buf, int size)
+{
+       const char **s;
+       char *p;
+       int new = 1;
+
+       for(s = path; *s != NULL; s++){
+               new += strlen(*s);
+               if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
+                  ((*s)[strlen(*s) - 1] != '/'))
+                       new++;
+       }
+
+       if(new > size){
+               buf = kmalloc(new, GFP_KERNEL);
+               if(buf == NULL)
+                       return(NULL);
+       }
+
+       p = buf;
+       for(s = path; *s != NULL; s++){
+               strcpy(p, *s);
+               p += strlen(*s);
+               if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
+                  ((*s)[strlen(*s) - 1] != '/'))
+                       strcpy(p++, "/");
+       }
+               
+       return(buf);
+}
+
+void free_path(const char *buf, char *tmp)
+{
+       if((buf != tmp) && (buf != NULL))
+               kfree((char *) buf);
+}
+
+int host_open_file(const char *path[], int r, int w, struct file_handle *fh)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int mode = 0, err;
+       struct openflags flags = OPENFLAGS();
+
+       if (r)
+               flags = of_read(flags);
+       if (w)
+               flags = of_write(flags);
+       if(append)
+               flags = of_append(flags);
+
+       err = -ENOMEM;
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+       
+       err = open_filehandle(file, flags, mode, fh);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+void *host_open_dir(const char *path[])
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       void *dir = ERR_PTR(-ENOMEM);
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+       
+       dir = open_dir(file);
+ out:
+       free_path(file, tmp);
+       return(dir);
+}
+
+char *host_read_dir(void *stream, unsigned long long *pos, 
+                   unsigned long long *ino_out, int *len_out)
+{
+       int err;
+       char *name;
+
+       err = os_seek_dir(stream, *pos);
+       if(err)
+               return(ERR_PTR(err));
+
+       err = os_read_dir(stream, ino_out, &name);
+       if(err)
+               return(ERR_PTR(err));
+
+       if(name == NULL)
+               return(NULL);
+
+       *len_out = strlen(name);
+       *pos = os_tell_dir(stream);
+       return(name);
+}
+
+int host_file_type(const char *path[], int *rdev)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       struct uml_stat buf;
+       int ret;
+
+       ret = -ENOMEM;
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       if(rdev != NULL){
+               ret = os_lstat_file(file, &buf);
+               if(ret)
+                       goto out;
+               *rdev = MKDEV(buf.ust_rmajor, buf.ust_rminor);
+       }
+
+       ret = os_file_type(file);
+ out:
+       free_path(file, tmp);
+       return(ret);
+}
+
+int host_create_file(const char *path[], int mode, struct file_handle *fh)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = open_filehandle(file, of_create(of_rdwr(OPENFLAGS())), mode, fh);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+static int do_stat_file(const char *path, int *dev_out, 
+                       unsigned long long *inode_out, int *mode_out, 
+                       int *nlink_out, int *uid_out, int *gid_out, 
+                       unsigned long long *size_out, unsigned long *atime_out,
+                       unsigned long *mtime_out, unsigned long *ctime_out,
+                       int *blksize_out, unsigned long long *blocks_out)
+{
+       struct uml_stat buf;
+       int err;
+
+       err = os_lstat_file(path, &buf);
+       if(err < 0)
+               return(err);
+
+       if(dev_out != NULL) *dev_out = MKDEV(buf.ust_major, buf.ust_minor);
+       if(inode_out != NULL) *inode_out = buf.ust_ino;
+       if(mode_out != NULL) *mode_out = buf.ust_mode;
+       if(nlink_out != NULL) *nlink_out = buf.ust_nlink;
+       if(uid_out != NULL) *uid_out = buf.ust_uid;
+       if(gid_out != NULL) *gid_out = buf.ust_gid;
+       if(size_out != NULL) *size_out = buf.ust_size;
+       if(atime_out != NULL) *atime_out = buf.ust_atime;
+       if(mtime_out != NULL) *mtime_out = buf.ust_mtime;
+       if(ctime_out != NULL) *ctime_out = buf.ust_ctime;
+       if(blksize_out != NULL) *blksize_out = buf.ust_blksize;
+       if(blocks_out != NULL) *blocks_out = buf.ust_blocks;
+
+       return(0);
+}
+
+int host_stat_file(const char *path[], int *dev_out,
+                  unsigned long long *inode_out, int *mode_out, 
+                  int *nlink_out, int *uid_out, int *gid_out, 
+                  unsigned long long *size_out, unsigned long *atime_out,
+                  unsigned long *mtime_out, unsigned long *ctime_out,
+                  int *blksize_out, unsigned long long *blocks_out)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err;
+
+       err = -ENOMEM;
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = do_stat_file(file, dev_out, inode_out, mode_out, nlink_out, 
+                          uid_out, gid_out, size_out, atime_out, mtime_out,
+                          ctime_out, blksize_out, blocks_out);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_set_attr(const char *path[], struct externfs_iattr *attrs)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       unsigned long time;
+       int err = 0, ma;
+
+       if(append && (attrs->ia_valid & EXTERNFS_ATTR_SIZE))
+               return(-EPERM);
+
+       err = -ENOMEM;
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
+               err = os_set_file_perms(file, attrs->ia_mode);
+               if(err < 0)
+                       goto out;
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_UID){
+               err = os_set_file_owner(file, attrs->ia_uid, -1);
+               if(err < 0)
+                       goto out;
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_GID){
+               err = os_set_file_owner(file, -1, attrs->ia_gid);
+               if(err < 0)
+                       goto out;
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_SIZE){
+               err = os_truncate_file(file, attrs->ia_size);
+               if(err < 0)
+                       goto out;
+       }
+       ma = EXTERNFS_ATTR_ATIME_SET | EXTERNFS_ATTR_MTIME_SET;
+       if((attrs->ia_valid & ma) == ma){
+               err = os_set_file_time(file, attrs->ia_atime, attrs->ia_mtime);
+               if(err)
+                       goto out;
+       }
+       else {
+               if(attrs->ia_valid & EXTERNFS_ATTR_ATIME_SET){
+                       err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+                                          NULL, NULL, NULL, &time, 
+                                          NULL, NULL, NULL);
+                       if(err != 0)
+                               goto out;
+
+                       err = os_set_file_time(file, attrs->ia_atime, time);
+                       if(err)
+                               goto out;
+               }
+               if(attrs->ia_valid & EXTERNFS_ATTR_MTIME_SET){
+                       err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+                                          NULL, NULL, &time, NULL, 
+                                          NULL, NULL, NULL);
+                       if(err != 0)
+                               goto out;
+
+                       err = os_set_file_time(file, time, attrs->ia_mtime);
+                       if(err)
+                               goto out;
+               }
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_CTIME) ;
+       if(attrs->ia_valid & (EXTERNFS_ATTR_ATIME | EXTERNFS_ATTR_MTIME)){
+               err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+                                  NULL, NULL, &attrs->ia_atime, 
+                                  &attrs->ia_mtime, NULL, NULL, NULL);
+               if(err != 0)
+                       goto out;
+       }
+
+       err = 0;
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_make_symlink(const char *from[], const char *to)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(from, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+       
+       err = os_make_symlink(to, file);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_unlink_file(const char *path[])
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       if(append)
+               return(-EPERM);
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_remove_file(file);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_make_dir(const char *path[], int mode)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_make_dir(file, mode);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_remove_dir(const char *path[])
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_remove_dir(file);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+int host_link_file(const char *to[], const char *from[])
+{
+       char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
+       int err = -ENOMEM;
+
+       f = get_path(from, from_tmp, sizeof(from_tmp));
+       t = get_path(to, to_tmp, sizeof(to_tmp));
+       if((f == NULL) || (t == NULL))
+               goto out;
+
+       err = os_link_file(t, f);
+ out:
+       free_path(f, from_tmp);
+       free_path(t, to_tmp);
+       return(err);
+}
+
+int host_read_link(const char *path[], char *buf, int size)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int n = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       n = os_read_symlink(file, buf, size);
+       if(n < size) 
+               buf[n] = '\0';
+ out:
+       free_path(file, tmp);
+       return(n);
+}
+
+int host_rename_file(const char *from[], const char *to[])
+{
+       char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
+       int err = -ENOMEM;
+
+       f = get_path(from, from_tmp, sizeof(from_tmp));
+       t = get_path(to, to_tmp, sizeof(to_tmp));
+       if((f == NULL) || (t == NULL))
+               goto out;
+
+       err = os_move_file(f, t);
+ out:
+       free_path(f, from_tmp);
+       free_path(t, to_tmp);
+       return(err);
+}
+
+int host_stat_fs(const char *path[], long *bsize_out, long long *blocks_out, 
+                long long *bfree_out, long long *bavail_out, 
+                long long *files_out, long long *ffree_out, void *fsid_out, 
+                int fsid_size, long *namelen_out, long *spare_out)
+{
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_stat_filesystem(file, bsize_out, blocks_out, bfree_out, 
+                                bavail_out, files_out, ffree_out, fsid_out, 
+                                fsid_size, namelen_out, spare_out);
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+char *generic_host_read_dir(void *stream, unsigned long long *pos, 
+                           unsigned long long *ino_out, int *len_out, 
+                           void *mount)
+{
+       return(host_read_dir(stream, pos, ino_out, len_out));
+}
+
+int generic_host_truncate_file(struct file_handle *fh, __u64 size, void *m)
+{
+       return(truncate_file(fh, size));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/host_fs.c b/fs/hostfs/host_fs.c
new file mode 100644 (file)
index 0000000..c059539
--- /dev/null
@@ -0,0 +1,467 @@
+/* 
+ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/string.h"
+#include "linux/types.h"
+#include "linux/errno.h"
+#include "linux/slab.h"
+#include "linux/init.h"
+#include "linux/fs.h"
+#include "linux/stat.h"
+#include "hostfs.h"
+#include "kern.h"
+#include "init.h"
+#include "kern_util.h"
+#include "filehandle.h"
+#include "os.h"
+
+/* Changed in hostfs_args before the kernel starts running */
+static char *jail_dir = "/";
+int append = 0;
+
+static int __init hostfs_args(char *options, int *add)
+{
+       char *ptr;
+
+       ptr = strchr(options, ',');
+       if(ptr != NULL)
+               *ptr++ = '\0';
+       if(*options != '\0')
+               jail_dir = options;
+
+       options = ptr;
+       while(options){
+               ptr = strchr(options, ',');
+               if(ptr != NULL)
+                       *ptr++ = '\0';
+               if(*options != '\0'){
+                       if(!strcmp(options, "append"))
+                               append = 1;
+                       else printf("hostfs_args - unsupported option - %s\n",
+                                   options);
+               }
+               options = ptr;
+       }
+       return(0);
+}
+
+__uml_setup("hostfs=", hostfs_args,
+"hostfs=<root dir>,<flags>,...\n"
+"    This is used to set hostfs parameters.  The root directory argument\n"
+"    is used to confine all hostfs mounts to within the specified directory\n"
+"    tree on the host.  If this isn't specified, then a user inside UML can\n"
+"    mount anything on the host that's accessible to the user that's running\n"
+"    it.\n"
+"    The only flag currently supported is 'append', which specifies that all\n"
+"    files opened by hostfs will be opened in append mode.\n\n"
+);
+
+struct hostfs_data {
+       struct externfs_data ext;
+       char *mount;
+};
+
+struct hostfs_file {
+       struct externfs_inode ext;
+       struct file_handle fh;
+};
+
+static int hostfs_access_file(char *file, int uid, int w, int x, int gid, 
+                             int r, struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+       char tmp[HOSTFS_BUFSIZE];
+       int err, mode = 0;
+
+       if(r) mode = OS_ACC_R_OK;
+       if(w) mode |= OS_ACC_W_OK;
+       if(x) mode |= OS_ACC_X_OK;
+       
+       err = -ENOMEM;
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_access(file, mode);
+       free_path(file, tmp);
+ out:
+       return(err);
+}
+
+static int hostfs_make_node(const char *file, int mode, int uid, int gid, 
+                           int type, int major, int minor, 
+                           struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+       char tmp[HOSTFS_BUFSIZE];
+       int err = -ENOMEM;
+
+       file = get_path(path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       /* XXX Pass type in an OS-independent way */
+       mode |= type;
+
+       err = os_make_dev(file, mode, major, minor);
+       free_path(file, tmp);
+ out:
+       return(err);
+}
+
+static int hostfs_stat_file(const char *file, struct externfs_data *ed, 
+                           dev_t *dev_out, unsigned long long *inode_out, 
+                           int *mode_out, int *nlink_out, int *uid_out, 
+                           int *gid_out, unsigned long long *size_out, 
+                           unsigned long *atime_out, unsigned long *mtime_out,
+                           unsigned long *ctime_out, int *blksize_out, 
+                           unsigned long long *blocks_out)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       /* XXX Why pretend everything is owned by root? */
+       *uid_out = 0;
+       *gid_out = 0;
+       return(host_stat_file(path, dev_out, inode_out, mode_out, nlink_out,
+                             NULL, NULL, size_out, atime_out, mtime_out,
+                             ctime_out, blksize_out, blocks_out));
+}
+
+static int hostfs_file_type(const char *file, int *rdev, 
+                           struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_file_type(path, rdev));
+}
+
+static char *hostfs_name(struct inode *inode)
+{
+       struct externfs_data *ed = inode_externfs_info(inode);
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+
+       return(inode_name_prefix(inode, mount));        
+}
+
+static struct externfs_inode *hostfs_init_file(struct externfs_data *ed)
+{
+       struct hostfs_file *hf;
+
+       hf = kmalloc(sizeof(*hf), GFP_KERNEL);
+       if(hf == NULL)
+               return(NULL);
+
+       hf->fh.fd = -1;
+       return(&hf->ext);
+}
+
+static int hostfs_open_file(struct externfs_inode *ext, char *file, 
+                           int uid, int gid, struct inode *inode, 
+                           struct externfs_data *ed)
+{
+       struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+       int err;
+
+       err = host_open_file(path, 1, 1, &hf->fh);
+       if(err == -EISDIR)
+               goto out;
+
+       if(err == -EACCES)
+               err = host_open_file(path, 1, 0, &hf->fh);
+
+       if(err)
+               goto out;
+
+       is_reclaimable(&hf->fh, hostfs_name, inode);
+ out:
+       return(err);
+}
+
+static void *hostfs_open_dir(char *file, int uid, int gid, 
+                            struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_open_dir(path));
+}
+
+static void hostfs_close_dir(void *stream, struct externfs_data *ed)
+{
+       os_close_dir(stream);
+}
+
+static char *hostfs_read_dir(void *stream, unsigned long long *pos, 
+                            unsigned long long *ino_out, int *len_out, 
+                            struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+
+       return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
+}
+
+static int hostfs_read_file(struct externfs_inode *ext, 
+                           unsigned long long offset, char *buf, int len, 
+                           int ignore_start, int ignore_end,
+                           void (*completion)(char *, int, void *), void *arg,
+                           struct externfs_data *ed)
+{
+       struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
+       int err = 0;
+
+       if(ignore_start != 0){
+               err = read_file(&hf->fh, offset, buf, ignore_start);
+               if(err < 0)
+                       goto out;
+       }
+
+       if(ignore_end != len)
+               err = read_file(&hf->fh, offset + ignore_end, buf + ignore_end,
+                               len - ignore_end);
+
+ out:
+
+       (*completion)(buf, err, arg);
+       if (err > 0)
+               err = 0;
+       return(err);
+}
+
+static int hostfs_write_file(struct externfs_inode *ext,
+                            unsigned long long offset, const char *buf, 
+                            int start, int len, 
+                            void (*completion)(char *, int, void *), 
+                            void *arg, struct externfs_data *ed)
+{
+       struct file_handle *fh;
+       int err;
+
+       fh = &container_of(ext, struct hostfs_file, ext)->fh;
+       err = write_file(fh, offset + start, buf + start, len);
+
+       (*completion)((char *) buf, err, arg);
+       if (err > 0)
+               err = 0;
+
+       return(err);
+}
+
+static int hostfs_create_file(struct externfs_inode *ext, char *file, int mode,
+                             int uid, int gid, struct inode *inode, 
+                             struct externfs_data *ed)
+{
+       struct hostfs_file *hf = container_of(ext, struct hostfs_file, 
+                                             ext);
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+       int err = -ENOMEM;
+       
+       err = host_create_file(path, mode, &hf->fh);
+       if(err)
+               goto out;
+
+       is_reclaimable(&hf->fh, hostfs_name, inode);
+ out:
+       return(err);
+}
+
+static int hostfs_set_attr(const char *file, struct externfs_iattr *attrs, 
+                          struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_set_attr(path, attrs));
+}
+
+static int hostfs_make_symlink(const char *from, const char *to, int uid, 
+                              int gid, struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, from, NULL };
+
+       return(host_make_symlink(path, to));
+}
+
+static int hostfs_link_file(const char *to, const char *from, int uid, int gid,
+                           struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *to_path[] = { jail_dir, mount, to, NULL };
+       const char *from_path[] = { jail_dir, mount, from, NULL };
+
+       return(host_link_file(to_path, from_path));
+}
+
+static int hostfs_unlink_file(const char *file, struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_unlink_file(path));
+}
+
+static int hostfs_make_dir(const char *file, int mode, int uid, int gid, 
+                          struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_make_dir(path, mode));
+}
+
+static int hostfs_remove_dir(const char *file, int uid, int gid, 
+                            struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_remove_dir(path));
+}
+
+static int hostfs_read_link(char *file, int uid, int gid, char *buf, int size, 
+                           struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, file, NULL };
+
+       return(host_read_link(path, buf, size));
+}
+
+static int hostfs_rename_file(char *from, char *to, struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *to_path[] = { jail_dir, mount, to, NULL };
+       const char *from_path[] = { jail_dir, mount, from, NULL };
+
+       return(host_rename_file(from_path, to_path));
+}
+
+static int hostfs_stat_fs(long *bsize_out, long long *blocks_out, 
+                         long long *bfree_out, long long *bavail_out, 
+                         long long *files_out, long long *ffree_out,
+                         void *fsid_out, int fsid_size, long *namelen_out, 
+                         long *spare_out, struct externfs_data *ed)
+{
+       char *mount = container_of(ed, struct hostfs_data, ext)->mount;
+       const char *path[] = { jail_dir, mount, NULL };
+
+       return(host_stat_fs(path, bsize_out, blocks_out, bfree_out, bavail_out,
+                           files_out, ffree_out, fsid_out, fsid_size, 
+                           namelen_out, spare_out));
+}
+
+void hostfs_close_file(struct externfs_inode *ext,
+                      unsigned long long size)
+{
+       struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
+
+       if(hf->fh.fd != -1){
+               truncate_file(&hf->fh, size);
+               close_file(&hf->fh);
+       }
+
+       kfree(hf);
+}
+
+int hostfs_truncate_file(struct externfs_inode *ext, __u64 size, 
+                        struct externfs_data *ed)
+{
+       struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
+
+       return(truncate_file(&hf->fh, size));
+}
+
+static struct externfs_file_ops hostfs_file_ops = {
+       .stat_file              = hostfs_stat_file,
+       .file_type              = hostfs_file_type,
+       .access_file            = hostfs_access_file,
+       .open_file              = hostfs_open_file,
+       .open_dir               = hostfs_open_dir,
+       .read_dir               = hostfs_read_dir,
+       .read_file              = hostfs_read_file,
+       .write_file             = hostfs_write_file,
+       .map_file_page          = NULL,
+       .close_file             = hostfs_close_file,
+       .close_dir              = hostfs_close_dir,
+       .invisible              = NULL,
+       .create_file            = hostfs_create_file,
+       .set_attr               = hostfs_set_attr,
+       .make_symlink           = hostfs_make_symlink,
+       .unlink_file            = hostfs_unlink_file,
+       .make_dir               = hostfs_make_dir,
+       .remove_dir             = hostfs_remove_dir,
+       .make_node              = hostfs_make_node,
+       .link_file              = hostfs_link_file,
+       .read_link              = hostfs_read_link,
+       .rename_file            = hostfs_rename_file,
+       .statfs                 = hostfs_stat_fs,
+       .truncate_file          = hostfs_truncate_file
+};
+
+static struct externfs_data *mount_fs(char *mount_arg)
+{
+       struct hostfs_data *hd;
+       int err = -ENOMEM;
+
+       hd = kmalloc(sizeof(*hd), GFP_KERNEL);
+       if(hd == NULL)
+               goto out;
+
+       hd->mount = host_root_filename(mount_arg);
+       if(hd->mount == NULL)
+               goto out_free;
+
+       init_externfs(&hd->ext, &hostfs_file_ops);
+
+       return(&hd->ext);
+
+ out_free:
+       kfree(hd);
+ out:
+       return(ERR_PTR(err));
+}
+
+static struct externfs_mount_ops hostfs_mount_ops = {
+       .init_file              = hostfs_init_file,
+       .mount                  = mount_fs,
+};
+
+static int __init init_hostfs(void)
+{
+       return(register_externfs("hostfs", &hostfs_mount_ops));
+}
+
+static void __exit exit_hostfs(void)
+{
+       unregister_externfs("hostfs");
+}
+
+__initcall(init_hostfs);
+__exitcall(exit_hostfs);
+
+#if 0
+module_init(init_hostfs)
+module_exit(exit_hostfs)
+MODULE_LICENSE("GPL");
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
new file mode 100644 (file)
index 0000000..e80b6f8
--- /dev/null
@@ -0,0 +1,188 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_FS_HOSTFS
+#define __UM_FS_HOSTFS
+
+#include "linux/fs.h"
+#include "filehandle.h"
+#include "os.h"
+
+/* These are exactly the same definitions as in fs.h, but the names are 
+ * changed so that this file can be included in both kernel and user files.
+ */
+
+#define EXTERNFS_ATTR_MODE     1
+#define EXTERNFS_ATTR_UID      2
+#define EXTERNFS_ATTR_GID      4
+#define EXTERNFS_ATTR_SIZE     8
+#define EXTERNFS_ATTR_ATIME    16
+#define EXTERNFS_ATTR_MTIME    32
+#define EXTERNFS_ATTR_CTIME    64
+#define EXTERNFS_ATTR_ATIME_SET        128
+#define EXTERNFS_ATTR_MTIME_SET        256
+#define EXTERNFS_ATTR_FORCE    512     /* Not a change, but a change it */
+#define EXTERNFS_ATTR_ATTR_FLAG        1024
+
+struct externfs_iattr {
+       unsigned int    ia_valid;
+       mode_t          ia_mode;
+       uid_t           ia_uid;
+       gid_t           ia_gid;
+       loff_t          ia_size;
+       time_t          ia_atime;
+       time_t          ia_mtime;
+       time_t          ia_ctime;
+       unsigned int    ia_attr_flags;
+};
+
+struct externfs_data {
+       struct externfs_file_ops *file_ops;
+       struct externfs_mount_ops *mount_ops;
+};
+
+struct externfs_inode {
+       struct inode vfs_inode;
+       struct externfs_file_ops *ops;
+};
+
+struct externfs_mount_ops {
+       struct externfs_data *(*mount)(char *mount_arg);
+       struct externfs_inode *(*init_file)(struct externfs_data *ed);
+};
+
+struct externfs_file_ops {
+       int (*stat_file)(const char *path, struct externfs_data *ed, 
+                        dev_t *dev_out, unsigned long long *inode_out, 
+                        int *mode_out, int *nlink_out, int *uid_out, 
+                        int *gid_out, unsigned long long *size_out, 
+                        unsigned long *atime_out, unsigned long *mtime_out,
+                        unsigned long *ctime_out, int *blksize_out, 
+                        unsigned long long *blocks_out);
+       int (*file_type)(const char *path, int *rdev, 
+                        struct externfs_data *ed);
+       int (*access_file)(char *path, int r, int w, int x, int uid, int gid, 
+                          struct externfs_data *ed);
+       int (*open_file)(struct externfs_inode *ext, char *file, 
+                        int uid, int gid, struct inode *inode, 
+                        struct externfs_data *ed);
+       void (*close_file)(struct externfs_inode *ext, 
+                          unsigned long long size);
+       void *(*open_dir)(char *path, int uid, int gid, 
+                         struct externfs_data *ed);
+       char *(*read_dir)(void *stream, unsigned long long *pos, 
+                         unsigned long long *ino_out, int *len_out, 
+                         struct externfs_data *ed);
+       int (*read_file)(struct externfs_inode *ext, 
+                        unsigned long long offset, char *buf, int len, 
+                        int ignore_start, int ignore_end,
+                        void (*completion)(char *, int, void *), void *arg, 
+                        struct externfs_data *ed);
+       int (*write_file)(struct externfs_inode *ext, 
+                         unsigned long long offset, const char *buf, 
+                         int start, int len, 
+                         void (*completion)(char *, int, void *), void *arg, 
+                         struct externfs_data *ed);
+       int (*map_file_page)(struct externfs_inode *ext, 
+                            unsigned long long offset, char *buf, int w, 
+                            struct externfs_data *ed);
+       void (*close_dir)(void *stream, struct externfs_data *ed);
+       void (*invisible)(struct externfs_inode *ext);
+       int (*create_file)(struct externfs_inode *ext, char *path, 
+                          int mode, int uid, int gid, struct inode *inode, 
+                          struct externfs_data *ed);
+       int (*set_attr)(const char *path, struct externfs_iattr *attrs, 
+                       struct externfs_data *ed);
+       int (*make_symlink)(const char *from, const char *to, int uid, int gid,
+                           struct externfs_data *ed);
+       int (*unlink_file)(const char *path, struct externfs_data *ed);
+       int (*make_dir)(const char *path, int mode, int uid, int gid, 
+                       struct externfs_data *ed);
+       int (*remove_dir)(const char *path, int uid, int gid, 
+                         struct externfs_data *ed);
+       int (*make_node)(const char *path, int mode, int uid, int gid, 
+                        int type, int maj, int min, struct externfs_data *ed);
+       int (*link_file)(const char *to, const char *from, int uid, int gid, 
+                        struct externfs_data *ed);
+       int (*read_link)(char *path, int uid, int gid, char *buf, int size, 
+                        struct externfs_data *ed);
+       int (*rename_file)(char *from, char *to, struct externfs_data *ed);
+       int (*statfs)(long *bsize_out, long long *blocks_out, 
+                     long long *bfree_out, long long *bavail_out, 
+                     long long *files_out, long long *ffree_out,
+                     void *fsid_out, int fsid_size, long *namelen_out, 
+                     long *spare_out, struct externfs_data *ed);
+       int (*truncate_file)(struct externfs_inode *ext, __u64 size, 
+                            struct externfs_data *ed);
+};
+
+#define HOSTFS_BUFSIZE 64
+
+extern int register_externfs(char *name, struct externfs_mount_ops *mount_ops);
+extern void unregister_externfs(char *name);
+extern void init_externfs(struct externfs_data *ed, 
+                         struct externfs_file_ops *ops);
+struct externfs_data *inode_externfs_info(struct inode *inode);
+
+extern char *generic_root_filename(char *mount_arg);
+extern void host_close_file(void *stream);
+extern int host_read_file(int fd, unsigned long long offset, char *buf, 
+                         int len);
+extern int host_open_file(const char *path[], int r, int w,
+                         struct file_handle *fh);
+extern void *host_open_dir(const char *path[]);
+extern char *host_read_dir(void *stream, unsigned long long *pos, 
+                          unsigned long long *ino_out, int *len_out);
+extern int host_file_type(const char *path[], int *rdev);
+extern char *host_root_filename(char *mount_arg);
+extern char *get_path(const char *path[], char *buf, int size);
+extern void free_path(const char *buf, char *tmp);
+extern int host_create_file(const char *path[], int mode, 
+                           struct file_handle *fh);
+extern int host_set_attr(const char *path[], struct externfs_iattr *attrs);
+extern int host_make_symlink(const char *from[], const char *to);
+extern int host_unlink_file(const char *path[]);
+extern int host_make_dir(const char *path[], int mode);
+extern int host_remove_dir(const char *path[]);
+extern int host_link_file(const char *to[], const char *from[]);
+extern int host_read_link(const char *path[], char *buf, int size);
+extern int host_rename_file(const char *from[], const char *to[]);
+extern int host_stat_fs(const char *path[], long *bsize_out, 
+                       long long *blocks_out, long long *bfree_out, 
+                       long long *bavail_out, long long *files_out, 
+                       long long *ffree_out, void *fsid_out, int fsid_size, 
+                       long *namelen_out, long *spare_out);
+extern int host_stat_file(const char *path[], int *dev_out, 
+                         unsigned long long *inode_out, int *mode_out, 
+                         int *nlink_out, int *uid_out, int *gid_out, 
+                         unsigned long long *size_out, 
+                         unsigned long *atime_out, unsigned long *mtime_out,
+                         unsigned long *ctime_out, int *blksize_out,
+                         unsigned long long *blocks_out);
+
+extern char *generic_host_read_dir(void *stream, unsigned long long *pos, 
+                             unsigned long long *ino_out, int *len_out, 
+                             void *mount);
+extern int generic_host_read_file(int fd, unsigned long long offset, char *buf,
+                            int len, void *mount);
+extern void generic_host_close_file(void *stream, unsigned long long size,
+                                   void *mount);
+extern int generic_host_truncate_file(struct file_handle *fh, __u64 size, 
+                                     void *m);
+
+extern char *inode_name_prefix(struct inode *inode, char *prefix);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/humfs.c b/fs/hostfs/humfs.c
new file mode 100644 (file)
index 0000000..7878be5
--- /dev/null
@@ -0,0 +1,1026 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/kdev_t.h>
+#include "linux/init.h"
+#include "linux/workqueue.h"
+#include <asm/irq.h>
+#include "hostfs.h"
+#include "mem.h"
+#include "os.h"
+#include "mode.h"
+#include "aio.h"
+#include "irq_user.h"
+#include "irq_kern.h"
+#include "filehandle.h"
+#include "metadata.h"
+
+#define HUMFS_VERSION 2
+
+static int humfs_stat_file(const char *path, struct externfs_data *ed, 
+                          dev_t *dev_out, unsigned long long *inode_out, 
+                          int *mode_out, int *nlink_out, int *uid_out, 
+                          int *gid_out, unsigned long long *size_out, 
+                          unsigned long *atime_out, unsigned long *mtime_out, 
+                          unsigned long *ctime_out, int *blksize_out, 
+                          unsigned long long *blocks_out)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err, mode, perms, major, minor;
+       char type;
+
+       err = host_stat_file(data_path, NULL, inode_out, mode_out, 
+                            nlink_out, NULL, NULL, size_out, atime_out, 
+                            mtime_out, ctime_out, blksize_out, blocks_out);
+       if(err)
+               return(err);
+
+       err = (*mount->meta->ownerships)(path, &perms, uid_out, gid_out, 
+                                        &type, &major, &minor, mount);
+       if(err)
+               return(err);
+
+       *mode_out = (*mode_out & ~S_IRWXUGO) | perms;
+
+       mode = 0;
+       switch(type){
+       case 'c':
+               mode = S_IFCHR;
+               *dev_out = MKDEV(major, minor);
+               break;
+       case 'b':
+               mode = S_IFBLK;
+               *dev_out = MKDEV(major, minor);
+               break;
+       case 's':
+               mode = S_IFSOCK;
+               break;
+       default:
+               break;
+       }
+
+       if(mode != 0)
+               *mode_out = (*mode_out & ~S_IFMT) | mode;
+
+       return(0);
+}
+
+static int meta_type(const char *path, int *dev_out, void *m)
+{
+       struct humfs *mount = m;
+       int err, type, maj, min;
+       char c;
+
+       err = (*mount->meta->ownerships)(path, NULL, NULL, NULL, &c, &maj, 
+                                        &min, mount);
+       if(err)
+               return(err);
+
+       if(c == 0)
+               return(0);
+
+       if(dev_out)
+               *dev_out = MKDEV(maj, min);
+
+       switch(c){
+       case 'c':
+               type = OS_TYPE_CHARDEV;
+               break;
+       case 'b':
+               type = OS_TYPE_BLOCKDEV;
+               break;
+       case 'p':
+               type = OS_TYPE_FIFO;
+               break;
+       case 's':
+               type = OS_TYPE_SOCK;
+               break;
+       default:
+               type = -EINVAL;
+               break;
+       }
+
+       return(type);
+}
+
+static int humfs_file_type(const char *path, int *dev_out, 
+                          struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int type;
+
+       type = meta_type(path, dev_out, mount);
+       if(type != 0)
+               return(type);
+
+       return(host_file_type(data_path, dev_out));
+}
+
+static char *humfs_data_name(struct inode *inode)
+{
+       struct externfs_data *ed = inode_externfs_info(inode);
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+
+       return(inode_name_prefix(inode, mount->data));
+}
+
+static struct externfs_inode *humfs_init_file(struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct humfs_file *hf;
+
+       hf = (*mount->meta->init_file)();
+       if(hf == NULL)
+               return(NULL);
+
+       hf->data.fd = -1;
+       return(&hf->ext);
+}
+
+static int humfs_open_file(struct externfs_inode *ext, char *path, int uid, 
+                          int gid, struct inode *inode, 
+                          struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       struct openflags flags;
+       char tmp[HOSTFS_BUFSIZE], *file;
+       int err = -ENOMEM;
+
+       file = get_path(data_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       flags = of_rdwr(OPENFLAGS());
+       if(mount->direct)
+               flags = of_direct(flags);
+
+       if(path == NULL)
+               path = "";
+       err = (*mount->meta->open_file)(hf, path, inode, mount);
+       if(err)
+               goto out_free;
+
+       err = open_filehandle(file, flags, 0, &hf->data);
+       if(err == -EISDIR)
+               goto out;
+       else if(err == -EPERM){
+               flags = of_set_rw(flags, 1, 0);
+               err = open_filehandle(file, flags, 0, &hf->data);
+       }
+       
+       if(err)
+               goto out_close;
+
+       hf->mount = mount;
+       is_reclaimable(&hf->data, humfs_data_name, inode);
+
+ out_free:
+       free_path(file, tmp);
+ out:
+       return(err);
+       
+ out_close:
+       (*mount->meta->close_file)(hf);
+       goto out_free;
+}
+
+static void *humfs_open_dir(char *path, int uid, int gid, 
+                           struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+
+       return(host_open_dir(data_path));
+}
+
+static void humfs_close_dir(void *stream, struct externfs_data *ed)
+{
+       os_close_dir(stream);
+}
+
+static char *humfs_read_dir(void *stream, unsigned long long *pos, 
+                           unsigned long long *ino_out, int *len_out, 
+                           struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+
+       return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
+}
+
+LIST_HEAD(humfs_replies);
+
+struct humfs_aio {
+       struct aio_context aio;
+       struct list_head list;
+       void (*completion)(char *, int, void *);
+       char *buf;
+       int real_len;
+       int err;
+       void *data;
+};
+
+static int humfs_reply_fd = -1;
+
+struct humfs_aio last_task_aio, last_intr_aio;
+struct humfs_aio *last_task_aio_ptr, *last_intr_aio_ptr;
+
+void humfs_work_proc(void *unused)
+{
+       struct humfs_aio *aio;
+       unsigned long flags;
+
+       while(!list_empty(&humfs_replies)){
+               local_irq_save(flags);
+               aio = list_entry(humfs_replies.next, struct humfs_aio, list);
+
+               last_task_aio = *aio;
+               last_task_aio_ptr = aio;
+
+               list_del(&aio->list);
+               local_irq_restore(flags);
+
+               if(aio->err >= 0)
+                       aio->err = aio->real_len;
+               (*aio->completion)(aio->buf, aio->err, aio->data);
+               kfree(aio);
+       }
+}
+
+DECLARE_WORK(humfs_work, humfs_work_proc, NULL);
+
+static irqreturn_t humfs_interrupt(int irq, void *dev_id, 
+                                  struct pt_regs *unused)
+{
+       struct aio_thread_reply reply;
+       struct humfs_aio *aio;
+       int err, fd = (int) dev_id;
+
+       while(1){
+               err = os_read_file(fd, &reply, sizeof(reply));
+               if(err < 0){
+                       if(err == -EAGAIN)
+                               break;
+                       printk("humfs_interrupt - read returned err %d\n", 
+                              -err);
+                       return(IRQ_HANDLED);
+               }
+               aio = reply.data;
+               aio->err = reply.err;
+               list_add(&aio->list, &humfs_replies);
+               last_intr_aio = *aio;
+               last_intr_aio_ptr = aio;
+       }
+
+       if(!list_empty(&humfs_replies))
+               schedule_work(&humfs_work);
+       reactivate_fd(fd, HUMFS_IRQ);
+       return(IRQ_HANDLED);
+}
+
+static int init_humfs_aio(void)
+{
+       int fds[2], err;
+
+       err = os_pipe(fds, 1, 1);
+       if(err){
+               printk("init_humfs_aio - pipe failed, err = %d\n", -err);
+               goto out;
+       }
+
+       err = um_request_irq(HUMFS_IRQ, fds[0], IRQ_READ, humfs_interrupt,
+                            SA_INTERRUPT | SA_SAMPLE_RANDOM, "humfs", 
+                            (void *) fds[0]);
+       if(err){
+               printk("init_humfs_aio - : um_request_irq failed, err = %d\n",
+                      err);
+               goto out_close;
+       }
+
+       humfs_reply_fd = fds[1];
+       goto out;
+       
+ out_close:
+       os_close_file(fds[0]);
+       os_close_file(fds[1]);
+ out:
+       return(0);
+}
+
+__initcall(init_humfs_aio);
+
+static int humfs_aio(enum aio_type type, int fd, unsigned long long offset,
+                    char *buf, int len, int real_len,
+                    void (*completion)(char *, int, void *), void *arg)
+{
+       struct humfs_aio *aio;
+       int err = -ENOMEM;
+
+       aio = kmalloc(sizeof(*aio), GFP_KERNEL);
+       if(aio == NULL)
+               goto out;
+       *aio = ((struct humfs_aio) { .aio       = INIT_AIO_CONTEXT,
+                                    .list      = LIST_HEAD_INIT(aio->list),
+                                    .completion= completion,
+                                    .buf       = buf,
+                                    .err       = 0,
+                                    .real_len  = real_len,
+                                    .data      = arg });
+
+       err = submit_aio(type, fd, buf, len, offset, humfs_reply_fd, aio);
+       if(err)
+               (*completion)(buf, err, arg);
+
+ out:
+       return(err);
+}
+
+static int humfs_read_file(struct externfs_inode *ext,
+                          unsigned long long offset, char *buf, int len,
+                          int ignore_start, int ignore_end,
+                          void (*completion)(char *, int, void *), void *arg, 
+                          struct externfs_data *ed)
+{
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       int fd = filehandle_fd(&hf->data);
+
+       if(fd < 0){
+               (*completion)(buf, fd, arg);
+               return(fd);
+       }
+
+       return(humfs_aio(AIO_READ, fd, offset, buf, len, len, completion, 
+                        arg));
+}
+
+static int humfs_write_file(struct externfs_inode *ext,
+                           unsigned long long offset, 
+                           const char *buf, int start, int len, 
+                           void (*completion)(char *, int, void *), void *arg,
+                           struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       int err, orig_len = len, fd = filehandle_fd(&hf->data);
+
+       if(fd < 0){
+               (*completion)((char *) buf, fd, arg);
+               return(fd);
+       }
+
+       if(mount->direct)
+               len = PAGE_SIZE;
+       else {
+               offset += start;
+               buf += start;
+       }
+
+       err = humfs_aio(AIO_WRITE, fd, offset, (char *) buf, len, orig_len, 
+                       completion, arg);
+
+       if(err < 0)
+               return(err);
+
+       if(mount->direct)
+               err = orig_len;
+
+       return(err);
+}
+
+static int humfs_map_file_page(struct externfs_inode *ext, 
+                              unsigned long long offset, char *buf, int w, 
+                              struct externfs_data *ed)
+{
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       unsigned long long size, need;
+       int err, fd = filehandle_fd(&hf->data);
+
+       if(fd < 0)
+               return(fd);
+
+       err = os_fd_size(fd, &size);
+       if(err)
+               return(err);
+
+       need = offset + PAGE_SIZE;
+       if(size < need){
+               err = os_truncate_fd(fd, need);
+               if(err)
+                       return(err);
+       }
+       
+       return(physmem_subst_mapping(buf, fd, offset, w));
+}
+
+static void humfs_close_file(struct externfs_inode *ext,
+                            unsigned long long size)
+{
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       int fd;
+
+       if(hf->data.fd == -1)
+               return;
+
+       fd = filehandle_fd(&hf->data);
+       physmem_forget_descriptor(fd);
+       truncate_file(&hf->data, size);
+       close_file(&hf->data);
+
+       (*hf->mount->meta->close_file)(hf);
+}
+
+/* XXX Assumes that you can't make a normal file */
+
+static int humfs_make_node(const char *path, int mode, int uid, int gid, 
+                          int type, int major, int minor, 
+                          struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct file_handle fh;
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err;
+       char t;
+
+       err = host_create_file(data_path, S_IRWXUGO, &fh);
+       if(err)
+               goto out;
+
+       close_file(&fh);
+
+       switch(type){
+       case S_IFCHR:
+               t = 'c';
+               break;
+       case S_IFBLK:
+               t = 'b';
+               break;
+       case S_IFIFO:
+               t = 'p';
+               break;
+       case S_IFSOCK:
+               t = 's';
+               break;
+       default:
+               err = -EINVAL;
+               printk("make_node - bad node type : %d\n", type);
+               goto out_rm;
+       }
+
+       err = (*mount->meta->make_node)(path, mode, uid, gid, t, major, minor, 
+                                       mount);
+       if(err)
+               goto out_rm;
+
+ out:
+       return(err);
+
+ out_rm:
+       host_unlink_file(data_path);
+       goto out;
+}
+               
+static int humfs_create_file(struct externfs_inode *ext, char *path, int mode,
+                            int uid, int gid, struct inode *inode, 
+                            struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err;
+
+       err = (*mount->meta->create_file)(hf, path, mode, uid, gid, inode, 
+                                         mount);
+       if(err)
+               goto out;
+
+       err = host_create_file(data_path, S_IRWXUGO, &hf->data);
+       if(err)
+               goto out_rm;
+
+       
+       is_reclaimable(&hf->data, humfs_data_name, inode);
+
+       return(0);
+
+ out_rm:
+       (*mount->meta->remove_file)(path, mount);
+       (*mount->meta->close_file)(hf);
+ out:
+       return(err);
+}
+
+static int humfs_set_attr(const char *path, struct externfs_iattr *attrs, 
+                         struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int (*chown)(const char *, int, int, int, struct humfs *);
+       int err;
+
+       chown = mount->meta->change_ownerships;
+       if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
+               err = (*chown)(path, attrs->ia_mode, -1, -1, mount);
+               if(err)
+                       return(err);
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_UID){
+               err = (*chown)(path, -1, attrs->ia_uid, -1, mount);
+               if(err)
+                       return(err);
+       }
+       if(attrs->ia_valid & EXTERNFS_ATTR_GID){
+               err = (*chown)(path, -1, -1, attrs->ia_gid, mount);
+               if(err)
+                       return(err);
+       }
+
+       attrs->ia_valid &= ~(EXTERNFS_ATTR_MODE | EXTERNFS_ATTR_UID | 
+                            EXTERNFS_ATTR_GID);
+
+       return(host_set_attr(data_path, attrs));
+}
+
+static int humfs_make_symlink(const char *from, const char *to, int uid, 
+                             int gid, struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       struct humfs_file *hf;
+       const char *data_path[3] = { mount->data, from, NULL };
+       int err = -ENOMEM;
+
+       hf = (*mount->meta->init_file)();
+       if(hf == NULL)
+               goto out;
+
+       err = (*mount->meta->create_file)(hf, from, S_IRWXUGO, uid, gid, NULL, 
+                                         mount);
+       if(err)
+               goto out_close;
+
+       err = host_make_symlink(data_path, to);
+       if(err)
+               (*mount->meta->remove_file)(from, mount);
+
+ out_close:
+       (*mount->meta->close_file)(hf);
+ out:
+       return(err);
+}
+
+static int humfs_link_file(const char *to, const char *from, int uid, int gid, 
+                          struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path_from[3] = { mount->data, from, NULL };
+       const char *data_path_to[3] = { mount->data, to, NULL };
+       int err;
+
+       err = (*mount->meta->create_link)(to, from, mount);
+       if(err)
+               return(err);
+
+       err = host_link_file(data_path_to, data_path_from);
+       if(err)
+               (*mount->meta->remove_file)(from, mount);
+       
+       return(err);
+}
+
+static int humfs_unlink_file(const char *path, struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err;
+
+       err = (*mount->meta->remove_file)(path, mount);
+       if (err)
+               return err;
+
+       (*mount->meta->remove_file)(path, mount);
+       return(host_unlink_file(data_path));
+}
+
+static void humfs_invisible(struct externfs_inode *ext)
+{
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+       struct humfs *mount = hf->mount;
+       
+       (*mount->meta->invisible)(hf);
+       not_reclaimable(&hf->data);
+}
+
+static int humfs_make_dir(const char *path, int mode, int uid, int gid, 
+                         struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err;
+
+       err = (*mount->meta->create_dir)(path, mode, uid, gid, mount);
+       if(err)
+               return(err);
+       
+       err = host_make_dir(data_path, S_IRWXUGO);
+       if(err)
+               (*mount->meta->remove_dir)(path, mount);
+
+       return(err);
+}
+
+static int humfs_remove_dir(const char *path, int uid, int gid, 
+                           struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, path, NULL };
+       int err;
+
+       err = host_remove_dir(data_path);
+       if (err)
+               return err;
+
+       (*mount->meta->remove_dir)(path, mount);
+
+       return(err);
+}
+
+static int humfs_read_link(char *file, int uid, int gid, char *buf, int size, 
+                          struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, file, NULL };
+
+       return(host_read_link(data_path, buf, size));
+}
+
+struct humfs *inode_humfs_info(struct inode *inode)
+{
+       return(container_of(inode_externfs_info(inode), struct humfs, ext));
+}
+
+static int humfs_rename_file(char *from, char *to, struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path_from[3] = { mount->data, from, NULL };
+       const char *data_path_to[3] = { mount->data, to, NULL };
+       int err;
+
+       err = (*mount->meta->rename_file)(from, to, mount);
+       if(err)
+               return(err);
+       
+       err = host_rename_file(data_path_from, data_path_to);
+       if(err)
+               (*mount->meta->rename_file)(to, from, mount);
+
+       return(err);
+}
+
+static int humfs_stat_fs(long *bsize_out, long long *blocks_out, 
+                        long long *bfree_out, long long *bavail_out, 
+                        long long *files_out, long long *ffree_out, 
+                        void *fsid_out, int fsid_size, long *namelen_out, 
+                        long *spare_out, struct externfs_data *ed)
+{
+       struct humfs *mount = container_of(ed, struct humfs, ext);
+       const char *data_path[3] = { mount->data, NULL };
+       int err;
+
+       /* XXX Needs to maintain this info as metadata */
+       err = host_stat_fs(data_path, bsize_out, blocks_out, bfree_out, 
+                          bavail_out, files_out, ffree_out, fsid_out, 
+                          fsid_size, namelen_out, spare_out);
+       if(err)
+               return(err);
+
+       *blocks_out = mount->total / *bsize_out;
+       *bfree_out = (mount->total - mount->used) / *bsize_out;
+       *bavail_out = (mount->total - mount->used) / *bsize_out;
+       return(0);
+}
+
+int humfs_truncate_file(struct externfs_inode *ext, __u64 size, 
+                       struct externfs_data *ed)
+{
+       struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
+
+       return(truncate_file(&hf->data, size));
+}
+
+char *humfs_path(char *dir, char *file)
+{
+       int need_slash, len = strlen(dir) + strlen(file);
+       char *new;
+
+       need_slash = (dir[strlen(dir) - 1] != '/');
+       if(need_slash)
+               len++;
+
+       new = kmalloc(len + 1, GFP_KERNEL);
+       if(new == NULL)
+               return(NULL);
+
+       strcpy(new, dir);
+       if(need_slash)
+               strcat(new, "/");
+       strcat(new, file);
+
+       return(new);
+}
+
+DECLARE_MUTEX(meta_sem);
+struct list_head metas = LIST_HEAD_INIT(metas);
+
+static struct humfs_meta_ops *find_meta(const char *name)
+{
+       struct list_head *ele;
+       struct humfs_meta_ops *m;
+       down(&meta_sem);
+       list_for_each(ele, &metas){
+               m = list_entry(ele, struct humfs_meta_ops, list);
+               if(!strcmp(m->name, name))
+                       goto out;
+       }
+       m = NULL;
+ out:
+       up(&meta_sem);
+       return(m);
+}
+
+void register_meta(struct humfs_meta_ops *ops)
+{
+       down(&meta_sem);
+       list_add(&ops->list, &metas);
+       up(&meta_sem);
+}
+void unregister_meta(struct humfs_meta_ops *ops)
+{
+       down(&meta_sem);
+       list_del(&ops->list);
+       up(&meta_sem);
+}
+static struct humfs *read_superblock(char *root)
+{
+       struct humfs *mount;
+       struct humfs_meta_ops *meta = NULL;
+       struct file_handle *fh;
+       const char *path[] = { root, "superblock", NULL };
+       u64 used, total;
+       char meta_buf[33], line[HOSTFS_BUFSIZE], *newline;
+       unsigned long long pos;
+       int version, i, n, err;
+
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if(fh == NULL)
+               return(ERR_PTR(-ENOMEM));
+
+       err = host_open_file(path, 1, 0, fh);
+       if(err){
+               printk("Failed to open %s/%s, errno = %d\n", path[0],
+                      path[1], err);
+               return(ERR_PTR(err));
+       }
+
+       used = 0;
+       total = 0;
+       pos = 0;
+       i = 0;
+       while(1){
+               n = read_file(fh, pos, &line[i], sizeof(line) - i - 1);
+               if((n == 0) && (i == 0))
+                       break;
+               if(n < 0)
+                       return(ERR_PTR(n));
+
+               pos += n;
+               if(n > 0)
+                       line[n + i] = '\0';
+
+               newline = strchr(line, '\n');
+               if(newline == NULL){
+                       printk("read_superblock - line too long : '%s'\n", 
+                              line);
+                       return(ERR_PTR(-EINVAL));
+               }
+               newline++;
+
+               if(sscanf(line, "version %d\n", &version) == 1){
+                       if(version != HUMFS_VERSION){
+                               printk("humfs version mismatch - want version "
+                                      "%d, got version %d.\n", HUMFS_VERSION,
+                                      version);
+                               return(ERR_PTR(-EINVAL));
+                       }
+               }
+               else if(sscanf(line, "used %Lu\n", &used) == 1) ;
+               else if(sscanf(line, "total %Lu\n", &total) == 1) ;
+               else if(sscanf(line, "metadata %32s\n", meta_buf) == 1){
+                       meta = find_meta(meta_buf);
+                       if(meta == NULL){
+                               printk("read_superblock - meta api \"%s\" not "
+                                      "registered\n", meta_buf);
+                               return(ERR_PTR(-EINVAL));
+                       }
+               }
+               
+               else {
+                       printk("read_superblock - bogus line : '%s'\n", line);
+                       return(ERR_PTR(-EINVAL));
+               }
+
+               i = newline - line;
+               memmove(line, newline, sizeof(line) - i);
+               i = strlen(line);
+       }
+
+       if(used == 0){
+               printk("read_superblock - used not specified or set to "
+                      "zero\n");
+               return(ERR_PTR(-EINVAL));
+       }
+       if(total == 0){
+               printk("read_superblock - total not specified or set to "
+                      "zero\n");
+               return(ERR_PTR(-EINVAL));
+       }
+       if(used > total){
+               printk("read_superblock - used is greater than total\n");
+               return(ERR_PTR(-EINVAL));
+       }
+
+       if(meta == NULL){
+               meta = find_meta("shadow_fs");
+       }
+
+       if(meta == NULL){
+               printk("read_superblock - valid meta api was not specified\n");
+               return(ERR_PTR(-EINVAL));
+       }
+
+       mount = (*meta->init_mount)(root);
+       if(IS_ERR(mount))
+               return(mount);
+
+       *mount = ((struct humfs) { .total       = total,
+                                  .used        = used,
+                                  .meta        = meta });
+       return(mount);
+}
+
+struct externfs_file_ops humfs_no_mmap_file_ops = {
+       .stat_file              = humfs_stat_file,
+       .file_type              = humfs_file_type,
+       .access_file            = NULL,
+       .open_file              = humfs_open_file,
+       .open_dir               = humfs_open_dir,
+       .read_dir               = humfs_read_dir,
+       .read_file              = humfs_read_file,
+       .write_file             = humfs_write_file,
+       .map_file_page          = NULL,
+       .close_file             = humfs_close_file,
+       .close_dir              = humfs_close_dir,
+       .invisible              = humfs_invisible,
+       .create_file            = humfs_create_file,
+       .set_attr               = humfs_set_attr,
+       .make_symlink           = humfs_make_symlink,
+       .unlink_file            = humfs_unlink_file,
+       .make_dir               = humfs_make_dir,
+       .remove_dir             = humfs_remove_dir,
+       .make_node              = humfs_make_node,
+       .link_file              = humfs_link_file,
+       .read_link              = humfs_read_link,
+       .rename_file            = humfs_rename_file,
+       .statfs                 = humfs_stat_fs,
+       .truncate_file          = humfs_truncate_file
+};
+
+struct externfs_file_ops humfs_mmap_file_ops = {
+       .stat_file              = humfs_stat_file,
+       .file_type              = humfs_file_type,
+       .access_file            = NULL,
+       .open_file              = humfs_open_file,
+       .open_dir               = humfs_open_dir,
+       .invisible              = humfs_invisible,
+       .read_dir               = humfs_read_dir,
+       .read_file              = humfs_read_file,
+       .write_file             = humfs_write_file,
+       .map_file_page          = humfs_map_file_page,
+       .close_file             = humfs_close_file,
+       .close_dir              = humfs_close_dir,
+       .create_file            = humfs_create_file,
+       .set_attr               = humfs_set_attr,
+       .make_symlink           = humfs_make_symlink,
+       .unlink_file            = humfs_unlink_file,
+       .make_dir               = humfs_make_dir,
+       .remove_dir             = humfs_remove_dir,
+       .make_node              = humfs_make_node,
+       .link_file              = humfs_link_file,
+       .read_link              = humfs_read_link,
+       .rename_file            = humfs_rename_file,
+       .statfs                 = humfs_stat_fs,
+       .truncate_file          = humfs_truncate_file
+};
+
+static struct externfs_data *mount_fs(char *mount_arg)
+{
+       char *root, *data, *flags;
+       struct humfs *mount;
+       struct externfs_file_ops *file_ops;
+       int err, do_mmap = 0;
+
+       if(mount_arg == NULL){
+               printk("humfs - no host directory specified\n");
+               return(NULL);
+       }
+
+       flags = strchr((char *) mount_arg, ',');
+       if(flags != NULL){
+               do {
+                       *flags++ = '\0';
+
+                       if(!strcmp(flags, "mmap"))
+                               do_mmap = 1;
+
+                       flags = strchr(flags, ',');
+               } while(flags != NULL);
+       }
+
+       err = -ENOMEM;
+       root = host_root_filename(mount_arg);
+       if(root == NULL)
+               goto err;
+
+       mount = read_superblock(root);
+       if(IS_ERR(mount)){
+               err = PTR_ERR(mount);
+               goto err_free_root;
+       }
+
+       data = humfs_path(root, "data/");
+       if(data == NULL)
+               goto err_free_mount;
+
+       if(CHOOSE_MODE(do_mmap, 0)){
+               printk("humfs doesn't support mmap in tt mode\n");
+               do_mmap = 0;
+       }
+
+       mount->data = data;
+       mount->mmap = do_mmap;
+
+       file_ops = do_mmap ? &humfs_mmap_file_ops : &humfs_no_mmap_file_ops;
+       init_externfs(&mount->ext, file_ops);
+
+       return(&mount->ext);
+
+ err_free_mount:
+       kfree(mount);
+ err_free_root:
+       kfree(root);
+ err:
+       return(NULL);
+}
+
+struct externfs_mount_ops humfs_mount_ops = {
+       .init_file              = humfs_init_file,
+       .mount                  = mount_fs,
+};
+
+static int __init init_humfs(void)
+{
+       return(register_externfs("humfs", &humfs_mount_ops));
+}
+
+static void __exit exit_humfs(void)
+{
+       unregister_externfs("humfs");
+}
+
+__initcall(init_humfs);
+__exitcall(exit_humfs);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/meta_fs.c b/fs/hostfs/meta_fs.c
new file mode 100644 (file)
index 0000000..7464149
--- /dev/null
@@ -0,0 +1,520 @@
+/* 
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include "hostfs.h"
+#include "metadata.h"
+#include "kern_util.h"
+
+#define METADATA_FILE_PATH(meta) (meta)->root, "file_metadata"
+#define METADATA_DIR_PATH(meta) (meta)->root, "dir_metadata"
+
+struct meta_fs {
+       struct humfs humfs;
+       char *root;
+};
+
+struct meta_file {
+       struct humfs_file humfs;
+       struct file_handle fh;
+};
+
+static int meta_file_path(const char *path, struct meta_fs *meta, 
+                         const char *path_out[])
+{
+       const char *data_path[] = { meta->root, "data", path, NULL };
+       char data_tmp[HOSTFS_BUFSIZE];
+       char *data_file = get_path(data_path, data_tmp, sizeof(data_tmp));
+
+       if(data_file == NULL)
+               return(-ENOMEM);
+
+       path_out[0] = meta->root;
+       path_out[2] = path;
+       if(os_file_type(data_file) == OS_TYPE_DIR){
+               path_out[1] = "dir_metadata";
+               path_out[3] = "metadata";
+               path_out[4] = NULL;
+       }
+       else {
+               path_out[1] = "file_metadata";
+               path_out[3] = NULL;
+       }
+
+       return(0);
+}
+
+static int open_meta_file(const char *path, struct humfs *humfs,
+                         struct file_handle *fh)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       const char *meta_path[5];
+       char meta_tmp[HOSTFS_BUFSIZE];
+       char *meta_file;
+       int err;
+
+       err = meta_file_path(path, meta, meta_path);
+       if(err)
+               goto out;
+
+       meta_file = get_path(meta_path, meta_tmp, sizeof(meta_tmp));
+       if(meta_file == NULL)
+               goto out;
+       
+       err = open_filehandle(meta_file, of_rdwr(OPENFLAGS()), 0, fh);
+
+ out:
+       return(err);
+}
+
+static char *meta_fs_name(struct inode *inode)
+{
+       struct humfs *mount = inode_humfs_info(inode);
+       struct meta_fs *meta = container_of(mount, struct meta_fs, humfs);
+       const char *metadata_path[5];
+       char tmp[HOSTFS_BUFSIZE], *name, *file;
+
+       if(meta_file_path("", meta, metadata_path))
+               return(NULL);
+
+       file = get_path(metadata_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               return(NULL);
+
+       name = inode_name_prefix(inode, file);
+
+       free_path(file, tmp);
+       return(name);
+}
+
+static void metafs_invisible(struct humfs_file *hf)
+{
+       struct meta_file *mf = container_of(hf, struct meta_file, humfs);
+
+       not_reclaimable(&mf->fh);
+}
+
+static struct humfs_file *metafs_init_file(void)
+{
+       struct meta_file *mf;
+       int err = -ENOMEM;
+
+       mf = kmalloc(sizeof(*mf), GFP_KERNEL);
+       if(mf == NULL)
+               return(ERR_PTR(err));
+
+       return(&mf->humfs);
+}
+
+static int metafs_open_file(struct humfs_file *hf, const char *path, 
+                           struct inode *inode, struct humfs *humfs)
+{
+       struct meta_file *mf = container_of(hf, struct meta_file, humfs);
+       int err;
+
+       err = open_meta_file(path, humfs, &mf->fh);
+       if(err)
+               return(err);
+
+       is_reclaimable(&mf->fh, meta_fs_name, inode);
+
+       return(0);
+}
+
+static void metafs_close_file(struct humfs_file *hf)
+{
+       struct meta_file *meta = container_of(hf, struct meta_file, humfs);
+
+       close_file(&meta->fh);
+       kfree(meta);
+}
+
+static int metafs_create_file(struct humfs_file *hf, const char *path, 
+                             int mode, int uid, int gid, struct inode *inode, 
+                             struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       struct meta_file *mf = container_of(hf, struct meta_file, humfs);
+       char tmp[HOSTFS_BUFSIZE];
+       const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
+       char *file = get_path(metadata_path, tmp, sizeof(tmp));
+       char buf[sizeof("mmmm uuuuuuuuuu gggggggggg")];
+       int err = -ENOMEM;
+
+       if(file == NULL)
+               goto out;
+
+       err = open_filehandle(file, of_write(of_create(OPENFLAGS())), 0644, 
+                             &mf->fh);
+       if(err)
+               goto out_free_path;
+
+       if(inode != NULL)
+               is_reclaimable(&mf->fh, meta_fs_name, inode);
+
+       sprintf(buf, "%d %d %d\n", mode  & S_IRWXUGO, uid, gid);
+       err = write_file(&mf->fh, 0, buf, strlen(buf));
+       if(err < 0)
+               goto out_rm;
+
+       free_path(file, tmp);
+       return(0);
+
+ out_rm:
+       close_file(&mf->fh);
+       os_remove_file(file);
+ out_free_path:
+       free_path(file, tmp);
+ out:
+       return(err);
+}
+
+static int metafs_create_link(const char *to, const char *from, 
+                             struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       const char *path_to[] = { METADATA_FILE_PATH(meta), to,  NULL };
+       const char *path_from[] = { METADATA_FILE_PATH(meta), from, NULL };
+
+       return(host_link_file(path_to, path_from));
+}
+
+static int metafs_remove_file(const char *path, struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       char tmp[HOSTFS_BUFSIZE];
+       const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
+       char *file = get_path(metadata_path, tmp, sizeof(tmp));
+       int err = -ENOMEM;
+
+       if(file == NULL)
+               goto out;
+
+       err = os_remove_file(file);
+
+ out:
+       free_path(file, tmp);
+       return(err);
+}
+
+static int metafs_create_directory(const char *path, int mode, int uid, 
+                                  int gid, struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       char tmp[HOSTFS_BUFSIZE];
+       const char *dir_path[] = { METADATA_DIR_PATH(meta), path, NULL, NULL };
+       const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL, 
+                                   NULL };
+       char *file, dir_meta[sizeof("mmmm uuuuuuuuuu gggggggggg\n")];
+       int err, fd;
+
+       err = host_make_dir(dir_path, 0755);
+       if(err)
+               goto out;
+
+       err = host_make_dir(file_path, 0755);
+       if(err)
+               goto out_rm;
+
+       /* This to make the index independent of the number of elements in
+        * METADATA_DIR_PATH().
+        */
+       dir_path[sizeof(dir_path) / sizeof(dir_path[0]) - 2] = "metadata";
+
+       err = -ENOMEM;
+       file = get_path(dir_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       fd = os_open_file(file, of_create(of_rdwr(OPENFLAGS())), 0644);
+       if(fd < 0){
+               err = fd;
+               goto out_free;
+       }
+
+       sprintf(dir_meta, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
+       err = os_write_file(fd, dir_meta, strlen(dir_meta));
+       if(err > 0)
+               err = 0;
+
+       os_close_file(fd);
+
+ out_free:
+       free_path(file, tmp);
+ out_rm:
+       host_remove_dir(dir_path);
+ out:
+       return(err);
+}
+
+static int metafs_remove_directory(const char *path, struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       char tmp[HOSTFS_BUFSIZE], *file;
+       const char *dir_path[] = { METADATA_DIR_PATH(meta), path, "metadata", 
+                                  NULL };
+       const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL };
+       char *slash;
+       int err;
+
+       err = -ENOMEM;
+       file = get_path(dir_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_remove_file(file);
+       if(err)
+               goto out_free;
+
+       slash = strrchr(file, '/');
+       if(slash == NULL){
+               printk("remove_shadow_directory failed to find last slash\n");
+               goto out_free;
+       }
+       *slash = '\0';
+       err = os_remove_dir(file);
+       free_path(file, tmp);
+
+       file = get_path(file_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = os_remove_dir(file);
+       if(err)
+               goto out_free;
+
+ out:
+       return(err);
+ out_free:
+       free_path(file, tmp);
+       goto out;
+}
+
+static int metafs_make_node(const char *path, int mode, int uid, int gid, 
+                           int type, int maj, int min, struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       struct file_handle fh;
+       char tmp[HOSTFS_BUFSIZE];
+       const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
+       int err;
+       char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")], *file;
+
+       sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid, type, 
+               maj, min);
+
+       err = -ENOMEM;
+       file = get_path(metadata_path, tmp, sizeof(tmp));
+       if(file == NULL)
+               goto out;
+
+       err = open_filehandle(file, 
+                             of_create(of_rdwr(OPENFLAGS())), 0644, &fh);
+       if(err)
+               goto out_free;
+
+       err = write_file(&fh, 0, buf, strlen(buf));
+       if(err > 0)
+               err = 0;
+
+       close_file(&fh);
+
+ out_free:
+       free_path(file, tmp);
+ out:
+       return(err);
+}
+
+static int metafs_ownerships(const char *path, int *mode_out, int *uid_out, 
+                            int *gid_out, char *type_out, int *maj_out, 
+                            int *min_out, struct humfs *humfs)
+{
+       struct file_handle fh;
+       char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
+       int err, n, mode, uid, gid, maj, min;
+       char type;
+
+       err = open_meta_file(path, humfs, &fh);
+       if(err)
+               goto out;
+
+       err = os_read_file(fh.fd, buf, sizeof(buf) - 1);
+       if(err < 0)
+               goto out_close;
+
+       buf[err] = '\0';
+       err = 0;
+
+       n = sscanf(buf, "%d %d %d %c %d %d", &mode, &uid, &gid, &type, &maj, 
+                  &min);
+       if(n == 3){
+               maj = -1;
+               min = -1;
+               type = 0;
+               err = 0;
+       }
+       else if(n != 6)
+               err = -EINVAL;
+
+       if(mode_out != NULL)
+               *mode_out = mode;
+       if(uid_out != NULL)
+               *uid_out = uid;
+       if(gid_out != NULL)
+               *gid_out = uid;
+       if(type_out != NULL)
+               *type_out = type;
+       if(maj_out != NULL)
+               *maj_out = maj;
+       if(min_out != NULL)
+               *min_out = min;
+
+ out_close:
+       close_file(&fh);
+ out:
+       return(err);
+}
+
+static int metafs_change_ownerships(const char *path, int mode, int uid, 
+                                   int gid, struct humfs *humfs)
+{
+       struct file_handle fh;
+       char type;
+       char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
+       int err = -ENOMEM, old_mode, old_uid, old_gid, n, maj, min;
+
+       err = open_meta_file(path, humfs, &fh);
+       if(err)
+               goto out;
+
+       err = read_file(&fh, 0, buf, sizeof(buf) - 1);
+       if(err < 0)
+               goto out_close;
+
+       buf[err] = '\0';
+
+       n = sscanf(buf, "%d %d %d %c %d %d\n", &old_mode, &old_uid, &old_gid,
+                  &type, &maj, &min);
+       if((n != 3) && (n != 6)){
+               err = -EINVAL;
+               goto out_close;
+       }
+
+       if(mode == -1)
+                mode = old_mode;
+       if(uid == -1)
+               uid = old_uid;
+       if(gid == -1)
+               gid = old_gid;
+
+       if(n == 3)
+               sprintf(buf, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
+       else
+               sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid,
+                       type, maj, min);
+
+       err = write_file(&fh, 0, buf, strlen(buf));
+       if(err > 0)
+               err = 0;
+
+       err = truncate_file(&fh, strlen(buf));
+
+ out_close:
+       close_file(&fh);
+ out:
+       return(err);
+}
+
+static int metafs_rename_file(const char *from, const char *to, 
+                             struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       const char *metadata_path_from[5], *metadata_path_to[5];
+       int err;
+
+       err = meta_file_path(from, meta, metadata_path_from);
+       if(err)
+               return(err);
+
+       err = meta_file_path(to, meta, metadata_path_to);
+       if(err)
+               return(err);
+
+       return(host_rename_file(metadata_path_from, metadata_path_to));
+}
+
+static struct humfs *metafs_init_mount(char *root)
+{
+       struct meta_fs *meta;
+       int err = -ENOMEM;
+
+       meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+       if(meta == NULL)
+               goto out;
+
+       meta->root = uml_strdup(root);
+       if(meta->root == NULL)
+               goto out_free_meta;
+
+       return(&meta->humfs);
+
+ out_free_meta:
+       kfree(meta);
+ out:
+       return(ERR_PTR(err));
+}
+
+static void metafs_free_mount(struct humfs *humfs)
+{
+       struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
+       
+       kfree(meta);
+}
+
+struct humfs_meta_ops hum_fs_meta_fs_ops = {
+       .list                   = LIST_HEAD_INIT(hum_fs_meta_fs_ops.list),
+       .name                   = "shadow_fs",
+       .init_file              = metafs_init_file,
+       .open_file              = metafs_open_file,
+       .close_file             = metafs_close_file,
+       .ownerships             = metafs_ownerships,
+       .make_node              = metafs_make_node,
+       .create_file            = metafs_create_file,
+       .create_link            = metafs_create_link,
+       .remove_file            = metafs_remove_file,
+       .create_dir             = metafs_create_directory,
+       .remove_dir             = metafs_remove_directory,
+       .change_ownerships      = metafs_change_ownerships,
+       .rename_file            = metafs_rename_file,
+       .invisible              = metafs_invisible,
+       .init_mount             = metafs_init_mount,
+       .free_mount             = metafs_free_mount,
+};
+
+static int __init init_meta_fs(void)
+{
+       register_meta(&hum_fs_meta_fs_ops);
+       return(0);
+}
+
+static void __exit exit_meta_fs(void)
+{
+       unregister_meta(&hum_fs_meta_fs_ops);
+}
+
+__initcall(init_meta_fs);
+__exitcall(exit_meta_fs);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/metadata.h b/fs/hostfs/metadata.h
new file mode 100644 (file)
index 0000000..924fb5b
--- /dev/null
@@ -0,0 +1,79 @@
+/* 
+ * Copyright (C) 2004 Piotr Neuman (sikkh@wp.pl) and 
+ * Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_FS_METADATA
+#define __UM_FS_METADATA
+
+#include "linux/fs.h"
+#include "linux/list.h"
+#include "os.h"
+#include "hostfs.h"
+
+struct humfs {
+       struct externfs_data ext;
+       __u64 used;
+       __u64 total;
+       char *data;
+       int mmap;
+       int direct;
+       struct humfs_meta_ops *meta;
+};
+
+struct humfs_file {
+       struct humfs *mount;
+       struct file_handle data;
+       struct externfs_inode ext;
+};
+
+struct humfs_meta_ops {
+       struct list_head list;
+       char *name;
+       struct humfs_file *(*init_file)(void);
+       int (*open_file)(struct humfs_file *hf, const char *path, 
+                        struct inode *inode, struct humfs *humfs);
+       int (*create_file)(struct humfs_file *hf, const char *path, int mode, 
+                          int uid, int gid, struct inode *inode, 
+                          struct humfs *humfs);
+       void (*close_file)(struct humfs_file *humfs);
+       int (*ownerships)(const char *path, int *mode_out, int *uid_out, 
+                         int *gid_out, char *type_out, int *maj_out, 
+                         int *min_out, struct humfs *humfs);
+       int (*make_node)(const char *path, int mode, int uid, int gid,
+                        int type, int major, int minor, struct humfs *humfs);
+       int (*create_link)(const char *to, const char *from, 
+                          struct humfs *humfs);
+       int (*remove_file)(const char *path, struct humfs *humfs);
+       int (*create_dir)(const char *path, int mode, int uid, int gid, 
+                         struct humfs *humfs);
+       int (*remove_dir)(const char *path, struct humfs *humfs);
+       int (*change_ownerships)(const char *path, int mode, int uid, int gid,
+                                struct humfs *humfs);
+       int (*rename_file)(const char *from, const char *to, 
+                          struct humfs *humfs);
+       void (*invisible)(struct humfs_file *hf);
+       struct humfs *(*init_mount)(char *root);
+       void (*free_mount)(struct humfs *humfs);
+};
+
+extern void register_meta(struct humfs_meta_ops *ops);
+extern void unregister_meta(struct humfs_meta_ops *ops);
+
+extern char *humfs_path(char *dir, char *file);
+extern char *humfs_name(struct inode *inode, char *prefix);
+extern struct humfs *inode_humfs_info(struct inode *inode);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
new file mode 100644 (file)
index 0000000..e67f038
--- /dev/null
@@ -0,0 +1,19 @@
+# 
+# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+hppfs-objs := hppfs_kern.o
+
+obj-y = 
+obj-$(CONFIG_HPPFS) += hppfs.o
+
+clean:
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper: clean
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
new file mode 100644 (file)
index 0000000..ebf08cb
--- /dev/null
@@ -0,0 +1,811 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/dcache.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include "os.h"
+
+static int init_inode(struct inode *inode, struct dentry *dentry);
+
+struct hppfs_data {
+       struct list_head list;
+       char contents[PAGE_SIZE - sizeof(struct list_head)];
+};
+
+struct hppfs_private {
+       struct file proc_file;
+       int host_fd;
+       loff_t len;
+       struct hppfs_data *contents;
+};
+
+struct hppfs_inode_info {
+        struct dentry *proc_dentry;
+       struct inode vfs_inode;
+};
+
+static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
+{
+       return(list_entry(inode, struct hppfs_inode_info, vfs_inode));
+}
+
+#define HPPFS_SUPER_MAGIC 0xb00000ee
+
+static struct super_operations hppfs_sbops;
+
+static int is_pid(struct dentry *dentry)
+{
+       struct super_block *sb;
+       int i;
+
+       sb = dentry->d_sb;
+       if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
+               return(0);
+
+       for(i = 0; i < dentry->d_name.len; i++){
+               if(!isdigit(dentry->d_name.name[i]))
+                       return(0);
+       }
+       return(1);
+}
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+       struct dentry *parent;
+       char *root, *name;
+       const char *seg_name;
+       int len, seg_len;
+
+       len = 0;
+       parent = dentry;
+       while(parent->d_parent != parent){
+               if(is_pid(parent))
+                       len += strlen("pid") + 1;
+               else len += parent->d_name.len + 1;
+               parent = parent->d_parent;
+       }
+       
+       root = "proc";
+       len += strlen(root);
+       name = kmalloc(len + extra + 1, GFP_KERNEL);
+       if(name == NULL) return(NULL);
+
+       name[len] = '\0';
+       parent = dentry;
+       while(parent->d_parent != parent){
+               if(is_pid(parent)){
+                       seg_name = "pid";
+                       seg_len = strlen("pid");
+               }
+               else {
+                       seg_name = parent->d_name.name;
+                       seg_len = parent->d_name.len;
+               }
+
+               len -= seg_len + 1;
+               name[len] = '/';
+               strncpy(&name[len + 1], seg_name, seg_len);
+               parent = parent->d_parent;
+       }
+       strncpy(name, root, strlen(root));
+       return(name);
+}
+
+struct dentry_operations hppfs_dentry_ops = {
+};
+
+static int file_removed(struct dentry *dentry, const char *file)
+{
+       char *host_file;
+       int extra, fd;
+
+       extra = 0;
+       if(file != NULL) extra += strlen(file) + 1;
+
+       host_file = dentry_name(dentry, extra + strlen("/remove"));
+       if(host_file == NULL){
+               printk("file_removed : allocation failed\n");
+               return(-ENOMEM);
+       }
+
+       if(file != NULL){
+               strcat(host_file, "/");
+               strcat(host_file, file);
+       }
+       strcat(host_file, "/remove");
+
+       fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+       kfree(host_file);
+       if(fd > 0){
+               os_close_file(fd);
+               return(1);
+       }
+       return(0);
+}
+
+static void hppfs_read_inode(struct inode *ino)
+{
+       struct inode *proc_ino;
+
+       if(HPPFS_I(ino)->proc_dentry == NULL)
+               return;
+
+       proc_ino = HPPFS_I(ino)->proc_dentry->d_inode;
+       ino->i_uid = proc_ino->i_uid;
+       ino->i_gid = proc_ino->i_gid;
+       ino->i_atime = proc_ino->i_atime;
+       ino->i_mtime = proc_ino->i_mtime;
+       ino->i_ctime = proc_ino->i_ctime;
+       ino->i_ino = proc_ino->i_ino;
+       ino->i_mode = proc_ino->i_mode;
+       ino->i_nlink = proc_ino->i_nlink;
+       ino->i_size = proc_ino->i_size;
+       ino->i_blksize = proc_ino->i_blksize;
+       ino->i_blocks = proc_ino->i_blocks;
+}
+
+static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, 
+                                  struct nameidata *nd)
+{
+       struct dentry *proc_dentry, *new, *parent;
+       struct inode *inode;
+       int err, deleted;
+
+       deleted = file_removed(dentry, NULL);
+       if(deleted < 0)
+               return(ERR_PTR(deleted));
+       else if(deleted)
+               return(ERR_PTR(-ENOENT));
+
+       err = -ENOMEM;
+       parent = HPPFS_I(ino)->proc_dentry;
+       down(&parent->d_inode->i_sem);
+       proc_dentry = d_lookup(parent, &dentry->d_name);
+       if(proc_dentry == NULL){
+               proc_dentry = d_alloc(parent, &dentry->d_name);
+               if(proc_dentry == NULL){
+                       up(&parent->d_inode->i_sem);
+                       goto out;
+               }
+               new = (*parent->d_inode->i_op->lookup)(parent->d_inode, 
+                                                      proc_dentry, NULL);
+               if(new){
+                       dput(proc_dentry);
+                       proc_dentry = new;
+               }
+       }
+       up(&parent->d_inode->i_sem);
+
+       if(IS_ERR(proc_dentry))
+               return(proc_dentry);
+
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out_dput;
+
+       err = init_inode(inode, proc_dentry);
+       if(err) 
+               goto out_put;
+       
+       hppfs_read_inode(inode);
+
+       d_add(dentry, inode);
+       dentry->d_op = &hppfs_dentry_ops;
+       return(NULL);
+
+ out_put:
+       iput(inode);
+ out_dput:
+       dput(proc_dentry);
+ out:
+       return(ERR_PTR(err));
+}
+
+static struct inode_operations hppfs_file_iops = {
+};
+
+static ssize_t read_proc(struct file *file, char *buf, ssize_t count, 
+                        loff_t *ppos, int is_user)
+{
+       ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+       ssize_t n;
+
+       read = file->f_dentry->d_inode->i_fop->read;
+
+       if(!is_user)
+               set_fs(KERNEL_DS);
+               
+       n = (*read)(file, buf, count, &file->f_pos);
+
+       if(!is_user)
+               set_fs(USER_DS);
+
+       if(ppos) *ppos = file->f_pos;
+       return(n);
+}
+
+static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
+{
+       ssize_t n;
+       int cur, err;
+       char *new_buf;
+
+       n = -ENOMEM;
+       new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if(new_buf == NULL){
+               printk("hppfs_read_file : kmalloc failed\n");
+               goto out;
+       }
+       n = 0;
+       while(count > 0){
+               cur = min_t(ssize_t, count, PAGE_SIZE);
+               err = os_read_file(fd, new_buf, cur);
+               if(err < 0){
+                       printk("hppfs_read : read failed, errno = %d\n",
+                              count);
+                       n = err;
+                       goto out_free;
+               }
+               else if(err == 0)
+                       break;
+
+               if(copy_to_user(buf, new_buf, err)){
+                       n = -EFAULT;
+                       goto out_free;
+               }
+               n += err;
+               count -= err;
+       }
+ out_free:
+       kfree(new_buf);
+ out:
+       return(n);
+}
+
+static ssize_t hppfs_read(struct file *file, char *buf, size_t count, 
+                         loff_t *ppos)
+{
+       struct hppfs_private *hppfs = file->private_data;
+       struct hppfs_data *data;
+       loff_t off;
+       int err;
+
+       if(hppfs->contents != NULL){
+               if(*ppos >= hppfs->len) return(0);
+
+               data = hppfs->contents;
+               off = *ppos;
+               while(off >= sizeof(data->contents)){
+                       data = list_entry(data->list.next, struct hppfs_data,
+                                         list);
+                       off -= sizeof(data->contents);
+               }
+
+               if(off + count > hppfs->len)
+                       count = hppfs->len - off;
+               copy_to_user(buf, &data->contents[off], count);
+               *ppos += count;
+       }
+       else if(hppfs->host_fd != -1){
+               err = os_seek_file(hppfs->host_fd, *ppos);
+               if(err){
+                       printk("hppfs_read : seek failed, errno = %d\n", err);
+                       return(err);
+               }
+               count = hppfs_read_file(hppfs->host_fd, buf, count);
+               if(count > 0)
+                       *ppos += count;
+       }
+       else count = read_proc(&hppfs->proc_file, buf, count, ppos, 1);
+
+       return(count);
+}
+
+static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, 
+                          loff_t *ppos)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+       int err;
+
+       write = proc_file->f_dentry->d_inode->i_fop->write;
+
+       proc_file->f_pos = file->f_pos;
+       err = (*write)(proc_file, buf, len, &proc_file->f_pos);
+       file->f_pos = proc_file->f_pos;
+
+       return(err);
+}
+
+static int open_host_sock(char *host_file, int *filter_out)
+{
+       char *end;
+       int fd;
+
+       end = &host_file[strlen(host_file)];
+       strcpy(end, "/rw");
+       *filter_out = 1;
+       fd = os_connect_socket(host_file);
+       if(fd > 0)
+               return(fd);
+
+       strcpy(end, "/r");
+       *filter_out = 0;
+       fd = os_connect_socket(host_file);
+       return(fd);
+}
+
+static void free_contents(struct hppfs_data *head)
+{
+       struct hppfs_data *data;
+       struct list_head *ele, *next;
+
+       if(head == NULL) return;
+
+       list_for_each_safe(ele, next, &head->list){
+               data = list_entry(ele, struct hppfs_data, list);
+               kfree(data);
+       }
+       kfree(head);
+}
+
+static struct hppfs_data *hppfs_get_data(int fd, int filter, 
+                                        struct file *proc_file, 
+                                        struct file *hppfs_file, 
+                                        loff_t *size_out)
+{
+       struct hppfs_data *data, *new, *head;
+       int n, err;
+
+       err = -ENOMEM;
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if(data == NULL){
+               printk("hppfs_get_data : head allocation failed\n");
+               goto failed;
+       }
+
+       INIT_LIST_HEAD(&data->list);
+
+       head = data;
+       *size_out = 0;
+
+       if(filter){
+               while((n = read_proc(proc_file, data->contents,
+                                    sizeof(data->contents), NULL, 0)) > 0)
+                       os_write_file(fd, data->contents, n);
+               err = os_shutdown_socket(fd, 0, 1);
+               if(err){
+                       printk("hppfs_get_data : failed to shut down "
+                              "socket\n");
+                       goto failed_free;
+               }
+       }
+       while(1){
+               n = os_read_file(fd, data->contents, sizeof(data->contents));
+               if(n < 0){
+                       err = n;
+                       printk("hppfs_get_data : read failed, errno = %d\n",
+                              err);
+                       goto failed_free;
+               }
+               else if(n == 0)
+                       break;
+
+               *size_out += n;
+
+               if(n < sizeof(data->contents))
+                       break;
+
+               new = kmalloc(sizeof(*data), GFP_KERNEL);
+               if(new == 0){
+                       printk("hppfs_get_data : data allocation failed\n");
+                       err = -ENOMEM;
+                       goto failed_free;
+               }
+       
+               INIT_LIST_HEAD(&new->list);
+               list_add(&new->list, &data->list);
+               data = new;
+       }
+       return(head);
+
+ failed_free:
+       free_contents(head);
+ failed:               
+       return(ERR_PTR(err));
+}
+
+static struct hppfs_private *hppfs_data(void)
+{
+       struct hppfs_private *data;
+
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if(data == NULL)
+               return(data);
+
+       *data = ((struct hppfs_private ) { .host_fd             = -1,
+                                          .len                 = -1,
+                                          .contents            = NULL } );
+       return(data);
+}
+
+static int file_mode(int fmode)
+{
+       if(fmode == (FMODE_READ | FMODE_WRITE))
+               return(O_RDWR);
+       if(fmode == FMODE_READ)
+               return(O_RDONLY);
+       if(fmode == FMODE_WRITE)
+               return(O_WRONLY);
+       return(0);
+}
+
+static int hppfs_open(struct inode *inode, struct file *file)
+{
+       struct hppfs_private *data;
+       struct dentry *proc_dentry;
+       char *host_file;
+       int err, fd, type, filter;
+
+       err = -ENOMEM;
+       data = hppfs_data();
+       if(data == NULL)
+               goto out;
+
+       host_file = dentry_name(file->f_dentry, strlen("/rw"));
+       if(host_file == NULL)
+               goto out_free2;
+
+       proc_dentry = HPPFS_I(inode)->proc_dentry;
+
+       /* XXX This isn't closed anywhere */
+       err = open_private_file(&data->proc_file, proc_dentry, 
+                               file_mode(file->f_mode));
+       if(err)
+               goto out_free1;
+
+       type = os_file_type(host_file);
+       if(type == OS_TYPE_FILE){
+               fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+               if(fd >= 0) 
+                       data->host_fd = fd;
+               else printk("hppfs_open : failed to open '%s', errno = %d\n",
+                           host_file, -fd);
+
+               data->contents = NULL;
+       }
+       else if(type == OS_TYPE_DIR){
+               fd = open_host_sock(host_file, &filter);
+               if(fd > 0){
+                       data->contents = hppfs_get_data(fd, filter, 
+                                                       &data->proc_file, 
+                                                       file, &data->len);
+                       if(!IS_ERR(data->contents))
+                               data->host_fd = fd;
+               }
+               else printk("hppfs_open : failed to open a socket in "
+                           "'%s', errno = %d\n", host_file, -fd);
+       }
+       kfree(host_file);
+
+       file->private_data = data;
+       return(0);
+
+ out_free1:
+       kfree(host_file);
+ out_free2:
+       free_contents(data->contents);
+       kfree(data);
+ out:
+       return(err);
+}
+
+static int hppfs_dir_open(struct inode *inode, struct file *file)
+{
+       struct hppfs_private *data;
+       struct dentry *proc_dentry;
+       int err;
+
+       err = -ENOMEM;
+       data = hppfs_data();
+       if(data == NULL)
+               goto out;
+
+       proc_dentry = HPPFS_I(inode)->proc_dentry;
+       err = open_private_file(&data->proc_file, proc_dentry, 
+                               file_mode(file->f_mode));
+       if(err)
+               goto out_free;
+
+       file->private_data = data;
+       return(0);
+
+ out_free:
+       kfree(data);
+ out:
+       return(err);
+}
+
+static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       loff_t (*llseek)(struct file *, loff_t, int);
+       loff_t ret;
+
+       llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
+       if(llseek != NULL){
+               ret = (*llseek)(proc_file, off, where);
+               if(ret < 0)
+                       return(ret);
+       }
+
+       return(default_llseek(file, off, where));
+}
+
+static struct file_operations hppfs_file_fops = {
+       .owner          = NULL,
+       .llseek         = hppfs_llseek,
+       .read           = hppfs_read,
+       .write          = hppfs_write,
+       .open           = hppfs_open,
+};
+
+struct hppfs_dirent {
+       void *vfs_dirent;
+       filldir_t filldir;
+       struct dentry *dentry;
+};
+
+static int hppfs_filldir(void *d, const char *name, int size, 
+                        loff_t offset, ino_t inode, unsigned int type)
+{
+       struct hppfs_dirent *dirent = d;
+
+       if(file_removed(dirent->dentry, name))
+               return(0);
+
+       return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, 
+                                 inode, type));
+}
+
+static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       int (*readdir)(struct file *, void *, filldir_t);
+       struct hppfs_dirent dirent = ((struct hppfs_dirent)
+                                     { .vfs_dirent     = ent,
+                                       .filldir        = filldir,
+                                       .dentry         = file->f_dentry } );
+       int err;
+
+       readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
+
+       proc_file->f_pos = file->f_pos;
+       err = (*readdir)(proc_file, &dirent, hppfs_filldir);
+       file->f_pos = proc_file->f_pos;
+
+       return(err);
+}
+
+static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       return(0);
+}
+
+static struct file_operations hppfs_dir_fops = {
+       .owner          = NULL,
+       .readdir        = hppfs_readdir,
+       .open           = hppfs_dir_open,
+       .fsync          = hppfs_fsync,
+};
+
+static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+       sf->f_blocks = 0;
+       sf->f_bfree = 0;
+       sf->f_bavail = 0;
+       sf->f_files = 0;
+       sf->f_ffree = 0;
+       sf->f_type = HPPFS_SUPER_MAGIC;
+       return(0);
+}
+
+static struct inode *hppfs_alloc_inode(struct super_block *sb)
+{
+       struct hppfs_inode_info *hi;
+
+       hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+       if(hi == NULL) 
+               return(NULL);
+
+       *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL });
+       inode_init_once(&hi->vfs_inode);
+       return(&hi->vfs_inode);
+}
+
+void hppfs_delete_inode(struct inode *ino)
+{
+       clear_inode(ino);
+}
+
+static void hppfs_destroy_inode(struct inode *inode)
+{
+       kfree(HPPFS_I(inode));
+}
+
+static struct super_operations hppfs_sbops = { 
+       .alloc_inode    = hppfs_alloc_inode,
+       .destroy_inode  = hppfs_destroy_inode,
+       .read_inode     = hppfs_read_inode,
+       .delete_inode   = hppfs_delete_inode,
+       .statfs         = hppfs_statfs,
+};
+
+static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+       struct file proc_file;
+       struct dentry *proc_dentry;
+       int (*readlink)(struct dentry *, char *, int);
+       int err, n;
+
+       proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+       err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
+       if(err) 
+               return(err);
+
+       readlink = proc_dentry->d_inode->i_op->readlink;
+       n = (*readlink)(proc_dentry, buffer, buflen);
+
+       close_private_file(&proc_file);
+       
+       return(n);
+}
+
+static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       struct file proc_file;
+       struct dentry *proc_dentry;
+       int (*follow_link)(struct dentry *, struct nameidata *);
+       int err, n;
+
+       proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+       err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
+       if(err) 
+               return(err);
+
+       follow_link = proc_dentry->d_inode->i_op->follow_link;
+       n = (*follow_link)(proc_dentry, nd);
+
+       close_private_file(&proc_file);
+       
+       return(n);
+}
+
+static struct inode_operations hppfs_dir_iops = {
+       .lookup         = hppfs_lookup,
+};
+
+static struct inode_operations hppfs_link_iops = {
+       .readlink       = hppfs_readlink,
+       .follow_link    = hppfs_follow_link,
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+       if(S_ISDIR(dentry->d_inode->i_mode)){
+               inode->i_op = &hppfs_dir_iops;
+               inode->i_fop = &hppfs_dir_fops;
+       }
+       else if(S_ISLNK(dentry->d_inode->i_mode)){
+               inode->i_op = &hppfs_link_iops;
+               inode->i_fop = &hppfs_file_fops;
+       }
+       else {
+               inode->i_op = &hppfs_file_iops;
+               inode->i_fop = &hppfs_file_fops;
+       }
+
+       HPPFS_I(inode)->proc_dentry = dentry;
+
+       return(0);
+}
+
+static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
+{
+       struct inode *root_inode;
+       struct file_system_type *procfs;
+       struct super_block *proc_sb;
+       int err;
+
+       err = -ENOENT;
+       procfs = get_fs_type("proc");
+       if(procfs == NULL) 
+               goto out;
+
+       if(list_empty(&procfs->fs_supers))
+               goto out;
+
+       proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
+                            s_instances);
+       
+       sb->s_blocksize = 1024;
+       sb->s_blocksize_bits = 10;
+       sb->s_magic = HPPFS_SUPER_MAGIC;
+       sb->s_op = &hppfs_sbops;
+
+       root_inode = iget(sb, 0);
+       if(root_inode == NULL)
+               goto out;
+
+       err = init_inode(root_inode, proc_sb->s_root);
+       if(err)
+               goto out_put;
+
+       err = -ENOMEM;
+       sb->s_root = d_alloc_root(root_inode);
+       if(sb->s_root == NULL)
+               goto out_put;
+
+       hppfs_read_inode(root_inode);
+
+       return(0);
+
+ out_put:
+       iput(root_inode);
+ out:
+       return(err);
+}
+
+static struct super_block *hppfs_read_super(struct file_system_type *type,
+                                            int flags, const char *dev_name,
+                                            void *data)
+{
+       return(get_sb_nodev(type, flags, data, hppfs_fill_super));
+}
+
+static struct file_system_type hppfs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "hppfs",
+       .get_sb         = hppfs_read_super,
+       .kill_sb        = kill_anon_super,
+       .fs_flags       = 0,
+};
+
+static int __init init_hppfs(void)
+{
+       return(register_filesystem(&hppfs_type));
+}
+
+static void __exit exit_hppfs(void)
+{
+       unregister_filesystem(&hppfs_type);
+}
+
+module_init(init_hppfs)
+module_exit(exit_hppfs)
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
new file mode 100644 (file)
index 0000000..6777d8c
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in the 
+ * jffs2 directory.
+ *
+ * $Id: compr.h,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $
+ *
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/jffs2.h>
+#include <linux/jffs2_fs_i.h>
+#include <linux/jffs2_fs_sb.h>
+#include "nodelist.h"
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY  20
+#define JFFS2_LZARI_PRIORITY     30
+#define JFFS2_LZO_PRIORITY       40
+#define JFFS2_RTIME_PRIORITY     50
+#define JFFS2_ZLIB_PRIORITY      60
+
+#define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+#define JFFS2_DYNRUBIN_DISABLED  /*        for decompression */
+
+#define JFFS2_COMPR_MODE_NONE       0
+#define JFFS2_COMPR_MODE_PRIORITY   1
+#define JFFS2_COMPR_MODE_SIZE       2
+
+void jffs2_set_compression_mode(int mode);
+int jffs2_get_compression_mode(void);
+
+struct jffs2_compressor {
+        struct list_head list;
+        int priority;              /* used by prirority comr. mode */
+        char *name;
+        char compr;                /* JFFS2_COMPR_XXX */
+        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+                        uint32_t *srclen, uint32_t *destlen, void *model);
+        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+                        uint32_t cdatalen, uint32_t datalen, void *model);
+        int usecount;
+        int disabled;              /* if seted the compressor won't compress */
+        unsigned char *compr_buf;  /* used by size compr. mode */
+        uint32_t compr_buf_size;   /* used by size compr. mode */
+        uint32_t stat_compr_orig_size;
+        uint32_t stat_compr_new_size;
+        uint32_t stat_compr_blocks;
+        uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                             unsigned char *data_in, unsigned char **cpage_out,
+                             uint32_t *datalen, uint32_t *cdatalen);
+
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                     uint16_t comprtype, unsigned char *cdata_in,
+                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
+
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
+
+#ifdef CONFIG_JFFS2_PROC
+int jffs2_enable_compressor_name(const char *name);
+int jffs2_disable_compressor_name(const char *name);
+int jffs2_set_compression_mode_name(const char *mode_name);
+char *jffs2_get_compression_mode_name(void);
+int jffs2_set_compressor_priority(const char *mode_name, int priority);
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+#endif
+
+/* Compressor modules */
+/* These functions will be called by jffs2_compressors_init/exit */
+
+#ifdef CONFIG_JFFS2_RUBIN
+int jffs2_rubinmips_init(void);
+void jffs2_rubinmips_exit(void);
+int jffs2_dynrubin_init(void);
+void jffs2_dynrubin_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+int jffs2_rtime_init(void);
+void jffs2_rtime_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_LZARI
+int jffs2_lzari_init(void);
+void jffs2_lzari_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
+
+#endif /* __JFFS2_COMPR_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
new file mode 100644 (file)
index 0000000..4a173d3
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2001-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * 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/
+ */
+
+#include "xfs.h"
+#include "xfs_rw.h"
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+
+static struct ctl_table_header *xfs_table_header;
+
+
+#ifdef CONFIG_PROC_FS
+STATIC int
+xfs_stats_clear_proc_handler(
+       ctl_table       *ctl,
+       int             write,
+       struct file     *filp,
+       void            *buffer,
+       size_t          *lenp,
+       loff_t          *ppos)
+{
+       int             c, ret, *valp = ctl->data;
+       __uint32_t      vn_active;
+
+       ret = proc_dointvec_minmax(ctl, write, filp, buffer, lenp, ppos);
+
+       if (!ret && write && *valp) {
+               printk("XFS Clearing xfsstats\n");
+               for (c = 0; c < NR_CPUS; c++) {
+                       if (!cpu_possible(c)) continue;
+                       preempt_disable();
+                       /* save vn_active, it's a universal truth! */
+                       vn_active = per_cpu(xfsstats, c).vn_active;
+                       memset(&per_cpu(xfsstats, c), 0,
+                              sizeof(struct xfsstats));
+                       per_cpu(xfsstats, c).vn_active = vn_active;
+                       preempt_enable();
+               }
+               xfs_stats_clear = 0;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_PROC_FS */
+
+STATIC ctl_table xfs_table[] = {
+       {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.restrict_chown.min, &xfs_params.restrict_chown.max},
+
+       {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.sgid_inherit.min, &xfs_params.sgid_inherit.max},
+
+       {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.symlink_mode.min, &xfs_params.symlink_mode.max},
+
+       {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.panic_mask.min, &xfs_params.panic_mask.max},
+
+       {XFS_ERRLEVEL, "error_level", &xfs_params.error_level.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.error_level.min, &xfs_params.error_level.max},
+
+       {XFS_SYNCD_TIMER, "xfssyncd_centisecs", &xfs_params.syncd_timer.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.syncd_timer.min, &xfs_params.syncd_timer.max},
+
+       {XFS_INHERIT_SYNC, "inherit_sync", &xfs_params.inherit_sync.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.inherit_sync.min, &xfs_params.inherit_sync.max},
+
+       {XFS_INHERIT_NODUMP, "inherit_nodump", &xfs_params.inherit_nodump.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.inherit_nodump.min, &xfs_params.inherit_nodump.max},
+
+       {XFS_INHERIT_NOATIME, "inherit_noatime", &xfs_params.inherit_noatim.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max},
+       
+       {XFS_BUF_TIMER, "xfsbufd_centisecs", &xfs_params.xfs_buf_timer.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.xfs_buf_timer.min, &xfs_params.xfs_buf_timer.max},
+
+       {XFS_BUF_AGE, "age_buffer_centisecs", &xfs_params.xfs_buf_age.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.xfs_buf_age.min, &xfs_params.xfs_buf_age.max},
+
+       /* please keep this the last entry */
+#ifdef CONFIG_PROC_FS
+       {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
+       sizeof(int), 0644, NULL, &xfs_stats_clear_proc_handler,
+       &sysctl_intvec, NULL, 
+       &xfs_params.stats_clear.min, &xfs_params.stats_clear.max},
+#endif /* CONFIG_PROC_FS */
+
+       {0}
+};
+
+STATIC ctl_table xfs_dir_table[] = {
+       {FS_XFS, "xfs", NULL, 0, 0555, xfs_table},
+       {0}
+};
+
+STATIC ctl_table xfs_root_table[] = {
+       {CTL_FS, "fs",  NULL, 0, 0555, xfs_dir_table},
+       {0}
+};
+
+void
+xfs_sysctl_register(void)
+{
+       xfs_table_header = register_sysctl_table(xfs_root_table, 1);
+}
+
+void
+xfs_sysctl_unregister(void)
+{
+       if (xfs_table_header)
+               unregister_sysctl_table(xfs_table_header);
+}
diff --git a/include/asm-parisc/unwind.h b/include/asm-parisc/unwind.h
new file mode 100644 (file)
index 0000000..ff9396b
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _UNWIND_H_
+#define _UNWIND_H_
+
+/* From ABI specifications */
+struct unwind_table_entry {
+       unsigned int region_start;
+       unsigned int region_end;
+       unsigned int Cannot_unwind:1; /* 0 */
+       unsigned int Millicode:1;       /* 1 */
+       unsigned int Millicode_save_sr0:1;      /* 2 */
+       unsigned int Region_description:2;      /* 3..4 */
+       unsigned int reserved1:1;       /* 5 */
+       unsigned int Entry_SR:1;        /* 6 */
+       unsigned int Entry_FR:4;        /* number saved *//* 7..10 */
+       unsigned int Entry_GR:5;        /* number saved *//* 11..15 */
+       unsigned int Args_stored:1;     /* 16 */
+       unsigned int Variable_Frame:1;  /* 17 */
+       unsigned int Separate_Package_Body:1;   /* 18 */
+       unsigned int Frame_Extension_Millicode:1;       /* 19 */
+       unsigned int Stack_Overflow_Check:1;    /* 20 */
+       unsigned int Two_Instruction_SP_Increment:1;    /* 21 */
+       unsigned int Ada_Region:1;      /* 22 */
+       unsigned int cxx_info:1;        /* 23 */
+       unsigned int cxx_try_catch:1;   /* 24 */
+       unsigned int sched_entry_seq:1; /* 25 */
+       unsigned int reserved2:1;       /* 26 */
+       unsigned int Save_SP:1; /* 27 */
+       unsigned int Save_RP:1; /* 28 */
+       unsigned int Save_MRP_in_frame:1;       /* 29 */
+       unsigned int extn_ptr_defined:1;        /* 30 */
+       unsigned int Cleanup_defined:1; /* 31 */
+       
+       unsigned int MPE_XL_interrupt_marker:1; /* 0 */
+       unsigned int HP_UX_interrupt_marker:1;  /* 1 */
+       unsigned int Large_frame:1;     /* 2 */
+       unsigned int Pseudo_SP_Set:1;   /* 3 */
+       unsigned int reserved4:1;       /* 4 */
+       unsigned int Total_frame_size:27;       /* 5..31 */
+};
+
+struct unwind_table {
+       struct unwind_table *next;
+       const char *name;
+       unsigned long gp;
+       unsigned long base_addr;
+       unsigned long start;
+       unsigned long end;
+       const struct unwind_table_entry *table;
+       unsigned long length;
+};
+
+struct unwind_frame_info {
+       struct task_struct *t;
+       /* Eventually we would like to be able to get at any of the registers
+          available; but for now we only try to get the sp and ip for each
+          frame */
+       /* struct pt_regs regs; */
+       unsigned long sp, ip, rp;
+       unsigned long prev_sp, prev_ip;
+};
+
+void * unwind_table_add(const char *name, unsigned long base_addr, 
+                unsigned long gp,
+                 void *start, void *end);
+void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
+                      unsigned long sp, unsigned long ip, unsigned long rp);
+void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t);
+void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs);
+int unwind_once(struct unwind_frame_info *info);
+int unwind_to_user(struct unwind_frame_info *info);
+
+#endif
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
new file mode 100644 (file)
index 0000000..2957e79
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+ * Communication Processor Module v2.
+ *
+ * This file contains structures and information for the communication
+ * processor channels found in the dual port RAM or parameter RAM.
+ * All CPM control and status is available through the CPM2 internal
+ * memory map.  See immap_cpm2.h for details.
+ */
+#ifdef __KERNEL__
+#ifndef __CPM2__
+#define __CPM2__
+
+#include <asm/immap_cpm2.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST     ((uint)0x80000000)
+#define CPM_CR_PAGE    ((uint)0x7c000000)
+#define CPM_CR_SBLOCK  ((uint)0x03e00000)
+#define CPM_CR_FLG     ((uint)0x00010000)
+#define CPM_CR_MCN     ((uint)0x00003fc0)
+#define CPM_CR_OPCODE  ((uint)0x0000000f)
+
+/* Device sub-block and page codes.
+*/
+#define CPM_CR_SCC1_SBLOCK     (0x04)
+#define CPM_CR_SCC2_SBLOCK     (0x05)
+#define CPM_CR_SCC3_SBLOCK     (0x06)
+#define CPM_CR_SCC4_SBLOCK     (0x07)
+#define CPM_CR_SMC1_SBLOCK     (0x08)
+#define CPM_CR_SMC2_SBLOCK     (0x09)
+#define CPM_CR_SPI_SBLOCK      (0x0a)
+#define CPM_CR_I2C_SBLOCK      (0x0b)
+#define CPM_CR_TIMER_SBLOCK    (0x0f)
+#define CPM_CR_RAND_SBLOCK     (0x0e)
+#define CPM_CR_FCC1_SBLOCK     (0x10)
+#define CPM_CR_FCC2_SBLOCK     (0x11)
+#define CPM_CR_FCC3_SBLOCK     (0x12)
+#define CPM_CR_IDMA1_SBLOCK    (0x14)
+#define CPM_CR_IDMA2_SBLOCK    (0x15)
+#define CPM_CR_IDMA3_SBLOCK    (0x16)
+#define CPM_CR_IDMA4_SBLOCK    (0x17)
+#define CPM_CR_MCC1_SBLOCK     (0x1c)
+
+#define CPM_CR_SCC1_PAGE       (0x00)
+#define CPM_CR_SCC2_PAGE       (0x01)
+#define CPM_CR_SCC3_PAGE       (0x02)
+#define CPM_CR_SCC4_PAGE       (0x03)
+#define CPM_CR_SMC1_PAGE       (0x07)
+#define CPM_CR_SMC2_PAGE       (0x08)
+#define CPM_CR_SPI_PAGE                (0x09)
+#define CPM_CR_I2C_PAGE                (0x0a)
+#define CPM_CR_TIMER_PAGE      (0x0a)
+#define CPM_CR_RAND_PAGE       (0x0a)
+#define CPM_CR_FCC1_PAGE       (0x04)
+#define CPM_CR_FCC2_PAGE       (0x05)
+#define CPM_CR_FCC3_PAGE       (0x06)
+#define CPM_CR_IDMA1_PAGE      (0x07)
+#define CPM_CR_IDMA2_PAGE      (0x08)
+#define CPM_CR_IDMA3_PAGE      (0x09)
+#define CPM_CR_IDMA4_PAGE      (0x0a)
+#define CPM_CR_MCC1_PAGE       (0x07)
+#define CPM_CR_MCC2_PAGE       (0x08)
+
+/* Some opcodes (there are more...later)
+*/
+#define CPM_CR_INIT_TRX                ((ushort)0x0000)
+#define CPM_CR_INIT_RX         ((ushort)0x0001)
+#define CPM_CR_INIT_TX         ((ushort)0x0002)
+#define CPM_CR_HUNT_MODE       ((ushort)0x0003)
+#define CPM_CR_STOP_TX         ((ushort)0x0004)
+#define CPM_CR_RESTART_TX      ((ushort)0x0006)
+#define CPM_CR_SET_GADDR       ((ushort)0x0008)
+#define CPM_CR_START_IDMA      ((ushort)0x0009)
+#define CPM_CR_STOP_IDMA       ((ushort)0x000b)
+
+#define mk_cr_cmd(PG, SBC, MCN, OP) \
+       ((PG << 26) | (SBC << 21) | (MCN << 6) | OP)
+
+/* Dual Port RAM addresses.  The first 16K is available for almost
+ * any CPM use, so we put the BDs there.  The first 128 bytes are
+ * used for SMC1 and SMC2 parameter RAM, so we start allocating
+ * BDs above that.  All of this must change when we start
+ * downloading RAM microcode.
+ */
+#define CPM_DATAONLY_BASE      ((uint)128)
+#define CPM_DP_NOSPACE         ((uint)0x7fffffff)
+#ifdef CONFIG_8272
+#define CPM_DATAONLY_SIZE      ((uint)(8 * 1024) - CPM_DATAONLY_BASE)
+#define CPM_FCC_SPECIAL_BASE   ((uint)0x00009000)
+#else
+#define CPM_DATAONLY_SIZE      ((uint)(16 * 1024) - CPM_DATAONLY_BASE)
+#define CPM_FCC_SPECIAL_BASE   ((uint)0x0000b000)
+#endif
+
+/* The number of pages of host memory we allocate for CPM.  This is
+ * done early in kernel initialization to get physically contiguous
+ * pages.
+ */
+#define NUM_CPM_HOST_PAGES     2
+
+static inline long IS_DPERR(const uint offset)
+{
+       return (uint)offset > (uint)-1000L;
+}
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern         cpm_cpm2_t      *cpmp;   /* Pointer to comm processor */
+extern uint cpm_dpalloc(uint size, uint align);
+extern int cpm_dpfree(uint offset);
+extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
+extern void cpm_dpdump(void);
+extern void *cpm_dpram_addr(uint offset);
+extern void cpm_setbrg(uint brg, uint rate);
+extern void cpm2_fastbrg(uint brg, uint rate, int div16);
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+       ushort  cbd_sc;         /* Status and Control */
+       ushort  cbd_datlen;     /* Data length in buffer */
+       uint    cbd_bufaddr;    /* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY    ((ushort)0x8000)        /* Receive is empty */
+#define BD_SC_READY    ((ushort)0x8000)        /* Transmit is ready */
+#define BD_SC_WRAP     ((ushort)0x2000)        /* Last buffer descriptor */
+#define BD_SC_INTRPT   ((ushort)0x1000)        /* Interrupt on change */
+#define BD_SC_LAST     ((ushort)0x0800)        /* Last buffer in frame */
+#define BD_SC_CM       ((ushort)0x0200)        /* Continous mode */
+#define BD_SC_ID       ((ushort)0x0100)        /* Rec'd too many idles */
+#define BD_SC_P                ((ushort)0x0100)        /* xmt preamble */
+#define BD_SC_BR       ((ushort)0x0020)        /* Break received */
+#define BD_SC_FR       ((ushort)0x0010)        /* Framing error */
+#define BD_SC_PR       ((ushort)0x0008)        /* Parity error */
+#define BD_SC_OV       ((ushort)0x0002)        /* Overrun */
+#define BD_SC_CD       ((ushort)0x0001)        /* ?? */
+
+/* Function code bits, usually generic to devices.
+*/
+#define CPMFCR_GBL     ((u_char)0x20)  /* Set memory snooping */
+#define CPMFCR_EB      ((u_char)0x10)  /* Set big endian byte order */
+#define CPMFCR_TC2     ((u_char)0x04)  /* Transfer code 2 value */
+#define CPMFCR_DTB     ((u_char)0x02)  /* Use local bus for data when set */
+#define CPMFCR_BDB     ((u_char)0x01)  /* Use local bus for BD when set */
+
+/* Parameter RAM offsets from the base.
+*/
+#define PROFF_SCC1             ((uint)0x8000)
+#define PROFF_SCC2             ((uint)0x8100)
+#define PROFF_SCC3             ((uint)0x8200)
+#define PROFF_SCC4             ((uint)0x8300)
+#define PROFF_FCC1             ((uint)0x8400)
+#define PROFF_FCC2             ((uint)0x8500)
+#define PROFF_FCC3             ((uint)0x8600)
+#define PROFF_MCC1             ((uint)0x8700)
+#define PROFF_SMC1_BASE                ((uint)0x87fc)
+#define PROFF_IDMA1_BASE       ((uint)0x87fe)
+#define PROFF_MCC2             ((uint)0x8800)
+#define PROFF_SMC2_BASE                ((uint)0x88fc)
+#define PROFF_IDMA2_BASE       ((uint)0x88fe)
+#define PROFF_SPI_BASE         ((uint)0x89fc)
+#define PROFF_IDMA3_BASE       ((uint)0x89fe)
+#define PROFF_TIMERS           ((uint)0x8ae0)
+#define PROFF_REVNUM           ((uint)0x8af0)
+#define PROFF_RAND             ((uint)0x8af8)
+#define PROFF_I2C_BASE         ((uint)0x8afc)
+#define PROFF_IDMA4_BASE       ((uint)0x8afe)
+
+/* The SMCs are relocated to any of the first eight DPRAM pages.
+ * We will fix these at the first locations of DPRAM, until we
+ * get some microcode patches :-).
+ * The parameter ram space for the SMCs is fifty-some bytes, and
+ * they are required to start on a 64 byte boundary.
+ */
+#define PROFF_SMC1     (0)
+#define PROFF_SMC2     (64)
+
+
+/* Define enough so I can at least use the serial port as a UART.
+ */
+typedef struct smc_uart {
+       ushort  smc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  smc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  smc_rfcr;       /* Rx function code */
+       u_char  smc_tfcr;       /* Tx function code */
+       ushort  smc_mrblr;      /* Max receive buffer length */
+       uint    smc_rstate;     /* Internal */
+       uint    smc_idp;        /* Internal */
+       ushort  smc_rbptr;      /* Internal */
+       ushort  smc_ibc;        /* Internal */
+       uint    smc_rxtmp;      /* Internal */
+       uint    smc_tstate;     /* Internal */
+       uint    smc_tdp;        /* Internal */
+       ushort  smc_tbptr;      /* Internal */
+       ushort  smc_tbc;        /* Internal */
+       uint    smc_txtmp;      /* Internal */
+       ushort  smc_maxidl;     /* Maximum idle characters */
+       ushort  smc_tmpidl;     /* Temporary idle counter */
+       ushort  smc_brklen;     /* Last received break length */
+       ushort  smc_brkec;      /* rcv'd break condition counter */
+       ushort  smc_brkcr;      /* xmt break count register */
+       ushort  smc_rmask;      /* Temporary bit mask */
+       uint    smc_stmp;       /* SDMA Temp */
+} smc_uart_t;
+
+/* SMC uart mode register (Internal memory map).
+*/
+#define SMCMR_REN      ((ushort)0x0001)
+#define SMCMR_TEN      ((ushort)0x0002)
+#define SMCMR_DM       ((ushort)0x000c)
+#define SMCMR_SM_GCI   ((ushort)0x0000)
+#define SMCMR_SM_UART  ((ushort)0x0020)
+#define SMCMR_SM_TRANS ((ushort)0x0030)
+#define SMCMR_SM_MASK  ((ushort)0x0030)
+#define SMCMR_PM_EVEN  ((ushort)0x0100)        /* Even parity, else odd */
+#define SMCMR_REVD     SMCMR_PM_EVEN
+#define SMCMR_PEN      ((ushort)0x0200)        /* Parity enable */
+#define SMCMR_BS       SMCMR_PEN
+#define SMCMR_SL       ((ushort)0x0400)        /* Two stops, else one */
+#define SMCR_CLEN_MASK ((ushort)0x7800)        /* Character length */
+#define smcr_mk_clen(C)        (((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC Event and Mask register.
+*/
+#define SMCM_BRKE       ((unsigned char)0x40)   /* When in UART Mode */
+#define SMCM_BRK        ((unsigned char)0x10)   /* When in UART Mode */
+#define SMCM_TXE       ((unsigned char)0x10)
+#define SMCM_BSY       ((unsigned char)0x04)
+#define SMCM_TX                ((unsigned char)0x02)
+#define SMCM_RX                ((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST            ((uint)0x00020000)
+#define CPM_BRG_EN             ((uint)0x00010000)
+#define CPM_BRG_EXTC_INT       ((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK3_9    ((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK5_15   ((uint)0x00008000)
+#define CPM_BRG_ATB            ((uint)0x00002000)
+#define CPM_BRG_CD_MASK                ((uint)0x00001ffe)
+#define CPM_BRG_DIV16          ((uint)0x00000001)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP          ((uint)0x00040000)
+#define SCC_GSMRH_GDE          ((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT   ((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC  ((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC    ((uint)0x00000000)
+#define SCC_GSMRH_REVD         ((uint)0x00002000)
+#define SCC_GSMRH_TRX          ((uint)0x00001000)
+#define SCC_GSMRH_TTX          ((uint)0x00000800)
+#define SCC_GSMRH_CDP          ((uint)0x00000400)
+#define SCC_GSMRH_CTSP         ((uint)0x00000200)
+#define SCC_GSMRH_CDS          ((uint)0x00000100)
+#define SCC_GSMRH_CTSS         ((uint)0x00000080)
+#define SCC_GSMRH_TFL          ((uint)0x00000040)
+#define SCC_GSMRH_RFW          ((uint)0x00000020)
+#define SCC_GSMRH_TXSY         ((uint)0x00000010)
+#define SCC_GSMRH_SYNL16       ((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8                ((uint)0x00000008)
+#define SCC_GSMRH_SYNL4                ((uint)0x00000004)
+#define SCC_GSMRH_RTSM         ((uint)0x00000002)
+#define SCC_GSMRH_RSYN         ((uint)0x00000001)
+
+#define SCC_GSMRL_SIR          ((uint)0x80000000)      /* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE    ((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG     ((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS     ((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH    ((uint)0x00000000)
+#define SCC_GSMRL_TCI          ((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3       ((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4       ((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14      ((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF     ((uint)0x00000000)
+#define SCC_GSMRL_RINV         ((uint)0x02000000)
+#define SCC_GSMRL_TINV         ((uint)0x01000000)
+#define SCC_GSMRL_TPL_128      ((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64       ((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48       ((uint)0x00800000)
+#define SCC_GSMRL_TPL_32       ((uint)0x00600000)
+#define SCC_GSMRL_TPL_16       ((uint)0x00400000)
+#define SCC_GSMRL_TPL_8                ((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE     ((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1     ((uint)0x00180000)
+#define SCC_GSMRL_TPP_01       ((uint)0x00100000)
+#define SCC_GSMRL_TPP_10       ((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS    ((uint)0x00000000)
+#define SCC_GSMRL_TEND         ((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32      ((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16      ((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8       ((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32      ((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16      ((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8       ((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN   ((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH   ((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0     ((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI    ((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN   ((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH   ((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0     ((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI    ((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE      ((uint)0x000000c0)      /* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO    ((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP    ((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM    ((uint)0x00000000)
+#define SCC_GSMRL_ENR          ((uint)0x00000020)
+#define SCC_GSMRL_ENT          ((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET    ((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP   ((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC  ((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14     ((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC   ((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS        ((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART    ((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7     ((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK   ((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC    ((uint)0x00000000)
+
+#define SCC_TODR_TOD           ((ushort)0x8000)
+
+/* SCC Event and Mask register.
+*/
+#define SCCM_TXE       ((unsigned char)0x10)
+#define SCCM_BSY       ((unsigned char)0x04)
+#define SCCM_TX                ((unsigned char)0x02)
+#define SCCM_RX                ((unsigned char)0x01)
+
+typedef struct scc_param {
+       ushort  scc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  scc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  scc_rfcr;       /* Rx function code */
+       u_char  scc_tfcr;       /* Tx function code */
+       ushort  scc_mrblr;      /* Max receive buffer length */
+       uint    scc_rstate;     /* Internal */
+       uint    scc_idp;        /* Internal */
+       ushort  scc_rbptr;      /* Internal */
+       ushort  scc_ibc;        /* Internal */
+       uint    scc_rxtmp;      /* Internal */
+       uint    scc_tstate;     /* Internal */
+       uint    scc_tdp;        /* Internal */
+       ushort  scc_tbptr;      /* Internal */
+       ushort  scc_tbc;        /* Internal */
+       uint    scc_txtmp;      /* Internal */
+       uint    scc_rcrc;       /* Internal */
+       uint    scc_tcrc;       /* Internal */
+} sccp_t;
+
+/* CPM Ethernet through SCC1.
+ */
+typedef struct scc_enet {
+       sccp_t  sen_genscc;
+       uint    sen_cpres;      /* Preset CRC */
+       uint    sen_cmask;      /* Constant mask for CRC */
+       uint    sen_crcec;      /* CRC Error counter */
+       uint    sen_alec;       /* alignment error counter */
+       uint    sen_disfc;      /* discard frame counter */
+       ushort  sen_pads;       /* Tx short frame pad character */
+       ushort  sen_retlim;     /* Retry limit threshold */
+       ushort  sen_retcnt;     /* Retry limit counter */
+       ushort  sen_maxflr;     /* maximum frame length register */
+       ushort  sen_minflr;     /* minimum frame length register */
+       ushort  sen_maxd1;      /* maximum DMA1 length */
+       ushort  sen_maxd2;      /* maximum DMA2 length */
+       ushort  sen_maxd;       /* Rx max DMA */
+       ushort  sen_dmacnt;     /* Rx DMA counter */
+       ushort  sen_maxb;       /* Max BD byte count */
+       ushort  sen_gaddr1;     /* Group address filter */
+       ushort  sen_gaddr2;
+       ushort  sen_gaddr3;
+       ushort  sen_gaddr4;
+       uint    sen_tbuf0data0; /* Save area 0 - current frame */
+       uint    sen_tbuf0data1; /* Save area 1 - current frame */
+       uint    sen_tbuf0rba;   /* Internal */
+       uint    sen_tbuf0crc;   /* Internal */
+       ushort  sen_tbuf0bcnt;  /* Internal */
+       ushort  sen_paddrh;     /* physical address (MSB) */
+       ushort  sen_paddrm;
+       ushort  sen_paddrl;     /* physical address (LSB) */
+       ushort  sen_pper;       /* persistence */
+       ushort  sen_rfbdptr;    /* Rx first BD pointer */
+       ushort  sen_tfbdptr;    /* Tx first BD pointer */
+       ushort  sen_tlbdptr;    /* Tx last BD pointer */
+       uint    sen_tbuf1data0; /* Save area 0 - current frame */
+       uint    sen_tbuf1data1; /* Save area 1 - current frame */
+       uint    sen_tbuf1rba;   /* Internal */
+       uint    sen_tbuf1crc;   /* Internal */
+       ushort  sen_tbuf1bcnt;  /* Internal */
+       ushort  sen_txlen;      /* Tx Frame length counter */
+       ushort  sen_iaddr1;     /* Individual address filter */
+       ushort  sen_iaddr2;
+       ushort  sen_iaddr3;
+       ushort  sen_iaddr4;
+       ushort  sen_boffcnt;    /* Backoff counter */
+
+       /* NOTE: Some versions of the manual have the following items
+        * incorrectly documented.  Below is the proper order.
+        */
+       ushort  sen_taddrh;     /* temp address (MSB) */
+       ushort  sen_taddrm;
+       ushort  sen_taddrl;     /* temp address (LSB) */
+} scc_enet_t;
+
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA  ((ushort)0x0080)        /* Graceful stop complete */
+#define SCCE_ENET_TXE  ((ushort)0x0010)        /* Transmit Error */
+#define SCCE_ENET_RXF  ((ushort)0x0008)        /* Full frame received */
+#define SCCE_ENET_BSY  ((ushort)0x0004)        /* All incoming buffers full */
+#define SCCE_ENET_TXB  ((ushort)0x0002)        /* A buffer was transmitted */
+#define SCCE_ENET_RXB  ((ushort)0x0001)        /* A buffer was received */
+
+/* SCC Mode Register (PSMR) as used by Ethernet.
+*/
+#define SCC_PSMR_HBC   ((ushort)0x8000)        /* Enable heartbeat */
+#define SCC_PSMR_FC    ((ushort)0x4000)        /* Force collision */
+#define SCC_PSMR_RSH   ((ushort)0x2000)        /* Receive short frames */
+#define SCC_PSMR_IAM   ((ushort)0x1000)        /* Check individual hash */
+#define SCC_PSMR_ENCRC ((ushort)0x0800)        /* Ethernet CRC mode */
+#define SCC_PSMR_PRO   ((ushort)0x0200)        /* Promiscuous mode */
+#define SCC_PSMR_BRO   ((ushort)0x0100)        /* Catch broadcast pkts */
+#define SCC_PSMR_SBT   ((ushort)0x0080)        /* Special backoff timer */
+#define SCC_PSMR_LPB   ((ushort)0x0040)        /* Set Loopback mode */
+#define SCC_PSMR_SIP   ((ushort)0x0020)        /* Sample Input Pins */
+#define SCC_PSMR_LCW   ((ushort)0x0010)        /* Late collision window */
+#define SCC_PSMR_NIB22 ((ushort)0x000a)        /* Start frame search */
+#define SCC_PSMR_FDE   ((ushort)0x0001)        /* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+ * Common to SCC and FCC.
+ */
+#define BD_ENET_RX_EMPTY       ((ushort)0x8000)
+#define BD_ENET_RX_WRAP                ((ushort)0x2000)
+#define BD_ENET_RX_INTR                ((ushort)0x1000)
+#define BD_ENET_RX_LAST                ((ushort)0x0800)
+#define BD_ENET_RX_FIRST       ((ushort)0x0400)
+#define BD_ENET_RX_MISS                ((ushort)0x0100)
+#define BD_ENET_RX_BC          ((ushort)0x0080)        /* FCC Only */
+#define BD_ENET_RX_MC          ((ushort)0x0040)        /* FCC Only */
+#define BD_ENET_RX_LG          ((ushort)0x0020)
+#define BD_ENET_RX_NO          ((ushort)0x0010)
+#define BD_ENET_RX_SH          ((ushort)0x0008)
+#define BD_ENET_RX_CR          ((ushort)0x0004)
+#define BD_ENET_RX_OV          ((ushort)0x0002)
+#define BD_ENET_RX_CL          ((ushort)0x0001)
+#define BD_ENET_RX_STATS       ((ushort)0x01ff)        /* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+ * Common to SCC and FCC.
+ */
+#define BD_ENET_TX_READY       ((ushort)0x8000)
+#define BD_ENET_TX_PAD         ((ushort)0x4000)
+#define BD_ENET_TX_WRAP                ((ushort)0x2000)
+#define BD_ENET_TX_INTR                ((ushort)0x1000)
+#define BD_ENET_TX_LAST                ((ushort)0x0800)
+#define BD_ENET_TX_TC          ((ushort)0x0400)
+#define BD_ENET_TX_DEF         ((ushort)0x0200)
+#define BD_ENET_TX_HB          ((ushort)0x0100)
+#define BD_ENET_TX_LC          ((ushort)0x0080)
+#define BD_ENET_TX_RL          ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK      ((ushort)0x003c)
+#define BD_ENET_TX_UN          ((ushort)0x0002)
+#define BD_ENET_TX_CSL         ((ushort)0x0001)
+#define BD_ENET_TX_STATS       ((ushort)0x03ff)        /* All status bits */
+
+/* SCC as UART
+*/
+typedef struct scc_uart {
+       sccp_t  scc_genscc;
+       uint    scc_res1;       /* Reserved */
+       uint    scc_res2;       /* Reserved */
+       ushort  scc_maxidl;     /* Maximum idle chars */
+       ushort  scc_idlc;       /* temp idle counter */
+       ushort  scc_brkcr;      /* Break count register */
+       ushort  scc_parec;      /* receive parity error counter */
+       ushort  scc_frmec;      /* receive framing error counter */
+       ushort  scc_nosec;      /* receive noise counter */
+       ushort  scc_brkec;      /* receive break condition counter */
+       ushort  scc_brkln;      /* last received break length */
+       ushort  scc_uaddr1;     /* UART address character 1 */
+       ushort  scc_uaddr2;     /* UART address character 2 */
+       ushort  scc_rtemp;      /* Temp storage */
+       ushort  scc_toseq;      /* Transmit out of sequence char */
+       ushort  scc_char1;      /* control character 1 */
+       ushort  scc_char2;      /* control character 2 */
+       ushort  scc_char3;      /* control character 3 */
+       ushort  scc_char4;      /* control character 4 */
+       ushort  scc_char5;      /* control character 5 */
+       ushort  scc_char6;      /* control character 6 */
+       ushort  scc_char7;      /* control character 7 */
+       ushort  scc_char8;      /* control character 8 */
+       ushort  scc_rccm;       /* receive control character mask */
+       ushort  scc_rccr;       /* receive control character register */
+       ushort  scc_rlbc;       /* receive last break character */
+} scc_uart_t;
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR          ((ushort)0x1000)
+#define UART_SCCM_GLT          ((ushort)0x0800)
+#define UART_SCCM_AB           ((ushort)0x0200)
+#define UART_SCCM_IDL          ((ushort)0x0100)
+#define UART_SCCM_GRA          ((ushort)0x0080)
+#define UART_SCCM_BRKE         ((ushort)0x0040)
+#define UART_SCCM_BRKS         ((ushort)0x0020)
+#define UART_SCCM_CCR          ((ushort)0x0008)
+#define UART_SCCM_BSY          ((ushort)0x0004)
+#define UART_SCCM_TX           ((ushort)0x0002)
+#define UART_SCCM_RX           ((ushort)0x0001)
+
+/* The SCC PSMR when used as a UART.
+*/
+#define SCU_PSMR_FLC           ((ushort)0x8000)
+#define SCU_PSMR_SL            ((ushort)0x4000)
+#define SCU_PSMR_CL            ((ushort)0x3000)
+#define SCU_PSMR_UM            ((ushort)0x0c00)
+#define SCU_PSMR_FRZ           ((ushort)0x0200)
+#define SCU_PSMR_RZS           ((ushort)0x0100)
+#define SCU_PSMR_SYN           ((ushort)0x0080)
+#define SCU_PSMR_DRT           ((ushort)0x0040)
+#define SCU_PSMR_PEN           ((ushort)0x0010)
+#define SCU_PSMR_RPM           ((ushort)0x000c)
+#define SCU_PSMR_REVP          ((ushort)0x0008)
+#define SCU_PSMR_TPM           ((ushort)0x0003)
+#define SCU_PSMR_TEVP          ((ushort)0x0003)
+
+/* CPM Transparent mode SCC.
+ */
+typedef struct scc_trans {
+       sccp_t  st_genscc;
+       uint    st_cpres;       /* Preset CRC */
+       uint    st_cmask;       /* Constant mask for CRC */
+} scc_trans_t;
+
+#define BD_SCC_TX_LAST         ((ushort)0x0800)
+
+/* How about some FCCs.....
+*/
+#define FCC_GFMR_DIAG_NORM     ((uint)0x00000000)
+#define FCC_GFMR_DIAG_LE       ((uint)0x40000000)
+#define FCC_GFMR_DIAG_AE       ((uint)0x80000000)
+#define FCC_GFMR_DIAG_ALE      ((uint)0xc0000000)
+#define FCC_GFMR_TCI           ((uint)0x20000000)
+#define FCC_GFMR_TRX           ((uint)0x10000000)
+#define FCC_GFMR_TTX           ((uint)0x08000000)
+#define FCC_GFMR_TTX           ((uint)0x08000000)
+#define FCC_GFMR_CDP           ((uint)0x04000000)
+#define FCC_GFMR_CTSP          ((uint)0x02000000)
+#define FCC_GFMR_CDS           ((uint)0x01000000)
+#define FCC_GFMR_CTSS          ((uint)0x00800000)
+#define FCC_GFMR_SYNL_NONE     ((uint)0x00000000)
+#define FCC_GFMR_SYNL_AUTO     ((uint)0x00004000)
+#define FCC_GFMR_SYNL_8                ((uint)0x00008000)
+#define FCC_GFMR_SYNL_16       ((uint)0x0000c000)
+#define FCC_GFMR_RTSM          ((uint)0x00002000)
+#define FCC_GFMR_RENC_NRZ      ((uint)0x00000000)
+#define FCC_GFMR_RENC_NRZI     ((uint)0x00000800)
+#define FCC_GFMR_REVD          ((uint)0x00000400)
+#define FCC_GFMR_TENC_NRZ      ((uint)0x00000000)
+#define FCC_GFMR_TENC_NRZI     ((uint)0x00000100)
+#define FCC_GFMR_TCRC_16       ((uint)0x00000000)
+#define FCC_GFMR_TCRC_32       ((uint)0x00000080)
+#define FCC_GFMR_ENR           ((uint)0x00000020)
+#define FCC_GFMR_ENT           ((uint)0x00000010)
+#define FCC_GFMR_MODE_ENET     ((uint)0x0000000c)
+#define FCC_GFMR_MODE_ATM      ((uint)0x0000000a)
+#define FCC_GFMR_MODE_HDLC     ((uint)0x00000000)
+
+/* Generic FCC parameter ram.
+*/
+typedef struct fcc_param {
+       ushort  fcc_riptr;      /* Rx Internal temp pointer */
+       ushort  fcc_tiptr;      /* Tx Internal temp pointer */
+       ushort  fcc_res1;
+       ushort  fcc_mrblr;      /* Max receive buffer length, mod 32 bytes */
+       uint    fcc_rstate;     /* Upper byte is Func code, must be set */
+       uint    fcc_rbase;      /* Receive BD base */
+       ushort  fcc_rbdstat;    /* RxBD status */
+       ushort  fcc_rbdlen;     /* RxBD down counter */
+       uint    fcc_rdptr;      /* RxBD internal data pointer */
+       uint    fcc_tstate;     /* Upper byte is Func code, must be set */
+       uint    fcc_tbase;      /* Transmit BD base */
+       ushort  fcc_tbdstat;    /* TxBD status */
+       ushort  fcc_tbdlen;     /* TxBD down counter */
+       uint    fcc_tdptr;      /* TxBD internal data pointer */
+       uint    fcc_rbptr;      /* Rx BD Internal buf pointer */
+       uint    fcc_tbptr;      /* Tx BD Internal buf pointer */
+       uint    fcc_rcrc;       /* Rx temp CRC */
+       uint    fcc_res2;
+       uint    fcc_tcrc;       /* Tx temp CRC */
+} fccp_t;
+
+
+/* Ethernet controller through FCC.
+*/
+typedef struct fcc_enet {
+       fccp_t  fen_genfcc;
+       uint    fen_statbuf;    /* Internal status buffer */
+       uint    fen_camptr;     /* CAM address */
+       uint    fen_cmask;      /* Constant mask for CRC */
+       uint    fen_cpres;      /* Preset CRC */
+       uint    fen_crcec;      /* CRC Error counter */
+       uint    fen_alec;       /* alignment error counter */
+       uint    fen_disfc;      /* discard frame counter */
+       ushort  fen_retlim;     /* Retry limit */
+       ushort  fen_retcnt;     /* Retry counter */
+       ushort  fen_pper;       /* Persistence */
+       ushort  fen_boffcnt;    /* backoff counter */
+       uint    fen_gaddrh;     /* Group address filter, high 32-bits */
+       uint    fen_gaddrl;     /* Group address filter, low 32-bits */
+       ushort  fen_tfcstat;    /* out of sequence TxBD */
+       ushort  fen_tfclen;
+       uint    fen_tfcptr;
+       ushort  fen_mflr;       /* Maximum frame length (1518) */
+       ushort  fen_paddrh;     /* MAC address */
+       ushort  fen_paddrm;
+       ushort  fen_paddrl;
+       ushort  fen_ibdcount;   /* Internal BD counter */
+       ushort  fen_ibdstart;   /* Internal BD start pointer */
+       ushort  fen_ibdend;     /* Internal BD end pointer */
+       ushort  fen_txlen;      /* Internal Tx frame length counter */
+       uint    fen_ibdbase[8]; /* Internal use */
+       uint    fen_iaddrh;     /* Individual address filter */
+       uint    fen_iaddrl;
+       ushort  fen_minflr;     /* Minimum frame length (64) */
+       ushort  fen_taddrh;     /* Filter transfer MAC address */
+       ushort  fen_taddrm;
+       ushort  fen_taddrl;
+       ushort  fen_padptr;     /* Pointer to pad byte buffer */
+       ushort  fen_cftype;     /* control frame type */
+       ushort  fen_cfrange;    /* control frame range */
+       ushort  fen_maxb;       /* maximum BD count */
+       ushort  fen_maxd1;      /* Max DMA1 length (1520) */
+       ushort  fen_maxd2;      /* Max DMA2 length (1520) */
+       ushort  fen_maxd;       /* internal max DMA count */
+       ushort  fen_dmacnt;     /* internal DMA counter */
+       uint    fen_octc;       /* Total octect counter */
+       uint    fen_colc;       /* Total collision counter */
+       uint    fen_broc;       /* Total broadcast packet counter */
+       uint    fen_mulc;       /* Total multicast packet count */
+       uint    fen_uspc;       /* Total packets < 64 bytes */
+       uint    fen_frgc;       /* Total packets < 64 bytes with errors */
+       uint    fen_ospc;       /* Total packets > 1518 */
+       uint    fen_jbrc;       /* Total packets > 1518 with errors */
+       uint    fen_p64c;       /* Total packets == 64 bytes */
+       uint    fen_p65c;       /* Total packets 64 < bytes <= 127 */
+       uint    fen_p128c;      /* Total packets 127 < bytes <= 255 */
+       uint    fen_p256c;      /* Total packets 256 < bytes <= 511 */
+       uint    fen_p512c;      /* Total packets 512 < bytes <= 1023 */
+       uint    fen_p1024c;     /* Total packets 1024 < bytes <= 1518 */
+       uint    fen_cambuf;     /* Internal CAM buffer poiner */
+       ushort  fen_rfthr;      /* Received frames threshold */
+       ushort  fen_rfcnt;      /* Received frames count */
+} fcc_enet_t;
+
+/* FCC Event/Mask register as used by Ethernet.
+*/
+#define FCC_ENET_GRA   ((ushort)0x0080)        /* Graceful stop complete */
+#define FCC_ENET_RXC   ((ushort)0x0040)        /* Control Frame Received */
+#define FCC_ENET_TXC   ((ushort)0x0020)        /* Out of seq. Tx sent */
+#define FCC_ENET_TXE   ((ushort)0x0010)        /* Transmit Error */
+#define FCC_ENET_RXF   ((ushort)0x0008)        /* Full frame received */
+#define FCC_ENET_BSY   ((ushort)0x0004)        /* Busy.  Rx Frame dropped */
+#define FCC_ENET_TXB   ((ushort)0x0002)        /* A buffer was transmitted */
+#define FCC_ENET_RXB   ((ushort)0x0001)        /* A buffer was received */
+
+/* FCC Mode Register (FPSMR) as used by Ethernet.
+*/
+#define FCC_PSMR_HBC   ((uint)0x80000000)      /* Enable heartbeat */
+#define FCC_PSMR_FC    ((uint)0x40000000)      /* Force Collision */
+#define FCC_PSMR_SBT   ((uint)0x20000000)      /* Stop backoff timer */
+#define FCC_PSMR_LPB   ((uint)0x10000000)      /* Local protect. 1 = FDX */
+#define FCC_PSMR_LCW   ((uint)0x08000000)      /* Late collision select */
+#define FCC_PSMR_FDE   ((uint)0x04000000)      /* Full Duplex Enable */
+#define FCC_PSMR_MON   ((uint)0x02000000)      /* RMON Enable */
+#define FCC_PSMR_PRO   ((uint)0x00400000)      /* Promiscuous Enable */
+#define FCC_PSMR_FCE   ((uint)0x00200000)      /* Flow Control Enable */
+#define FCC_PSMR_RSH   ((uint)0x00100000)      /* Receive Short Frames */
+#define FCC_PSMR_CAM   ((uint)0x00000400)      /* CAM enable */
+#define FCC_PSMR_BRO   ((uint)0x00000200)      /* Broadcast pkt discard */
+#define FCC_PSMR_ENCRC ((uint)0x00000080)      /* Use 32-bit CRC */
+
+/* IIC parameter RAM.
+*/
+typedef struct iic {
+       ushort  iic_rbase;      /* Rx Buffer descriptor base address */
+       ushort  iic_tbase;      /* Tx Buffer descriptor base address */
+       u_char  iic_rfcr;       /* Rx function code */
+       u_char  iic_tfcr;       /* Tx function code */
+       ushort  iic_mrblr;      /* Max receive buffer length */
+       uint    iic_rstate;     /* Internal */
+       uint    iic_rdp;        /* Internal */
+       ushort  iic_rbptr;      /* Internal */
+       ushort  iic_rbc;        /* Internal */
+       uint    iic_rxtmp;      /* Internal */
+       uint    iic_tstate;     /* Internal */
+       uint    iic_tdp;        /* Internal */
+       ushort  iic_tbptr;      /* Internal */
+       ushort  iic_tbc;        /* Internal */
+       uint    iic_txtmp;      /* Internal */
+} iic_t;
+
+/* SPI parameter RAM.
+*/
+typedef struct spi {
+       ushort  spi_rbase;      /* Rx Buffer descriptor base address */
+       ushort  spi_tbase;      /* Tx Buffer descriptor base address */
+       u_char  spi_rfcr;       /* Rx function code */
+       u_char  spi_tfcr;       /* Tx function code */
+       ushort  spi_mrblr;      /* Max receive buffer length */
+       uint    spi_rstate;     /* Internal */
+       uint    spi_rdp;        /* Internal */
+       ushort  spi_rbptr;      /* Internal */
+       ushort  spi_rbc;        /* Internal */
+       uint    spi_rxtmp;      /* Internal */
+       uint    spi_tstate;     /* Internal */
+       uint    spi_tdp;        /* Internal */
+       ushort  spi_tbptr;      /* Internal */
+       ushort  spi_tbc;        /* Internal */
+       uint    spi_txtmp;      /* Internal */
+       uint    spi_res;        /* Tx temp. */
+       uint    spi_res1[4];    /* SDMA temp. */
+} spi_t;
+
+/* SPI Mode register.
+*/
+#define SPMODE_LOOP    ((ushort)0x4000)        /* Loopback */
+#define SPMODE_CI      ((ushort)0x2000)        /* Clock Invert */
+#define SPMODE_CP      ((ushort)0x1000)        /* Clock Phase */
+#define SPMODE_DIV16   ((ushort)0x0800)        /* BRG/16 mode */
+#define SPMODE_REV     ((ushort)0x0400)        /* Reversed Data */
+#define SPMODE_MSTR    ((ushort)0x0200)        /* SPI Master */
+#define SPMODE_EN      ((ushort)0x0100)        /* Enable */
+#define SPMODE_LENMSK  ((ushort)0x00f0)        /* character length */
+#define SPMODE_PMMSK   ((ushort)0x000f)        /* prescale modulus */
+
+#define SPMODE_LEN(x)  ((((x)-1)&0xF)<<4)
+#define SPMODE_PM(x)   ((x) &0xF)
+
+#define SPI_EB         ((u_char)0x10)          /* big endian byte order */
+
+#define BD_IIC_START           ((ushort)0x0400)
+
+/* IDMA parameter RAM
+*/
+typedef struct idma {
+       ushort ibase;           /* IDMA buffer descriptor table base address */
+       ushort dcm;             /* DMA channel mode */
+       ushort ibdptr;          /* IDMA current buffer descriptor pointer */
+       ushort dpr_buf;         /* IDMA transfer buffer base address */
+       ushort buf_inv;         /* internal buffer inventory */
+       ushort ss_max;          /* steady-state maximum transfer size */
+       ushort dpr_in_ptr;      /* write pointer inside the internal buffer */
+       ushort sts;             /* source transfer size */
+       ushort dpr_out_ptr;     /* read pointer inside the internal buffer */
+       ushort seob;            /* source end of burst */
+       ushort deob;            /* destination end of burst */
+       ushort dts;             /* destination transfer size */
+       ushort ret_add;         /* return address when working in ERM=1 mode */
+       ushort res0;            /* reserved */
+       uint   bd_cnt;          /* internal byte count */
+       uint   s_ptr;           /* source internal data pointer */
+       uint   d_ptr;           /* destination internal data pointer */
+       uint   istate;          /* internal state */
+       u_char res1[20];        /* pad to 64-byte length */
+} idma_t;
+
+/* DMA channel mode bit fields
+*/
+#define IDMA_DCM_FB            ((ushort)0x8000) /* fly-by mode */
+#define IDMA_DCM_LP            ((ushort)0x4000) /* low priority */
+#define IDMA_DCM_TC2           ((ushort)0x0400) /* value driven on TC[2] */
+#define IDMA_DCM_DMA_WRAP_MASK ((ushort)0x01c0) /* mask for DMA wrap */
+#define IDMA_DCM_DMA_WRAP_64   ((ushort)0x0000) /* 64-byte DMA xfer buffer */
+#define IDMA_DCM_DMA_WRAP_128  ((ushort)0x0040) /* 128-byte DMA xfer buffer */
+#define IDMA_DCM_DMA_WRAP_256  ((ushort)0x0080) /* 256-byte DMA xfer buffer */
+#define IDMA_DCM_DMA_WRAP_512  ((ushort)0x00c0) /* 512-byte DMA xfer buffer */
+#define IDMA_DCM_DMA_WRAP_1024 ((ushort)0x0100) /* 1024-byte DMA xfer buffer */
+#define IDMA_DCM_DMA_WRAP_2048 ((ushort)0x0140) /* 2048-byte DMA xfer buffer */
+#define IDMA_DCM_SINC          ((ushort)0x0020) /* source inc addr */
+#define IDMA_DCM_DINC          ((ushort)0x0010) /* destination inc addr */
+#define IDMA_DCM_ERM           ((ushort)0x0008) /* external request mode */
+#define IDMA_DCM_DT            ((ushort)0x0004) /* DONE treatment */
+#define IDMA_DCM_SD_MASK       ((ushort)0x0003) /* mask for SD bit field */
+#define IDMA_DCM_SD_MEM2MEM    ((ushort)0x0000) /* memory-to-memory xfer */
+#define IDMA_DCM_SD_PER2MEM    ((ushort)0x0002) /* peripheral-to-memory xfer */
+#define IDMA_DCM_SD_MEM2PER    ((ushort)0x0001) /* memory-to-peripheral xfer */
+
+/* IDMA Buffer Descriptors
+*/
+typedef struct idma_bd {
+       uint flags;
+       uint len;       /* data length */
+       uint src;       /* source data buffer pointer */
+       uint dst;       /* destination data buffer pointer */
+} idma_bd_t;
+
+/* IDMA buffer descriptor flag bit fields
+*/
+#define IDMA_BD_V      ((uint)0x80000000)      /* valid */
+#define IDMA_BD_W      ((uint)0x20000000)      /* wrap */
+#define IDMA_BD_I      ((uint)0x10000000)      /* interrupt */
+#define IDMA_BD_L      ((uint)0x08000000)      /* last */
+#define IDMA_BD_CM     ((uint)0x02000000)      /* continuous mode */
+#define IDMA_BD_SDN    ((uint)0x00400000)      /* source done */
+#define IDMA_BD_DDN    ((uint)0x00200000)      /* destination done */
+#define IDMA_BD_DGBL   ((uint)0x00100000)      /* destination global */
+#define IDMA_BD_DBO_LE ((uint)0x00040000)      /* little-end dest byte order */
+#define IDMA_BD_DBO_BE ((uint)0x00080000)      /* big-end dest byte order */
+#define IDMA_BD_DDTB   ((uint)0x00010000)      /* destination data bus */
+#define IDMA_BD_SGBL   ((uint)0x00002000)      /* source global */
+#define IDMA_BD_SBO_LE ((uint)0x00000800)      /* little-end src byte order */
+#define IDMA_BD_SBO_BE ((uint)0x00001000)      /* big-end src byte order */
+#define IDMA_BD_SDTB   ((uint)0x00000200)      /* source data bus */
+
+/* per-channel IDMA registers
+*/
+typedef struct im_idma {
+       u_char idsr;                    /* IDMAn event status register */
+       u_char res0[3];
+       u_char idmr;                    /* IDMAn event mask register */
+       u_char res1[3];
+} im_idma_t;
+
+/* IDMA event register bit fields
+*/
+#define IDMA_EVENT_SC  ((unsigned char)0x08)   /* stop completed */
+#define IDMA_EVENT_OB  ((unsigned char)0x04)   /* out of buffers */
+#define IDMA_EVENT_EDN ((unsigned char)0x02)   /* external DONE asserted */
+#define IDMA_EVENT_BC  ((unsigned char)0x01)   /* buffer descriptor complete */
+
+/* RISC Controller Configuration Register (RCCR) bit fields
+*/
+#define RCCR_TIME      ((uint)0x80000000) /* timer enable */
+#define RCCR_TIMEP_MASK        ((uint)0x3f000000) /* mask for timer period bit field */
+#define RCCR_DR0M      ((uint)0x00800000) /* IDMA0 request mode */
+#define RCCR_DR1M      ((uint)0x00400000) /* IDMA1 request mode */
+#define RCCR_DR2M      ((uint)0x00000080) /* IDMA2 request mode */
+#define RCCR_DR3M      ((uint)0x00000040) /* IDMA3 request mode */
+#define RCCR_DR0QP_MASK        ((uint)0x00300000) /* mask for IDMA0 req priority */
+#define RCCR_DR0QP_HIGH ((uint)0x00000000) /* IDMA0 has high req priority */
+#define RCCR_DR0QP_MED ((uint)0x00100000) /* IDMA0 has medium req priority */
+#define RCCR_DR0QP_LOW ((uint)0x00200000) /* IDMA0 has low req priority */
+#define RCCR_DR1QP_MASK        ((uint)0x00030000) /* mask for IDMA1 req priority */
+#define RCCR_DR1QP_HIGH ((uint)0x00000000) /* IDMA1 has high req priority */
+#define RCCR_DR1QP_MED ((uint)0x00010000) /* IDMA1 has medium req priority */
+#define RCCR_DR1QP_LOW ((uint)0x00020000) /* IDMA1 has low req priority */
+#define RCCR_DR2QP_MASK        ((uint)0x00000030) /* mask for IDMA2 req priority */
+#define RCCR_DR2QP_HIGH ((uint)0x00000000) /* IDMA2 has high req priority */
+#define RCCR_DR2QP_MED ((uint)0x00000010) /* IDMA2 has medium req priority */
+#define RCCR_DR2QP_LOW ((uint)0x00000020) /* IDMA2 has low req priority */
+#define RCCR_DR3QP_MASK        ((uint)0x00000003) /* mask for IDMA3 req priority */
+#define RCCR_DR3QP_HIGH ((uint)0x00000000) /* IDMA3 has high req priority */
+#define RCCR_DR3QP_MED ((uint)0x00000001) /* IDMA3 has medium req priority */
+#define RCCR_DR3QP_LOW ((uint)0x00000002) /* IDMA3 has low req priority */
+#define RCCR_EIE       ((uint)0x00080000) /* external interrupt enable */
+#define RCCR_SCD       ((uint)0x00040000) /* scheduler configuration */
+#define RCCR_ERAM_MASK ((uint)0x0000e000) /* mask for enable RAM microcode */
+#define RCCR_ERAM_0KB  ((uint)0x00000000) /* use 0KB of dpram for microcode */
+#define RCCR_ERAM_2KB  ((uint)0x00002000) /* use 2KB of dpram for microcode */
+#define RCCR_ERAM_4KB  ((uint)0x00004000) /* use 4KB of dpram for microcode */
+#define RCCR_ERAM_6KB  ((uint)0x00006000) /* use 6KB of dpram for microcode */
+#define RCCR_ERAM_8KB  ((uint)0x00008000) /* use 8KB of dpram for microcode */
+#define RCCR_ERAM_10KB ((uint)0x0000a000) /* use 10KB of dpram for microcode */
+#define RCCR_ERAM_12KB ((uint)0x0000c000) /* use 12KB of dpram for microcode */
+#define RCCR_EDM0      ((uint)0x00000800) /* DREQ0 edge detect mode */
+#define RCCR_EDM1      ((uint)0x00000400) /* DREQ1 edge detect mode */
+#define RCCR_EDM2      ((uint)0x00000200) /* DREQ2 edge detect mode */
+#define RCCR_EDM3      ((uint)0x00000100) /* DREQ3 edge detect mode */
+#define RCCR_DEM01     ((uint)0x00000008) /* DONE0/DONE1 edge detect mode */
+#define RCCR_DEM23     ((uint)0x00000004) /* DONE2/DONE3 edge detect mode */
+
+/*-----------------------------------------------------------------------
+ * CMXFCR - CMX FCC Clock Route Register
+ */
+#define CMXFCR_FC1         0x40000000   /* FCC1 connection              */
+#define CMXFCR_RF1CS_MSK   0x38000000   /* Receive FCC1 Clock Source Mask */
+#define CMXFCR_TF1CS_MSK   0x07000000   /* Transmit FCC1 Clock Source Mask */
+#define CMXFCR_FC2         0x00400000   /* FCC2 connection              */
+#define CMXFCR_RF2CS_MSK   0x00380000   /* Receive FCC2 Clock Source Mask */
+#define CMXFCR_TF2CS_MSK   0x00070000   /* Transmit FCC2 Clock Source Mask */
+#define CMXFCR_FC3         0x00004000   /* FCC3 connection              */
+#define CMXFCR_RF3CS_MSK   0x00003800   /* Receive FCC3 Clock Source Mask */
+#define CMXFCR_TF3CS_MSK   0x00000700   /* Transmit FCC3 Clock Source Mask */
+
+#define CMXFCR_RF1CS_BRG5  0x00000000   /* Receive FCC1 Clock Source is BRG5 */
+#define CMXFCR_RF1CS_BRG6  0x08000000   /* Receive FCC1 Clock Source is BRG6 */
+#define CMXFCR_RF1CS_BRG7  0x10000000   /* Receive FCC1 Clock Source is BRG7 */
+#define CMXFCR_RF1CS_BRG8  0x18000000   /* Receive FCC1 Clock Source is BRG8 */
+#define CMXFCR_RF1CS_CLK9  0x20000000   /* Receive FCC1 Clock Source is CLK9 */
+#define CMXFCR_RF1CS_CLK10 0x28000000   /* Receive FCC1 Clock Source is CLK10 */
+#define CMXFCR_RF1CS_CLK11 0x30000000   /* Receive FCC1 Clock Source is CLK11 */
+#define CMXFCR_RF1CS_CLK12 0x38000000   /* Receive FCC1 Clock Source is CLK12 */
+
+#define CMXFCR_TF1CS_BRG5  0x00000000   /* Transmit FCC1 Clock Source is BRG5 */
+#define CMXFCR_TF1CS_BRG6  0x01000000   /* Transmit FCC1 Clock Source is BRG6 */
+#define CMXFCR_TF1CS_BRG7  0x02000000   /* Transmit FCC1 Clock Source is BRG7 */
+#define CMXFCR_TF1CS_BRG8  0x03000000   /* Transmit FCC1 Clock Source is BRG8 */
+#define CMXFCR_TF1CS_CLK9  0x04000000   /* Transmit FCC1 Clock Source is CLK9 */
+#define CMXFCR_TF1CS_CLK10 0x05000000   /* Transmit FCC1 Clock Source is CLK10 */
+#define CMXFCR_TF1CS_CLK11 0x06000000   /* Transmit FCC1 Clock Source is CLK11 */
+#define CMXFCR_TF1CS_CLK12 0x07000000   /* Transmit FCC1 Clock Source is CLK12 */
+
+#define CMXFCR_RF2CS_BRG5  0x00000000   /* Receive FCC2 Clock Source is BRG5 */
+#define CMXFCR_RF2CS_BRG6  0x00080000   /* Receive FCC2 Clock Source is BRG6 */
+#define CMXFCR_RF2CS_BRG7  0x00100000   /* Receive FCC2 Clock Source is BRG7 */
+#define CMXFCR_RF2CS_BRG8  0x00180000   /* Receive FCC2 Clock Source is BRG8 */
+#define CMXFCR_RF2CS_CLK13 0x00200000   /* Receive FCC2 Clock Source is CLK13 */
+#define CMXFCR_RF2CS_CLK14 0x00280000   /* Receive FCC2 Clock Source is CLK14 */
+#define CMXFCR_RF2CS_CLK15 0x00300000   /* Receive FCC2 Clock Source is CLK15 */
+#define CMXFCR_RF2CS_CLK16 0x00380000   /* Receive FCC2 Clock Source is CLK16 */
+
+#define CMXFCR_TF2CS_BRG5  0x00000000   /* Transmit FCC2 Clock Source is BRG5 */
+#define CMXFCR_TF2CS_BRG6  0x00010000   /* Transmit FCC2 Clock Source is BRG6 */
+#define CMXFCR_TF2CS_BRG7  0x00020000   /* Transmit FCC2 Clock Source is BRG7 */
+#define CMXFCR_TF2CS_BRG8  0x00030000   /* Transmit FCC2 Clock Source is BRG8 */
+#define CMXFCR_TF2CS_CLK13 0x00040000   /* Transmit FCC2 Clock Source is CLK13 */
+#define CMXFCR_TF2CS_CLK14 0x00050000   /* Transmit FCC2 Clock Source is CLK14 */
+#define CMXFCR_TF2CS_CLK15 0x00060000   /* Transmit FCC2 Clock Source is CLK15 */
+#define CMXFCR_TF2CS_CLK16 0x00070000   /* Transmit FCC2 Clock Source is CLK16 */
+
+#define CMXFCR_RF3CS_BRG5  0x00000000   /* Receive FCC3 Clock Source is BRG5 */
+#define CMXFCR_RF3CS_BRG6  0x00000800   /* Receive FCC3 Clock Source is BRG6 */
+#define CMXFCR_RF3CS_BRG7  0x00001000   /* Receive FCC3 Clock Source is BRG7 */
+#define CMXFCR_RF3CS_BRG8  0x00001800   /* Receive FCC3 Clock Source is BRG8 */
+#define CMXFCR_RF3CS_CLK13 0x00002000   /* Receive FCC3 Clock Source is CLK13 */
+#define CMXFCR_RF3CS_CLK14 0x00002800   /* Receive FCC3 Clock Source is CLK14 */
+#define CMXFCR_RF3CS_CLK15 0x00003000   /* Receive FCC3 Clock Source is CLK15 */
+#define CMXFCR_RF3CS_CLK16 0x00003800   /* Receive FCC3 Clock Source is CLK16 */
+
+#define CMXFCR_TF3CS_BRG5  0x00000000   /* Transmit FCC3 Clock Source is BRG5 */
+#define CMXFCR_TF3CS_BRG6  0x00000100   /* Transmit FCC3 Clock Source is BRG6 */
+#define CMXFCR_TF3CS_BRG7  0x00000200   /* Transmit FCC3 Clock Source is BRG7 */
+#define CMXFCR_TF3CS_BRG8  0x00000300   /* Transmit FCC3 Clock Source is BRG8 */
+#define CMXFCR_TF3CS_CLK13 0x00000400   /* Transmit FCC3 Clock Source is CLK13 */
+#define CMXFCR_TF3CS_CLK14 0x00000500   /* Transmit FCC3 Clock Source is CLK14 */
+#define CMXFCR_TF3CS_CLK15 0x00000600   /* Transmit FCC3 Clock Source is CLK15 */
+#define CMXFCR_TF3CS_CLK16 0x00000700   /* Transmit FCC3 Clock Source is CLK16 */
+
+/*-----------------------------------------------------------------------
+ * CMXSCR - CMX SCC Clock Route Register
+ */
+#define CMXSCR_GR1         0x80000000   /* Grant Support of SCC1        */
+#define CMXSCR_SC1         0x40000000   /* SCC1 connection              */
+#define CMXSCR_RS1CS_MSK   0x38000000   /* Receive SCC1 Clock Source Mask */
+#define CMXSCR_TS1CS_MSK   0x07000000   /* Transmit SCC1 Clock Source Mask */
+#define CMXSCR_GR2         0x00800000   /* Grant Support of SCC2        */
+#define CMXSCR_SC2         0x00400000   /* SCC2 connection              */
+#define CMXSCR_RS2CS_MSK   0x00380000   /* Receive SCC2 Clock Source Mask */
+#define CMXSCR_TS2CS_MSK   0x00070000   /* Transmit SCC2 Clock Source Mask */
+#define CMXSCR_GR3         0x00008000   /* Grant Support of SCC3        */
+#define CMXSCR_SC3         0x00004000   /* SCC3 connection              */
+#define CMXSCR_RS3CS_MSK   0x00003800   /* Receive SCC3 Clock Source Mask */
+#define CMXSCR_TS3CS_MSK   0x00000700   /* Transmit SCC3 Clock Source Mask */
+#define CMXSCR_GR4         0x00000080   /* Grant Support of SCC4        */
+#define CMXSCR_SC4         0x00000040   /* SCC4 connection              */
+#define CMXSCR_RS4CS_MSK   0x00000038   /* Receive SCC4 Clock Source Mask */
+#define CMXSCR_TS4CS_MSK   0x00000007   /* Transmit SCC4 Clock Source Mask */
+
+#define CMXSCR_RS1CS_BRG1  0x00000000   /* SCC1 Rx Clock Source is BRG1 */
+#define CMXSCR_RS1CS_BRG2  0x08000000   /* SCC1 Rx Clock Source is BRG2 */
+#define CMXSCR_RS1CS_BRG3  0x10000000   /* SCC1 Rx Clock Source is BRG3 */
+#define CMXSCR_RS1CS_BRG4  0x18000000   /* SCC1 Rx Clock Source is BRG4 */
+#define CMXSCR_RS1CS_CLK11 0x20000000   /* SCC1 Rx Clock Source is CLK11 */
+#define CMXSCR_RS1CS_CLK12 0x28000000   /* SCC1 Rx Clock Source is CLK12 */
+#define CMXSCR_RS1CS_CLK3  0x30000000   /* SCC1 Rx Clock Source is CLK3 */
+#define CMXSCR_RS1CS_CLK4  0x38000000   /* SCC1 Rx Clock Source is CLK4 */
+
+#define CMXSCR_TS1CS_BRG1  0x00000000   /* SCC1 Tx Clock Source is BRG1 */
+#define CMXSCR_TS1CS_BRG2  0x01000000   /* SCC1 Tx Clock Source is BRG2 */
+#define CMXSCR_TS1CS_BRG3  0x02000000   /* SCC1 Tx Clock Source is BRG3 */
+#define CMXSCR_TS1CS_BRG4  0x03000000   /* SCC1 Tx Clock Source is BRG4 */
+#define CMXSCR_TS1CS_CLK11 0x04000000   /* SCC1 Tx Clock Source is CLK11 */
+#define CMXSCR_TS1CS_CLK12 0x05000000   /* SCC1 Tx Clock Source is CLK12 */
+#define CMXSCR_TS1CS_CLK3  0x06000000   /* SCC1 Tx Clock Source is CLK3 */
+#define CMXSCR_TS1CS_CLK4  0x07000000   /* SCC1 Tx Clock Source is CLK4 */
+
+#define CMXSCR_RS2CS_BRG1  0x00000000   /* SCC2 Rx Clock Source is BRG1 */
+#define CMXSCR_RS2CS_BRG2  0x00080000   /* SCC2 Rx Clock Source is BRG2 */
+#define CMXSCR_RS2CS_BRG3  0x00100000   /* SCC2 Rx Clock Source is BRG3 */
+#define CMXSCR_RS2CS_BRG4  0x00180000   /* SCC2 Rx Clock Source is BRG4 */
+#define CMXSCR_RS2CS_CLK11 0x00200000   /* SCC2 Rx Clock Source is CLK11 */
+#define CMXSCR_RS2CS_CLK12 0x00280000   /* SCC2 Rx Clock Source is CLK12 */
+#define CMXSCR_RS2CS_CLK3  0x00300000   /* SCC2 Rx Clock Source is CLK3 */
+#define CMXSCR_RS2CS_CLK4  0x00380000   /* SCC2 Rx Clock Source is CLK4 */
+
+#define CMXSCR_TS2CS_BRG1  0x00000000   /* SCC2 Tx Clock Source is BRG1 */
+#define CMXSCR_TS2CS_BRG2  0x00010000   /* SCC2 Tx Clock Source is BRG2 */
+#define CMXSCR_TS2CS_BRG3  0x00020000   /* SCC2 Tx Clock Source is BRG3 */
+#define CMXSCR_TS2CS_BRG4  0x00030000   /* SCC2 Tx Clock Source is BRG4 */
+#define CMXSCR_TS2CS_CLK11 0x00040000   /* SCC2 Tx Clock Source is CLK11 */
+#define CMXSCR_TS2CS_CLK12 0x00050000   /* SCC2 Tx Clock Source is CLK12 */
+#define CMXSCR_TS2CS_CLK3  0x00060000   /* SCC2 Tx Clock Source is CLK3 */
+#define CMXSCR_TS2CS_CLK4  0x00070000   /* SCC2 Tx Clock Source is CLK4 */
+
+#define CMXSCR_RS3CS_BRG1  0x00000000   /* SCC3 Rx Clock Source is BRG1 */
+#define CMXSCR_RS3CS_BRG2  0x00000800   /* SCC3 Rx Clock Source is BRG2 */
+#define CMXSCR_RS3CS_BRG3  0x00001000   /* SCC3 Rx Clock Source is BRG3 */
+#define CMXSCR_RS3CS_BRG4  0x00001800   /* SCC3 Rx Clock Source is BRG4 */
+#define CMXSCR_RS3CS_CLK5  0x00002000   /* SCC3 Rx Clock Source is CLK5 */
+#define CMXSCR_RS3CS_CLK6  0x00002800   /* SCC3 Rx Clock Source is CLK6 */
+#define CMXSCR_RS3CS_CLK7  0x00003000   /* SCC3 Rx Clock Source is CLK7 */
+#define CMXSCR_RS3CS_CLK8  0x00003800   /* SCC3 Rx Clock Source is CLK8 */
+
+#define CMXSCR_TS3CS_BRG1  0x00000000   /* SCC3 Tx Clock Source is BRG1 */
+#define CMXSCR_TS3CS_BRG2  0x00000100   /* SCC3 Tx Clock Source is BRG2 */
+#define CMXSCR_TS3CS_BRG3  0x00000200   /* SCC3 Tx Clock Source is BRG3 */
+#define CMXSCR_TS3CS_BRG4  0x00000300   /* SCC3 Tx Clock Source is BRG4 */
+#define CMXSCR_TS3CS_CLK5  0x00000400   /* SCC3 Tx Clock Source is CLK5 */
+#define CMXSCR_TS3CS_CLK6  0x00000500   /* SCC3 Tx Clock Source is CLK6 */
+#define CMXSCR_TS3CS_CLK7  0x00000600   /* SCC3 Tx Clock Source is CLK7 */
+#define CMXSCR_TS3CS_CLK8  0x00000700   /* SCC3 Tx Clock Source is CLK8 */
+
+#define CMXSCR_RS4CS_BRG1  0x00000000   /* SCC4 Rx Clock Source is BRG1 */
+#define CMXSCR_RS4CS_BRG2  0x00000008   /* SCC4 Rx Clock Source is BRG2 */
+#define CMXSCR_RS4CS_BRG3  0x00000010   /* SCC4 Rx Clock Source is BRG3 */
+#define CMXSCR_RS4CS_BRG4  0x00000018   /* SCC4 Rx Clock Source is BRG4 */
+#define CMXSCR_RS4CS_CLK5  0x00000020   /* SCC4 Rx Clock Source is CLK5 */
+#define CMXSCR_RS4CS_CLK6  0x00000028   /* SCC4 Rx Clock Source is CLK6 */
+#define CMXSCR_RS4CS_CLK7  0x00000030   /* SCC4 Rx Clock Source is CLK7 */
+#define CMXSCR_RS4CS_CLK8  0x00000038   /* SCC4 Rx Clock Source is CLK8 */
+
+#define CMXSCR_TS4CS_BRG1  0x00000000   /* SCC4 Tx Clock Source is BRG1 */
+#define CMXSCR_TS4CS_BRG2  0x00000001   /* SCC4 Tx Clock Source is BRG2 */
+#define CMXSCR_TS4CS_BRG3  0x00000002   /* SCC4 Tx Clock Source is BRG3 */
+#define CMXSCR_TS4CS_BRG4  0x00000003   /* SCC4 Tx Clock Source is BRG4 */
+#define CMXSCR_TS4CS_CLK5  0x00000004   /* SCC4 Tx Clock Source is CLK5 */
+#define CMXSCR_TS4CS_CLK6  0x00000005   /* SCC4 Tx Clock Source is CLK6 */
+#define CMXSCR_TS4CS_CLK7  0x00000006   /* SCC4 Tx Clock Source is CLK7 */
+#define CMXSCR_TS4CS_CLK8  0x00000007   /* SCC4 Tx Clock Source is CLK8 */
+
+#endif /* __CPM2__ */
+#endif /* __KERNEL__ */
+
+
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
new file mode 100644 (file)
index 0000000..4fb6e57
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * include/asm-ppc/mpc52xx.h
+ * 
+ * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips
+ * May need to be cleaned as the port goes on ...
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> 
+ * for the 2.4 kernel.
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __ASM_MPC52xx_H__
+#define __ASM_MPC52xx_H__
+
+#ifndef __ASSEMBLY__
+#include <asm/ppcboot.h>
+#include <asm/types.h>
+
+struct pt_regs;
+struct ocp_def;
+#endif /* __ASSEMBLY__ */
+
+
+/* ======================================================================== */
+/* Main registers/struct addresses                                          */
+/* ======================================================================== */
+/* Theses are PHYSICAL addresses !                                          */
+/* TODO : There should be no static mapping, but it's not yet the case, so  */
+/*        we require a 1:1 mapping                                          */
+
+#define MPC52xx_MBAR           0xf0000000      /* Phys address */
+#define MPC52xx_MBAR_SIZE      0x00010000
+#define MPC52xx_MBAR_VIRT      0xf0000000      /* Virt address */
+
+#define MPC52xx_MMAP_CTL       (MPC52xx_MBAR + 0x0000)
+#define MPC52xx_CDM            (MPC52xx_MBAR + 0x0200)
+#define MPC52xx_SFTRST         (MPC52xx_MBAR + 0x0220)
+#define MPC52xx_SFTRST_BIT     0x01000000
+#define MPC52xx_INTR           (MPC52xx_MBAR + 0x0500)
+#define MPC52xx_GPTx(x)                (MPC52xx_MBAR + 0x0600 + ((x)<<4))
+#define MPC52xx_RTC            (MPC52xx_MBAR + 0x0800)
+#define MPC52xx_MSCAN1         (MPC52xx_MBAR + 0x0900)
+#define MPC52xx_MSCAN2         (MPC52xx_MBAR + 0x0980)
+#define MPC52xx_GPIO           (MPC52xx_MBAR + 0x0b00)
+#define MPC52xx_PCI            (MPC52xx_MBAR + 0x0d00)
+#define MPC52xx_USB_OHCI       (MPC52xx_MBAR + 0x1000)
+#define MPC52xx_SDMA           (MPC52xx_MBAR + 0x1200)
+#define MPC52xx_XLB            (MPC52xx_MBAR + 0x1f00)
+#define MPC52xx_PSCx(x)                (MPC52xx_MBAR + 0x2000 + ((x)<<9))
+#define MPC52xx_PSC1           (MPC52xx_MBAR + 0x2000)
+#define MPC52xx_PSC2           (MPC52xx_MBAR + 0x2200)
+#define MPC52xx_PSC3           (MPC52xx_MBAR + 0x2400)
+#define MPC52xx_PSC4           (MPC52xx_MBAR + 0x2600)
+#define MPC52xx_PSC5           (MPC52xx_MBAR + 0x2800)
+#define MPC52xx_PSC6           (MPC52xx_MBAR + 0x2C00)
+#define MPC52xx_FEC            (MPC52xx_MBAR + 0x3000)
+#define MPC52xx_ATA            (MPC52xx_MBAR + 0x3a00)
+#define MPC52xx_I2C1           (MPC52xx_MBAR + 0x3d00)
+#define MPC52xx_I2C_MICR       (MPC52xx_MBAR + 0x3d20)
+#define MPC52xx_I2C2           (MPC52xx_MBAR + 0x3d40)
+
+/* SRAM used for SDMA */
+#define MPC52xx_SRAM           (MPC52xx_MBAR + 0x8000)
+#define MPC52xx_SRAM_SIZE      (16*1024)
+#define MPC52xx_SDMA_MAX_TASKS 16
+
+       /* Memory allocation block size */
+#define MPC52xx_SDRAM_UNIT     0x8000          /* 32K byte */
+
+
+/* ======================================================================== */
+/* IRQ mapping                                                              */
+/* ======================================================================== */
+/* Be sure to look at mpc52xx_pic.h if you wish for whatever reason to change
+ * this
+ */
+
+#define MPC52xx_CRIT_IRQ_NUM   4
+#define MPC52xx_MAIN_IRQ_NUM   17
+#define MPC52xx_SDMA_IRQ_NUM   17
+#define MPC52xx_PERP_IRQ_NUM   23
+
+#define MPC52xx_CRIT_IRQ_BASE  0
+#define MPC52xx_MAIN_IRQ_BASE  (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM)
+#define MPC52xx_SDMA_IRQ_BASE  (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM)
+#define MPC52xx_PERP_IRQ_BASE  (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)
+
+#define MPC52xx_IRQ0                   (MPC52xx_CRIT_IRQ_BASE + 0)
+#define MPC52xx_SLICE_TIMER_0_IRQ      (MPC52xx_CRIT_IRQ_BASE + 1)
+#define MPC52xx_HI_INT_IRQ             (MPC52xx_CRIT_IRQ_BASE + 2)
+#define MPC52xx_CCS_IRQ                        (MPC52xx_CRIT_IRQ_BASE + 3)
+
+#define MPC52xx_IRQ1                   (MPC52xx_MAIN_IRQ_BASE + 1)
+#define MPC52xx_IRQ2                   (MPC52xx_MAIN_IRQ_BASE + 2)
+#define MPC52xx_IRQ3                   (MPC52xx_MAIN_IRQ_BASE + 3)
+
+#define MPC52xx_SDMA_IRQ               (MPC52xx_PERP_IRQ_BASE + 0)
+#define MPC52xx_PSC1_IRQ               (MPC52xx_PERP_IRQ_BASE + 1)
+#define MPC52xx_PSC2_IRQ               (MPC52xx_PERP_IRQ_BASE + 2)
+#define MPC52xx_PSC3_IRQ               (MPC52xx_PERP_IRQ_BASE + 3)
+#define MPC52xx_PSC6_IRQ               (MPC52xx_PERP_IRQ_BASE + 4)
+#define MPC52xx_IRDA_IRQ               (MPC52xx_PERP_IRQ_BASE + 4)
+#define MPC52xx_FEC_IRQ                        (MPC52xx_PERP_IRQ_BASE + 5)
+#define MPC52xx_USB_IRQ                        (MPC52xx_PERP_IRQ_BASE + 6)
+#define MPC52xx_ATA_IRQ                        (MPC52xx_PERP_IRQ_BASE + 7)
+#define MPC52xx_PCI_CNTRL_IRQ          (MPC52xx_PERP_IRQ_BASE + 8)
+#define MPC52xx_PCI_SCIRX_IRQ          (MPC52xx_PERP_IRQ_BASE + 9)
+#define MPC52xx_PCI_SCITX_IRQ          (MPC52xx_PERP_IRQ_BASE + 10)
+#define MPC52xx_PSC4_IRQ               (MPC52xx_PERP_IRQ_BASE + 11)
+#define MPC52xx_PSC5_IRQ               (MPC52xx_PERP_IRQ_BASE + 12)
+#define MPC52xx_SPI_MODF_IRQ           (MPC52xx_PERP_IRQ_BASE + 13)
+#define MPC52xx_SPI_SPIF_IRQ           (MPC52xx_PERP_IRQ_BASE + 14)
+#define MPC52xx_I2C1_IRQ               (MPC52xx_PERP_IRQ_BASE + 15)
+#define MPC52xx_I2C2_IRQ               (MPC52xx_PERP_IRQ_BASE + 16)
+#define MPC52xx_CAN1_IRQ               (MPC52xx_PERP_IRQ_BASE + 17)
+#define MPC52xx_CAN2_IRQ               (MPC52xx_PERP_IRQ_BASE + 18)
+#define MPC52xx_IR_RX_IRQ              (MPC52xx_PERP_IRQ_BASE + 19)
+#define MPC52xx_IR_TX_IRQ              (MPC52xx_PERP_IRQ_BASE + 20)
+#define MPC52xx_XLB_ARB_IRQ            (MPC52xx_PERP_IRQ_BASE + 21)
+
+
+
+/* ======================================================================== */
+/* Structures mapping of some unit register set                             */
+/* ======================================================================== */
+
+#ifndef __ASSEMBLY__
+
+/* Memory Mapping Control */
+struct mpc52xx_mmap_ctl {
+       volatile u32    mbar;           /* MMAP_CTRL + 0x00 */
+
+       volatile u32    cs0_start;      /* MMAP_CTRL + 0x04 */
+       volatile u32    cs0_stop;       /* MMAP_CTRL + 0x08 */
+       volatile u32    cs1_start;      /* MMAP_CTRL + 0x0c */
+       volatile u32    cs1_stop;       /* MMAP_CTRL + 0x10 */
+       volatile u32    cs2_start;      /* MMAP_CTRL + 0x14 */
+       volatile u32    cs2_stop;       /* MMAP_CTRL + 0x18 */
+       volatile u32    cs3_start;      /* MMAP_CTRL + 0x1c */
+       volatile u32    cs3_stop;       /* MMAP_CTRL + 0x20 */
+       volatile u32    cs4_start;      /* MMAP_CTRL + 0x24 */
+       volatile u32    cs4_stop;       /* MMAP_CTRL + 0x28 */
+       volatile u32    cs5_start;      /* MMAP_CTRL + 0x2c */
+       volatile u32    cs5_stop;       /* MMAP_CTRL + 0x30 */
+
+       volatile u32    sdram0;         /* MMAP_CTRL + 0x34 */
+       volatile u32    sdram1;         /* MMAP_CTRL + 0X38 */
+
+       volatile u32    reserved[4];    /* MMAP_CTRL + 0x3c .. 0x48 */
+
+       volatile u32    boot_start;     /* MMAP_CTRL + 0x4c */
+       volatile u32    boot_stop;      /* MMAP_CTRL + 0x50 */
+       
+       volatile u32    ipbi_ws_ctrl;   /* MMAP_CTRL + 0x54 */
+       
+       volatile u32    cs6_start;      /* MMAP_CTRL + 0x58 */
+       volatile u32    cs6_stop;       /* MMAP_CTRL + 0x5c */
+       volatile u32    cs7_start;      /* MMAP_CTRL + 0x60 */
+       volatile u32    cs7_stop;       /* MMAP_CTRL + 0x60 */
+};
+
+/* Interrupt controller */
+struct mpc52xx_intr {
+       volatile u32    per_mask;       /* INTR + 0x00 */
+       volatile u32    per_pri1;       /* INTR + 0x04 */
+       volatile u32    per_pri2;       /* INTR + 0x08 */
+       volatile u32    per_pri3;       /* INTR + 0x0c */
+       volatile u32    ctrl;           /* INTR + 0x10 */
+       volatile u32    main_mask;      /* INTR + 0x14 */
+       volatile u32    main_pri1;      /* INTR + 0x18 */
+       volatile u32    main_pri2;      /* INTR + 0x1c */
+       volatile u32    reserved1;      /* INTR + 0x20 */
+       volatile u32    enc_status;     /* INTR + 0x24 */
+       volatile u32    crit_status;    /* INTR + 0x28 */
+       volatile u32    main_status;    /* INTR + 0x2c */
+       volatile u32    per_status;     /* INTR + 0x30 */
+       volatile u32    reserved2;      /* INTR + 0x34 */
+       volatile u32    per_error;      /* INTR + 0x38 */
+};
+
+/* SDMA */
+struct mpc52xx_sdma {
+       volatile u32    taskBar;        /* SDMA + 0x00 */
+       volatile u32    currentPointer; /* SDMA + 0x04 */
+       volatile u32    endPointer;     /* SDMA + 0x08 */
+       volatile u32    variablePointer;/* SDMA + 0x0c */
+
+       volatile u8     IntVect1;       /* SDMA + 0x10 */
+       volatile u8     IntVect2;       /* SDMA + 0x11 */
+       volatile u16    PtdCntrl;       /* SDMA + 0x12 */
+
+       volatile u32    IntPend;        /* SDMA + 0x14 */
+       volatile u32    IntMask;        /* SDMA + 0x18 */
+       
+       volatile u16    tcr[16];        /* SDMA + 0x1c .. 0x3a */
+
+       volatile u8     ipr[31];        /* SDMA + 0x3c .. 5b */
+
+       volatile u32    res1;           /* SDMA + 0x5c */
+       volatile u32    task_size0;     /* SDMA + 0x60 */
+       volatile u32    task_size1;     /* SDMA + 0x64 */
+       volatile u32    MDEDebug;       /* SDMA + 0x68 */
+       volatile u32    ADSDebug;       /* SDMA + 0x6c */
+       volatile u32    Value1;         /* SDMA + 0x70 */
+       volatile u32    Value2;         /* SDMA + 0x74 */
+       volatile u32    Control;        /* SDMA + 0x78 */
+       volatile u32    Status;         /* SDMA + 0x7c */
+};
+
+/* GPT */
+struct mpc52xx_gpt {
+       volatile u32    mode;           /* GPTx + 0x00 */
+       volatile u32    count;          /* GPTx + 0x04 */
+       volatile u32    pwm;            /* GPTx + 0x08 */
+       volatile u32    status;         /* GPTx + 0X0c */
+};
+
+/* RTC */
+struct mpc52xx_rtc {
+       volatile u32    time_set;       /* RTC + 0x00 */
+       volatile u32    date_set;       /* RTC + 0x04 */
+       volatile u32    stopwatch;      /* RTC + 0x08 */
+       volatile u32    int_enable;     /* RTC + 0x0c */
+       volatile u32    time;           /* RTC + 0x10 */
+       volatile u32    date;           /* RTC + 0x14 */
+       volatile u32    stopwatch_intr; /* RTC + 0x18 */
+       volatile u32    bus_error;      /* RTC + 0x1c */
+       volatile u32    dividers;       /* RTC + 0x20 */
+};
+
+/* GPIO */
+struct mpc52xx_gpio {
+       volatile u32    port_config;    /* GPIO + 0x00 */
+       volatile u32    simple_gpioe;   /* GPIO + 0x04 */
+       volatile u32    simple_ode;     /* GPIO + 0x08 */
+       volatile u32    simple_ddr;     /* GPIO + 0x0c */
+       volatile u32    simple_dvo;     /* GPIO + 0x10 */
+       volatile u32    simple_ival;    /* GPIO + 0x14 */
+       volatile u8     outo_gpioe;     /* GPIO + 0x18 */
+       volatile u8     reserved1[3];   /* GPIO + 0x19 */
+       volatile u8     outo_dvo;       /* GPIO + 0x1c */
+       volatile u8     reserved2[3];   /* GPIO + 0x1d */
+       volatile u8     sint_gpioe;     /* GPIO + 0x20 */
+       volatile u8     reserved3[3];   /* GPIO + 0x21 */
+       volatile u8     sint_ode;       /* GPIO + 0x24 */
+       volatile u8     reserved4[3];   /* GPIO + 0x25 */
+       volatile u8     sint_ddr;       /* GPIO + 0x28 */
+       volatile u8     reserved5[3];   /* GPIO + 0x29 */
+       volatile u8     sint_dvo;       /* GPIO + 0x2c */
+       volatile u8     reserved6[3];   /* GPIO + 0x2d */
+       volatile u8     sint_inten;     /* GPIO + 0x30 */
+       volatile u8     reserved7[3];   /* GPIO + 0x31 */
+       volatile u16    sint_itype;     /* GPIO + 0x34 */
+       volatile u16    reserved8;      /* GPIO + 0x36 */
+       volatile u8     gpio_control;   /* GPIO + 0x38 */
+       volatile u8     reserved9[3];   /* GPIO + 0x39 */
+       volatile u8     sint_istat;     /* GPIO + 0x3c */
+       volatile u8     sint_ival;      /* GPIO + 0x3d */
+       volatile u8     bus_errs;       /* GPIO + 0x3e */
+       volatile u8     reserved10;     /* GPIO + 0x3f */
+};
+
+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD        4
+#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD   5
+#define MPC52xx_GPIO_PCI_DIS                   (1<<15)
+
+/* XLB Bus control */
+struct mpc52xx_xlb {
+       volatile u8 reserved[0x40];
+       volatile u32 config;            /* XLB + 0x40 */
+       volatile u32 version;           /* XLB + 0x44 */
+       volatile u32 status;            /* XLB + 0x48 */
+       volatile u32 int_enable;        /* XLB + 0x4c */
+       volatile u32 addr_capture;      /* XLB + 0x50 */
+       volatile u32 bus_sig_capture;   /* XLB + 0x54 */
+       volatile u32 addr_timeout;      /* XLB + 0x58 */
+       volatile u32 data_timeout;      /* XLB + 0x5c */
+       volatile u32 bus_act_timeout;   /* XLB + 0x60 */
+       volatile u32 master_pri_enable; /* XLB + 0x64 */
+       volatile u32 master_priority;   /* XLB + 0x68 */
+       volatile u32 base_address;      /* XLB + 0x6c */
+       volatile u32 snoop_window;      /* XLB + 0x70 */
+};
+
+
+/* Clock Distribution control */
+struct mpc52xx_cdm {
+       volatile u32    jtag_id;        /* MBAR_CDM + 0x00  reg0 read only */
+       volatile u32    rstcfg;         /* MBAR_CDM + 0x04  reg1 read only */
+       volatile u32    breadcrumb;     /* MBAR_CDM + 0x08  reg2 */
+
+       volatile u8     mem_clk_sel;    /* MBAR_CDM + 0x0c  reg3 byte0 */
+       volatile u8     xlb_clk_sel;    /* MBAR_CDM + 0x0d  reg3 byte1 read only */
+       volatile u8     ipb_clk_sel;    /* MBAR_CDM + 0x0e  reg3 byte2 */
+       volatile u8     pci_clk_sel;    /* MBAR_CDM + 0x0f  reg3 byte3 */
+
+       volatile u8     ext_48mhz_en;   /* MBAR_CDM + 0x10  reg4 byte0 */
+       volatile u8     fd_enable;      /* MBAR_CDM + 0x11  reg4 byte1 */
+       volatile u16    fd_counters;    /* MBAR_CDM + 0x12  reg4 byte2,3 */
+
+       volatile u32    clk_enables;    /* MBAR_CDM + 0x14  reg5 */
+
+       volatile u8     osc_disable;    /* MBAR_CDM + 0x18  reg6 byte0 */
+       volatile u8     reserved0[3];   /* MBAR_CDM + 0x19  reg6 byte1,2,3 */
+
+       volatile u8     ccs_sleep_enable;/* MBAR_CDM + 0x1c  reg7 byte0 */
+       volatile u8     osc_sleep_enable;/* MBAR_CDM + 0x1d  reg7 byte1 */
+       volatile u8     reserved1;      /* MBAR_CDM + 0x1e  reg7 byte2 */
+       volatile u8     ccs_qreq_test;  /* MBAR_CDM + 0x1f  reg7 byte3 */
+
+       volatile u8     soft_reset;     /* MBAR_CDM + 0x20  u8 byte0 */
+       volatile u8     no_ckstp;       /* MBAR_CDM + 0x21  u8 byte0 */
+       volatile u8     reserved2[2];   /* MBAR_CDM + 0x22  u8 byte1,2,3 */
+
+       volatile u8     pll_lock;       /* MBAR_CDM + 0x24  reg9 byte0 */
+       volatile u8     pll_looselock;  /* MBAR_CDM + 0x25  reg9 byte1 */
+       volatile u8     pll_sm_lockwin; /* MBAR_CDM + 0x26  reg9 byte2 */
+       volatile u8     reserved3;      /* MBAR_CDM + 0x27  reg9 byte3 */
+
+       volatile u16    reserved4;      /* MBAR_CDM + 0x28  reg10 byte0,1 */
+       volatile u16    mclken_div_psc1;/* MBAR_CDM + 0x2a  reg10 byte2,3 */
+    
+       volatile u16    reserved5;      /* MBAR_CDM + 0x2c  reg11 byte0,1 */
+       volatile u16    mclken_div_psc2;/* MBAR_CDM + 0x2e  reg11 byte2,3 */
+               
+       volatile u16    reserved6;      /* MBAR_CDM + 0x30  reg12 byte0,1 */
+       volatile u16    mclken_div_psc3;/* MBAR_CDM + 0x32  reg12 byte2,3 */
+    
+       volatile u16    reserved7;      /* MBAR_CDM + 0x34  reg13 byte0,1 */
+       volatile u16    mclken_div_psc6;/* MBAR_CDM + 0x36  reg13 byte2,3 */
+};
+
+#endif /* __ASSEMBLY__ */
+
+
+/* ========================================================================= */
+/* Prototypes for MPC52xx syslib                                             */
+/* ========================================================================= */
+
+#ifndef __ASSEMBLY__
+
+extern void mpc52xx_init_irq(void);
+extern int mpc52xx_get_irq(struct pt_regs *regs);
+
+extern unsigned long mpc52xx_find_end_of_memory(void);
+extern void mpc52xx_set_bat(void);
+extern void mpc52xx_map_io(void);
+extern void mpc52xx_restart(char *cmd);
+extern void mpc52xx_halt(void);
+extern void mpc52xx_power_off(void);
+extern void mpc52xx_progress(char *s, unsigned short hex);
+extern void mpc52xx_calibrate_decr(void);
+extern void mpc52xx_add_board_devices(struct ocp_def board_ocp[]);
+
+#endif /* __ASSEMBLY__ */
+
+
+/* ========================================================================= */
+/* Platform configuration                                                    */
+/* ========================================================================= */
+
+/* The U-Boot platform information struct */
+extern bd_t __res;
+
+/* Platform options */
+#if defined(CONFIG_LITE5200)
+#include <platforms/lite5200.h>
+#endif
+
+
+#endif /* __ASM_MPC52xx_H__ */
diff --git a/include/asm-ppc/mpc52xx_psc.h b/include/asm-ppc/mpc52xx_psc.h
new file mode 100644 (file)
index 0000000..483102e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * include/asm-ppc/mpc52xx_psc.h
+ * 
+ * Definitions of consts/structs to drive the Freescale MPC52xx OnChip
+ * PSCs. Theses are shared between multiple drivers since a PSC can be
+ * UART, AC97, IR, I2S, ... So this header is in asm-ppc.
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Based/Extracted from some header of the 2.4 originally written by 
+ * Dale Farnsworth <dfarnsworth@mvista.com> 
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __MPC52xx_PSC_H__
+#define __MPC52xx_PSC_H__
+
+#include <asm/types.h>
+
+/* Max number of PSCs */
+#define MPC52xx_PSC_MAXNUM     6
+
+/* Programmable Serial Controller (PSC) status register bits */
+#define MPC52xx_PSC_SR_CDE     0x0080
+#define MPC52xx_PSC_SR_RXRDY   0x0100
+#define MPC52xx_PSC_SR_RXFULL  0x0200
+#define MPC52xx_PSC_SR_TXRDY   0x0400
+#define MPC52xx_PSC_SR_TXEMP   0x0800
+#define MPC52xx_PSC_SR_OE      0x1000
+#define MPC52xx_PSC_SR_PE      0x2000
+#define MPC52xx_PSC_SR_FE      0x4000
+#define MPC52xx_PSC_SR_RB      0x8000
+
+/* PSC Command values */
+#define MPC52xx_PSC_RX_ENABLE          0x0001
+#define MPC52xx_PSC_RX_DISABLE         0x0002
+#define MPC52xx_PSC_TX_ENABLE          0x0004
+#define MPC52xx_PSC_TX_DISABLE         0x0008
+#define MPC52xx_PSC_SEL_MODE_REG_1     0x0010
+#define MPC52xx_PSC_RST_RX             0x0020
+#define MPC52xx_PSC_RST_TX             0x0030
+#define MPC52xx_PSC_RST_ERR_STAT       0x0040
+#define MPC52xx_PSC_RST_BRK_CHG_INT    0x0050
+#define MPC52xx_PSC_START_BRK          0x0060
+#define MPC52xx_PSC_STOP_BRK           0x0070
+
+/* PSC TxRx FIFO status bits */
+#define MPC52xx_PSC_RXTX_FIFO_ERR      0x0040
+#define MPC52xx_PSC_RXTX_FIFO_UF       0x0020
+#define MPC52xx_PSC_RXTX_FIFO_OF       0x0010
+#define MPC52xx_PSC_RXTX_FIFO_FR       0x0008
+#define MPC52xx_PSC_RXTX_FIFO_FULL     0x0004
+#define MPC52xx_PSC_RXTX_FIFO_ALARM    0x0002
+#define MPC52xx_PSC_RXTX_FIFO_EMPTY    0x0001
+
+/* PSC interrupt mask bits */
+#define MPC52xx_PSC_IMR_TXRDY          0x0100
+#define MPC52xx_PSC_IMR_RXRDY          0x0200
+#define MPC52xx_PSC_IMR_DB             0x0400
+#define MPC52xx_PSC_IMR_IPC            0x8000
+
+/* PSC input port change bit */
+#define MPC52xx_PSC_CTS                        0x01
+#define MPC52xx_PSC_DCD                        0x02
+#define MPC52xx_PSC_D_CTS              0x10
+#define MPC52xx_PSC_D_DCD              0x20
+
+/* PSC mode fields */
+#define MPC52xx_PSC_MODE_5_BITS                        0x00
+#define MPC52xx_PSC_MODE_6_BITS                        0x01
+#define MPC52xx_PSC_MODE_7_BITS                        0x02
+#define MPC52xx_PSC_MODE_8_BITS                        0x03
+#define MPC52xx_PSC_MODE_BITS_MASK             0x03
+#define MPC52xx_PSC_MODE_PAREVEN               0x00
+#define MPC52xx_PSC_MODE_PARODD                        0x04
+#define MPC52xx_PSC_MODE_PARFORCE              0x08
+#define MPC52xx_PSC_MODE_PARNONE               0x10
+#define MPC52xx_PSC_MODE_ERR                   0x20
+#define MPC52xx_PSC_MODE_FFULL                 0x40
+#define MPC52xx_PSC_MODE_RXRTS                 0x80
+
+#define MPC52xx_PSC_MODE_ONE_STOP_5_BITS       0x00
+#define MPC52xx_PSC_MODE_ONE_STOP              0x07
+#define MPC52xx_PSC_MODE_TWO_STOP              0x0f
+
+#define MPC52xx_PSC_RFNUM_MASK 0x01ff
+
+
+/* Structure of the hardware registers */
+struct mpc52xx_psc {
+       volatile u8             mode;           /* PSC + 0x00 */
+       volatile u8             reserved0[3];
+       union {                                 /* PSC + 0x04 */
+               volatile u16    status;
+               volatile u16    clock_select;
+       } sr_csr;
+#define mpc52xx_psc_status     sr_csr.status
+#define mpc52xx_psc_clock_select       sr_csr.clock_select
+       volatile u16            reserved1;
+       volatile u8             command;        /* PSC + 0x08 */
+volatile u8            reserved2[3];
+       union {                                 /* PSC + 0x0c */
+               volatile u8     buffer_8;
+               volatile u16    buffer_16;
+               volatile u32    buffer_32;
+       } buffer;
+#define mpc52xx_psc_buffer_8   buffer.buffer_8
+#define mpc52xx_psc_buffer_16  buffer.buffer_16
+#define mpc52xx_psc_buffer_32  buffer.buffer_32
+       union {                                 /* PSC + 0x10 */
+               volatile u8     ipcr;
+               volatile u8     acr;
+       } ipcr_acr;
+#define mpc52xx_psc_ipcr       ipcr_acr.ipcr
+#define mpc52xx_psc_acr                ipcr_acr.acr
+       volatile u8             reserved3[3];
+       union {                                 /* PSC + 0x14 */
+               volatile u16    isr;
+               volatile u16    imr;
+       } isr_imr;
+#define mpc52xx_psc_isr                isr_imr.isr
+#define mpc52xx_psc_imr                isr_imr.imr
+       volatile u16            reserved4;
+       volatile u8             ctur;           /* PSC + 0x18 */
+       volatile u8             reserved5[3];
+       volatile u8             ctlr;           /* PSC + 0x1c */
+       volatile u8             reserved6[3];
+       volatile u16            ccr;            /* PSC + 0x20 */
+       volatile u8             reserved7[14];
+       volatile u8             ivr;            /* PSC + 0x30 */
+       volatile u8             reserved8[3];
+       volatile u8             ip;             /* PSC + 0x34 */
+       volatile u8             reserved9[3];
+       volatile u8             op1;            /* PSC + 0x38 */
+       volatile u8             reserved10[3];
+       volatile u8             op0;            /* PSC + 0x3c */
+       volatile u8             reserved11[3];
+       volatile u32            sicr;           /* PSC + 0x40 */
+       volatile u8             ircr1;          /* PSC + 0x44 */
+       volatile u8             reserved13[3];
+       volatile u8             ircr2;          /* PSC + 0x44 */
+       volatile u8             reserved14[3];
+       volatile u8             irsdr;          /* PSC + 0x4c */
+       volatile u8             reserved15[3];
+       volatile u8             irmdr;          /* PSC + 0x50 */
+       volatile u8             reserved16[3];
+       volatile u8             irfdr;          /* PSC + 0x54 */
+       volatile u8             reserved17[3];
+       volatile u16            rfnum;          /* PSC + 0x58 */
+       volatile u16            reserved18;
+       volatile u16            tfnum;          /* PSC + 0x5c */
+       volatile u16            reserved19;
+       volatile u32            rfdata;         /* PSC + 0x60 */
+       volatile u16            rfstat;         /* PSC + 0x64 */
+       volatile u16            reserved20;
+       volatile u8             rfcntl;         /* PSC + 0x68 */
+       volatile u8             reserved21[5];
+       volatile u16            rfalarm;        /* PSC + 0x6e */
+       volatile u16            reserved22;
+       volatile u16            rfrptr;         /* PSC + 0x72 */
+       volatile u16            reserved23;
+       volatile u16            rfwptr;         /* PSC + 0x76 */
+       volatile u16            reserved24;
+       volatile u16            rflrfptr;       /* PSC + 0x7a */
+       volatile u16            reserved25;
+       volatile u16            rflwfptr;       /* PSC + 0x7e */
+       volatile u32            tfdata;         /* PSC + 0x80 */
+       volatile u16            tfstat;         /* PSC + 0x84 */
+       volatile u16            reserved26;
+       volatile u8             tfcntl;         /* PSC + 0x88 */
+       volatile u8             reserved27[5];
+       volatile u16            tfalarm;        /* PSC + 0x8e */
+       volatile u16            reserved28;
+       volatile u16            tfrptr;         /* PSC + 0x92 */
+       volatile u16            reserved29;
+       volatile u16            tfwptr;         /* PSC + 0x96 */
+       volatile u16            reserved30;
+       volatile u16            tflrfptr;       /* PSC + 0x9a */
+       volatile u16            reserved31;
+       volatile u16            tflwfptr;       /* PSC + 0x9e */
+};
+
+
+#endif  /* __MPC52xx_PSC_H__ */
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
new file mode 100644 (file)
index 0000000..d3be235
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * include/asm-ppc/mpc85xx.h
+ *
+ * MPC85xx definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor, 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC85xx_H__
+#define __ASM_MPC85xx_H__
+
+#include <linux/config.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_85xx
+
+#ifdef CONFIG_MPC8540_ADS
+#include <platforms/85xx/mpc8540_ads.h>
+#endif
+#ifdef CONFIG_MPC8555_CDS
+#include <platforms/85xx/mpc8555_cds.h>
+#endif
+#ifdef CONFIG_MPC8560_ADS
+#include <platforms/85xx/mpc8560_ads.h>
+#endif
+#ifdef CONFIG_SBC8560
+#include <platforms/85xx/sbc8560.h>
+#endif
+
+#define _IO_BASE        isa_io_base
+#define _ISA_MEM_BASE   isa_mem_base
+#ifdef CONFIG_PCI
+#define PCI_DRAM_OFFSET pci_dram_offset
+#else
+#define PCI_DRAM_OFFSET 0
+#endif
+
+/*
+ * The "residual" board information structure the boot loader passes
+ * into the kernel.
+ */
+extern unsigned char __res[];
+
+/* Internal IRQs on MPC85xx OpenPIC */
+/* Not all of these exist on all MPC85xx implementations */
+
+#ifndef MPC85xx_OPENPIC_IRQ_OFFSET
+#define MPC85xx_OPENPIC_IRQ_OFFSET     64
+#endif
+
+/* The 32 internal sources */
+#define MPC85xx_IRQ_L2CACHE    ( 0 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_ECM                ( 1 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DDR                ( 2 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_LBIU       ( 3 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA0       ( 4 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA1       ( 5 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA2       ( 6 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA3       ( 7 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI1       ( 8 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI2       ( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_ERROR  ( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_BELL   (10 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_TX     (11 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_RX     (12 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_TX   (13 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_RX   (14 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_ERROR        (18 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_TX   (19 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_RX   (20 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_ERROR        (24 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_FEC                (25 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DUART      (26 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_IIC1       (27 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PERFMON    (28 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_CPM                (30 + MPC85xx_OPENPIC_IRQ_OFFSET)
+
+/* The 12 external interrupt lines */
+#define MPC85xx_IRQ_EXT0        (32 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT1        (33 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT2        (34 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT3        (35 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT4        (36 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT5        (37 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT6        (38 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT7        (39 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT8        (40 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT9        (41 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT10       (42 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT11       (43 + MPC85xx_OPENPIC_IRQ_OFFSET)
+
+/* Offset from CCSRBAR */
+#define MPC85xx_CPM_OFFSET     (0x80000)
+#define MPC85xx_CPM_SIZE       (0x40000)
+#define MPC85xx_DMA_OFFSET     (0x21000)
+#define MPC85xx_DMA_SIZE       (0x01000)
+#define MPC85xx_ENET1_OFFSET   (0x24000)
+#define MPC85xx_ENET1_SIZE     (0x01000)
+#define MPC85xx_ENET2_OFFSET   (0x25000)
+#define MPC85xx_ENET2_SIZE     (0x01000)
+#define MPC85xx_ENET3_OFFSET   (0x26000)
+#define MPC85xx_ENET3_SIZE     (0x01000)
+#define MPC85xx_GUTS_OFFSET    (0xe0000)
+#define MPC85xx_GUTS_SIZE      (0x01000)
+#define MPC85xx_IIC1_OFFSET    (0x03000)
+#define MPC85xx_IIC1_SIZE      (0x01000)
+#define MPC85xx_OPENPIC_OFFSET (0x40000)
+#define MPC85xx_OPENPIC_SIZE   (0x40000)
+#define MPC85xx_PCI1_OFFSET    (0x08000)
+#define MPC85xx_PCI1_SIZE      (0x01000)
+#define MPC85xx_PCI2_OFFSET    (0x09000)
+#define MPC85xx_PCI2_SIZE      (0x01000)
+#define MPC85xx_PERFMON_OFFSET (0xe1000)
+#define MPC85xx_PERFMON_SIZE   (0x01000)
+#define MPC85xx_UART0_OFFSET   (0x04500)
+#define MPC85xx_UART0_SIZE     (0x00100)
+#define MPC85xx_UART1_OFFSET   (0x04600)
+#define MPC85xx_UART1_SIZE     (0x00100)
+
+#define MPC85xx_CCSRBAR_SIZE   (1024*1024)
+
+/* Let modules/drivers get at CCSRBAR */
+extern phys_addr_t get_ccsrbar(void);
+
+#ifdef MODULE
+#define CCSRBAR get_ccsrbar()
+#else
+#define CCSRBAR BOARD_CCSRBAR
+#endif
+
+#endif /* CONFIG_85xx */
+#endif /* __ASM_MPC85xx_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ppc4xx_dma.h b/include/asm-ppc/ppc4xx_dma.h
new file mode 100644 (file)
index 0000000..5b82faf
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * include/asm-ppc/ppc4xx_dma.h
+ *
+ * IBM PPC4xx DMA engine library
+ *
+ * Copyright 2000-2004 MontaVista Software Inc.
+ *
+ * Cleaned up a bit more, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Original code by Armin Kuster <akuster@mvista.com>
+ * and Pete Popov <ppopov@mvista.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.
+ *
+ * You 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASMPPC_PPC4xx_DMA_H
+#define __ASMPPC_PPC4xx_DMA_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/mmu.h>
+#include <asm/ibm4xx.h>
+
+#undef DEBUG_4xxDMA
+
+#define MAX_PPC4xx_DMA_CHANNELS                4
+
+/* in arch/ppc/kernel/setup.c -- Cort */
+extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
+
+/*
+ * Function return status codes
+ * These values are used to indicate whether or not the function
+ * call was successful, or a bad/invalid parameter was passed.
+ */
+#define DMA_STATUS_GOOD                        0
+#define DMA_STATUS_BAD_CHANNEL         1
+#define DMA_STATUS_BAD_HANDLE          2
+#define DMA_STATUS_BAD_MODE            3
+#define DMA_STATUS_NULL_POINTER                4
+#define DMA_STATUS_OUT_OF_MEMORY       5
+#define DMA_STATUS_SGL_LIST_EMPTY      6
+#define DMA_STATUS_GENERAL_ERROR       7
+#define DMA_STATUS_CHANNEL_NOTFREE     8
+
+#define DMA_CHANNEL_BUSY               0x80000000
+
+/*
+ * These indicate status as returned from the DMA Status Register.
+ */
+#define DMA_STATUS_NO_ERROR    0
+#define DMA_STATUS_CS          1       /* Count Status        */
+#define DMA_STATUS_TS          2       /* Transfer Status     */
+#define DMA_STATUS_DMA_ERROR   3       /* DMA Error Occurred  */
+#define DMA_STATUS_DMA_BUSY    4       /* The channel is busy */
+
+
+/*
+ * DMA Channel Control Registers
+ */
+
+#ifdef CONFIG_44x
+#define        PPC4xx_DMA_64BIT
+#define DMA_CR_OFFSET 1
+#else
+#define DMA_CR_OFFSET 0
+#endif
+
+#define DMA_CE_ENABLE        (1<<31)   /* DMA Channel Enable */
+#define SET_DMA_CE_ENABLE(x) (((x)&0x1)<<31)
+#define GET_DMA_CE_ENABLE(x) (((x)&DMA_CE_ENABLE)>>31)
+
+#define DMA_CIE_ENABLE        (1<<30)  /* DMA Channel Interrupt Enable */
+#define SET_DMA_CIE_ENABLE(x) (((x)&0x1)<<30)
+#define GET_DMA_CIE_ENABLE(x) (((x)&DMA_CIE_ENABLE)>>30)
+
+#define DMA_TD                (1<<29)
+#define SET_DMA_TD(x)         (((x)&0x1)<<29)
+#define GET_DMA_TD(x)         (((x)&DMA_TD)>>29)
+
+#define DMA_PL                (1<<28)  /* Peripheral Location */
+#define SET_DMA_PL(x)         (((x)&0x1)<<28)
+#define GET_DMA_PL(x)         (((x)&DMA_PL)>>28)
+
+#define EXTERNAL_PERIPHERAL    0
+#define INTERNAL_PERIPHERAL    1
+
+#define SET_DMA_PW(x)     (((x)&0x3)<<(26-DMA_CR_OFFSET))      /* Peripheral Width */
+#define DMA_PW_MASK       SET_DMA_PW(3)
+#define   PW_8                 0
+#define   PW_16                1
+#define   PW_32                2
+#define   PW_64                3
+/* FIXME: Add PW_128 support for 440GP DMA block */
+#define GET_DMA_PW(x)     (((x)&DMA_PW_MASK)>>(26-DMA_CR_OFFSET))
+
+#define DMA_DAI           (1<<(25-DMA_CR_OFFSET))      /* Destination Address Increment */
+#define SET_DMA_DAI(x)    (((x)&0x1)<<(25-DMA_CR_OFFSET))
+
+#define DMA_SAI           (1<<(24-DMA_CR_OFFSET))      /* Source Address Increment */
+#define SET_DMA_SAI(x)    (((x)&0x1)<<(24-DMA_CR_OFFSET))
+
+#define DMA_BEN           (1<<(23-DMA_CR_OFFSET))      /* Buffer Enable */
+#define SET_DMA_BEN(x)    (((x)&0x1)<<(23-DMA_CR_OFFSET))
+
+#define SET_DMA_TM(x)     (((x)&0x3)<<(21-DMA_CR_OFFSET))      /* Transfer Mode */
+#define DMA_TM_MASK       SET_DMA_TM(3)
+#define   TM_PERIPHERAL        0       /* Peripheral */
+#define   TM_RESERVED          1       /* Reserved */
+#define   TM_S_MM              2       /* Memory to Memory */
+#define   TM_D_MM              3       /* Device Paced Memory to Memory */
+#define GET_DMA_TM(x)     (((x)&DMA_TM_MASK)>>(21-DMA_CR_OFFSET))
+
+#define SET_DMA_PSC(x)    (((x)&0x3)<<(19-DMA_CR_OFFSET))      /* Peripheral Setup Cycles */
+#define DMA_PSC_MASK      SET_DMA_PSC(3)
+#define GET_DMA_PSC(x)    (((x)&DMA_PSC_MASK)>>(19-DMA_CR_OFFSET))
+
+#define SET_DMA_PWC(x)    (((x)&0x3F)<<(13-DMA_CR_OFFSET))     /* Peripheral Wait Cycles */
+#define DMA_PWC_MASK      SET_DMA_PWC(0x3F)
+#define GET_DMA_PWC(x)    (((x)&DMA_PWC_MASK)>>(13-DMA_CR_OFFSET))
+
+#define SET_DMA_PHC(x)    (((x)&0x7)<<(10-DMA_CR_OFFSET))      /* Peripheral Hold Cycles */
+#define DMA_PHC_MASK      SET_DMA_PHC(0x7)
+#define GET_DMA_PHC(x)    (((x)&DMA_PHC_MASK)>>(10-DMA_CR_OFFSET))
+
+#define DMA_ETD_OUTPUT     (1<<(9-DMA_CR_OFFSET))      /* EOT pin is a TC output */
+#define SET_DMA_ETD(x)     (((x)&0x1)<<(9-DMA_CR_OFFSET))
+
+#define DMA_TCE_ENABLE     (1<<(8-DMA_CR_OFFSET))
+#define SET_DMA_TCE(x)     (((x)&0x1)<<(8-DMA_CR_OFFSET))
+
+#define DMA_DEC            (1<<(2)     /* Address Decrement */
+#define SET_DMA_DEC(x)     (((x)&0x1)<<2)
+#define GET_DMA_DEC(x)     (((x)&DMA_DEC)>>2)
+
+/*
+ * Transfer Modes
+ * These modes are defined in a way that makes it possible to
+ * simply "or" in the value in the control register.
+ */
+
+#define DMA_MODE_MM            (SET_DMA_TM(TM_S_MM))   /* memory to memory */
+
+                               /* Device-paced memory to memory, */
+                               /* device is at source address    */
+#define DMA_MODE_MM_DEVATSRC   (DMA_TD | SET_DMA_TM(TM_D_MM))
+
+                               /* Device-paced memory to memory,      */
+                               /* device is at destination address    */
+#define DMA_MODE_MM_DEVATDST   (SET_DMA_TM(TM_D_MM))
+
+/* 405gp/440gp */
+#define SET_DMA_PREFETCH(x)   (((x)&0x3)<<(4-DMA_CR_OFFSET))   /* Memory Read Prefetch */
+#define DMA_PREFETCH_MASK      SET_DMA_PREFETCH(3)
+#define   PREFETCH_1           0       /* Prefetch 1 Double Word */
+#define   PREFETCH_2           1
+#define   PREFETCH_4           2
+#define GET_DMA_PREFETCH(x) (((x)&DMA_PREFETCH_MASK)>>(4-DMA_CR_OFFSET))
+
+#define DMA_PCE            (1<<(3-DMA_CR_OFFSET))      /* Parity Check Enable */
+#define SET_DMA_PCE(x)     (((x)&0x1)<<(3-DMA_CR_OFFSET))
+#define GET_DMA_PCE(x)     (((x)&DMA_PCE)>>(3-DMA_CR_OFFSET))
+
+/* stb3x */
+
+#define DMA_ECE_ENABLE (1<<5)
+#define SET_DMA_ECE(x) (((x)&0x1)<<5)
+#define GET_DMA_ECE(x) (((x)&DMA_ECE_ENABLE)>>5)
+
+#define DMA_TCD_DISABLE        (1<<4)
+#define SET_DMA_TCD(x) (((x)&0x1)<<4)
+#define GET_DMA_TCD(x) (((x)&DMA_TCD_DISABLE)>>4)
+
+typedef uint32_t sgl_handle_t;
+
+#ifdef CONFIG_PPC4xx_EDMA
+
+#define SGL_LIST_SIZE 4096
+#define DMA_PPC4xx_SIZE SGL_LIST_SIZE
+
+#define SET_DMA_PRIORITY(x)   (((x)&0x3)<<(6-DMA_CR_OFFSET))   /* DMA Channel Priority */
+#define DMA_PRIORITY_MASK SET_DMA_PRIORITY(3)
+#define PRIORITY_LOW           0
+#define PRIORITY_MID_LOW       1
+#define PRIORITY_MID_HIGH      2
+#define PRIORITY_HIGH          3
+#define GET_DMA_PRIORITY(x) (((x)&DMA_PRIORITY_MASK)>>(6-DMA_CR_OFFSET))
+
+/*
+ * DMA Polarity Configuration Register
+ */
+#define DMAReq_ActiveLow(chan) (1<<(31-(chan*3)))
+#define DMAAck_ActiveLow(chan) (1<<(30-(chan*3)))
+#define EOT_ActiveLow(chan)    (1<<(29-(chan*3)))      /* End of Transfer */
+
+/*
+ * DMA Sleep Mode Register
+ */
+#define SLEEP_MODE_ENABLE (1<<21)
+
+/*
+ * DMA Status Register
+ */
+#define DMA_CS0           (1<<31)      /* Terminal Count has been reached */
+#define DMA_CS1           (1<<30)
+#define DMA_CS2           (1<<29)
+#define DMA_CS3           (1<<28)
+
+#define DMA_TS0           (1<<27)      /* End of Transfer has been requested */
+#define DMA_TS1           (1<<26)
+#define DMA_TS2           (1<<25)
+#define DMA_TS3           (1<<24)
+
+#define DMA_CH0_ERR       (1<<23)      /* DMA Chanel 0 Error */
+#define DMA_CH1_ERR       (1<<22)
+#define DMA_CH2_ERR       (1<<21)
+#define DMA_CH3_ERR       (1<<20)
+
+#define DMA_IN_DMA_REQ0   (1<<19)      /* Internal DMA Request is pending */
+#define DMA_IN_DMA_REQ1   (1<<18)
+#define DMA_IN_DMA_REQ2   (1<<17)
+#define DMA_IN_DMA_REQ3   (1<<16)
+
+#define DMA_EXT_DMA_REQ0  (1<<15)      /* External DMA Request is pending */
+#define DMA_EXT_DMA_REQ1  (1<<14)
+#define DMA_EXT_DMA_REQ2  (1<<13)
+#define DMA_EXT_DMA_REQ3  (1<<12)
+
+#define DMA_CH0_BUSY      (1<<11)      /* DMA Channel 0 Busy */
+#define DMA_CH1_BUSY      (1<<10)
+#define DMA_CH2_BUSY       (1<<9)
+#define DMA_CH3_BUSY       (1<<8)
+
+#define DMA_SG0            (1<<7)      /* DMA Channel 0 Scatter/Gather in progress */
+#define DMA_SG1            (1<<6)
+#define DMA_SG2            (1<<5)
+#define DMA_SG3            (1<<4)
+
+/*
+ * DMA SG Command Register
+ */
+#define SSG_ENABLE(chan)       (1<<(31-chan))  /* Start Scatter Gather */
+#define SSG_MASK_ENABLE(chan)  (1<<(15-chan))  /* Enable writing to SSG0 bit */
+
+/*
+ * DMA Scatter/Gather Descriptor Bit fields
+ */
+#define SG_LINK            (1<<31)     /* Link */
+#define SG_TCI_ENABLE      (1<<29)     /* Enable Terminal Count Interrupt */
+#define SG_ETI_ENABLE      (1<<28)     /* Enable End of Transfer Interrupt */
+#define SG_ERI_ENABLE      (1<<27)     /* Enable Error Interrupt */
+#define SG_COUNT_MASK       0xFFFF     /* Count Field */
+
+#define SET_DMA_CONTROL \
+               (SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */ \
+               SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */\
+               SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */ \
+               SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */ \
+                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */ \
+                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */ \
+                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */ \
+                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */ \
+                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
+                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
+                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
+                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
+                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */)
+
+#define GET_DMA_POLARITY(chan) (DMAReq_ActiveLow(chan) | DMAAck_ActiveLow(chan) | EOT_ActiveLow(chan))
+
+#elif defined(CONFIG_STBXXX_DMA)               /* stb03xxx */
+
+#define DMA_PPC4xx_SIZE        4096
+
+/*
+ * DMA Status Register
+ */
+
+#define SET_DMA_PRIORITY(x)   (((x)&0x00800001))       /* DMA Channel Priority */
+#define DMA_PRIORITY_MASK      0x00800001
+#define   PRIORITY_LOW                 0x00000000
+#define   PRIORITY_MID_LOW             0x00000001
+#define   PRIORITY_MID_HIGH            0x00800000
+#define   PRIORITY_HIGH                0x00800001
+#define GET_DMA_PRIORITY(x) (((((x)&DMA_PRIORITY_MASK) &0x00800000) >> 22 ) | (((x)&DMA_PRIORITY_MASK) &0x00000001))
+
+#define DMA_CS0           (1<<31)      /* Terminal Count has been reached */
+#define DMA_CS1           (1<<30)
+#define DMA_CS2           (1<<29)
+#define DMA_CS3           (1<<28)
+
+#define DMA_TS0           (1<<27)      /* End of Transfer has been requested */
+#define DMA_TS1           (1<<26)
+#define DMA_TS2           (1<<25)
+#define DMA_TS3           (1<<24)
+
+#define DMA_CH0_ERR       (1<<23)      /* DMA Chanel 0 Error */
+#define DMA_CH1_ERR       (1<<22)
+#define DMA_CH2_ERR       (1<<21)
+#define DMA_CH3_ERR       (1<<20)
+
+#define DMA_CT0                  (1<<19)       /* Chained transfere */
+
+#define DMA_IN_DMA_REQ0   (1<<18)      /* Internal DMA Request is pending */
+#define DMA_IN_DMA_REQ1   (1<<17)
+#define DMA_IN_DMA_REQ2   (1<<16)
+#define DMA_IN_DMA_REQ3   (1<<15)
+
+#define DMA_EXT_DMA_REQ0  (1<<14)      /* External DMA Request is pending */
+#define DMA_EXT_DMA_REQ1  (1<<13)
+#define DMA_EXT_DMA_REQ2  (1<<12)
+#define DMA_EXT_DMA_REQ3  (1<<11)
+
+#define DMA_CH0_BUSY      (1<<10)      /* DMA Channel 0 Busy */
+#define DMA_CH1_BUSY      (1<<9)
+#define DMA_CH2_BUSY       (1<<8)
+#define DMA_CH3_BUSY       (1<<7)
+
+#define DMA_CT1            (1<<6)      /* Chained transfere */
+#define DMA_CT2            (1<<5)
+#define DMA_CT3            (1<<4)
+
+#define DMA_CH_ENABLE (1<<7)
+#define SET_DMA_CH(x) (((x)&0x1)<<7)
+#define GET_DMA_CH(x) (((x)&DMA_CH_ENABLE)>>7)
+
+/* STBx25xxx dma unique */
+/* enable device port on a dma channel
+ * example ext 0 on dma 1
+ */
+
+#define        SSP0_RECV       15
+#define        SSP0_XMIT       14
+#define EXT_DMA_0      12
+#define        SC1_XMIT        11
+#define SC1_RECV       10
+#define EXT_DMA_2      9
+#define        EXT_DMA_3       8
+#define SERIAL2_XMIT   7
+#define SERIAL2_RECV   6
+#define SC0_XMIT       5
+#define        SC0_RECV        4
+#define        SERIAL1_XMIT    3
+#define SERIAL1_RECV   2
+#define        SERIAL0_XMIT    1
+#define SERIAL0_RECV   0
+
+#define DMA_CHAN_0     1
+#define DMA_CHAN_1     2
+#define DMA_CHAN_2     3
+#define DMA_CHAN_3     4
+
+/* end STBx25xx */
+
+/*
+ * Bit 30 must be one for Redwoods, otherwise transfers may receive errors.
+ */
+#define DMA_CR_MB0 0x2
+
+#define SET_DMA_CONTROL \
+                       (SET_DMA_CIE_ENABLE(p_init->int_enable) |  /* interrupt enable         */ \
+               SET_DMA_ETD(p_init->etd_output)        |  /* end of transfer pin      */ \
+               SET_DMA_TCE(p_init->tce_enable)        |  /* terminal count enable    */ \
+               SET_DMA_PL(p_init->pl)                 |  /* peripheral location      */ \
+               SET_DMA_DAI(p_init->dai)               |  /* dest addr increment      */ \
+               SET_DMA_SAI(p_init->sai)               |  /* src addr increment       */ \
+               SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */  \
+               SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
+               SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
+               SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
+               SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
+               SET_DMA_TCD(p_init->tcd_disable)          |  /* TC chain mode disable   */ \
+               SET_DMA_ECE(p_init->ece_enable)   |  /* ECE chanin mode enable  */ \
+               SET_DMA_CH(p_init->ch_enable)   |    /* Chain enable            */ \
+               DMA_CR_MB0                              /* must be one */)
+
+#define GET_DMA_POLARITY(chan) chan
+
+#endif
+
+typedef struct {
+       unsigned short in_use;  /* set when channel is being used, clr when
+                                * available.
+                                */
+       /*
+        * Valid polarity settings:
+        *   DMAReq_ActiveLow(n)
+        *   DMAAck_ActiveLow(n)
+        *   EOT_ActiveLow(n)
+        *
+        *   n is 0 to max dma chans
+        */
+       unsigned int polarity;
+
+       char buffer_enable;     /* Boolean: buffer enable            */
+       char tce_enable;        /* Boolean: terminal count enable    */
+       char etd_output;        /* Boolean: eot pin is a tc output   */
+       char pce;               /* Boolean: parity check enable      */
+
+       /*
+        * Peripheral location:
+        * INTERNAL_PERIPHERAL (UART0 on the 405GP)
+        * EXTERNAL_PERIPHERAL
+        */
+       char pl;                /* internal/external peripheral      */
+
+       /*
+        * Valid pwidth settings:
+        *   PW_8
+        *   PW_16
+        *   PW_32
+        *   PW_64
+        */
+       unsigned int pwidth;
+
+       char dai;               /* Boolean: dst address increment   */
+       char sai;               /* Boolean: src address increment   */
+
+       /*
+        * Valid psc settings: 0-3
+        */
+       unsigned int psc;       /* Peripheral Setup Cycles         */
+
+       /*
+        * Valid pwc settings:
+        * 0-63
+        */
+       unsigned int pwc;       /* Peripheral Wait Cycles          */
+
+       /*
+        * Valid phc settings:
+        * 0-7
+        */
+       unsigned int phc;       /* Peripheral Hold Cycles          */
+
+       /*
+        * Valid cp (channel priority) settings:
+        *   PRIORITY_LOW
+        *   PRIORITY_MID_LOW
+        *   PRIORITY_MID_HIGH
+        *   PRIORITY_HIGH
+        */
+       unsigned int cp;        /* channel priority                */
+
+       /*
+        * Valid pf (memory read prefetch) settings:
+        *
+        *   PREFETCH_1
+        *   PREFETCH_2
+        *   PREFETCH_4
+        */
+       unsigned int pf;        /* memory read prefetch            */
+
+       /*
+        * Boolean: channel interrupt enable
+        * NOTE: for sgl transfers, only the last descriptor will be setup to
+        * interrupt.
+        */
+       char int_enable;
+
+       char shift;             /* easy access to byte_count shift, based on */
+       /* the width of the channel                  */
+
+       uint32_t control;       /* channel control word                      */
+
+       /* These variabled are used ONLY in single dma transfers              */
+       unsigned int mode;      /* transfer mode                     */
+       phys_addr_t addr;
+       char ce;                /* channel enable */
+#ifdef CONFIG_STB03xxx
+       char ch_enable;
+       char tcd_disable;
+       char ece_enable;
+       char td;                /* transfer direction */
+#endif
+
+} ppc_dma_ch_t;
+
+/*
+ * PPC44x DMA implementations have a slightly different
+ * descriptor layout.  Probably moved about due to the
+ * change to 64-bit addresses and link pointer. I don't
+ * know why they didn't just leave control_count after
+ * the dst_addr.
+ */
+#ifdef PPC4xx_DMA_64BIT
+typedef struct {
+       uint32_t control;
+       uint32_t control_count;
+       phys_addr_t src_addr;
+       phys_addr_t dst_addr;
+       phys_addr_t next;
+} ppc_sgl_t;
+#else
+typedef struct {
+       uint32_t control;
+       phys_addr_t src_addr;
+       phys_addr_t dst_addr;
+       uint32_t control_count;
+       uint32_t next;
+} ppc_sgl_t;
+#endif
+
+typedef struct {
+       unsigned int dmanr;
+       uint32_t control;       /* channel ctrl word; loaded from each descrptr */
+       uint32_t sgl_control;   /* LK, TCI, ETI, and ERI bits in sgl descriptor */
+       dma_addr_t dma_addr;    /* dma (physical) address of this list          */
+       ppc_sgl_t *phead;
+       dma_addr_t phead_dma;
+       ppc_sgl_t *ptail;
+       dma_addr_t ptail_dma;
+} sgl_list_info_t;
+
+typedef struct {
+       phys_addr_t *src_addr;
+       phys_addr_t *dst_addr;
+       phys_addr_t dma_src_addr;
+       phys_addr_t dma_dst_addr;
+} pci_alloc_desc_t;
+
+extern ppc_dma_ch_t dma_channels[];
+
+/*
+ * The DMA API are in ppc4xx_dma.c and ppc4xx_sgdma.c
+ */
+extern int ppc4xx_init_dma_channel(unsigned int, ppc_dma_ch_t *);
+extern int ppc4xx_get_channel_config(unsigned int, ppc_dma_ch_t *);
+extern int ppc4xx_set_channel_priority(unsigned int, unsigned int);
+extern unsigned int ppc4xx_get_peripheral_width(unsigned int);
+extern void ppc4xx_set_sg_addr(int, phys_addr_t);
+extern int ppc4xx_add_dma_sgl(sgl_handle_t, phys_addr_t, phys_addr_t, unsigned int);
+extern void ppc4xx_enable_dma_sgl(sgl_handle_t);
+extern void ppc4xx_disable_dma_sgl(sgl_handle_t);
+extern int ppc4xx_get_dma_sgl_residue(sgl_handle_t, phys_addr_t *, phys_addr_t *);
+extern int ppc4xx_delete_dma_sgl_element(sgl_handle_t, phys_addr_t *, phys_addr_t *);
+extern int ppc4xx_alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);
+extern void ppc4xx_free_dma_handle(sgl_handle_t);
+extern int ppc4xx_get_dma_status(void);
+extern void ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr);
+extern void ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr);
+extern void ppc4xx_enable_dma(unsigned int dmanr);
+extern void ppc4xx_disable_dma(unsigned int dmanr);
+extern void ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count);
+extern int ppc4xx_get_dma_residue(unsigned int dmanr);
+extern void ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
+                                phys_addr_t dst_dma_addr);
+extern int ppc4xx_enable_dma_interrupt(unsigned int dmanr);
+extern int ppc4xx_disable_dma_interrupt(unsigned int dmanr);
+extern int ppc4xx_clr_dma_status(unsigned int dmanr);
+extern int ppc4xx_map_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
+extern int ppc4xx_disable_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
+extern int ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode);
+
+/* These are in kernel/dma.c: */
+
+/* reserve a DMA channel */
+extern int request_dma(unsigned int dmanr, const char *device_id);
+/* release it again */
+extern void free_dma(unsigned int dmanr);
+#endif
+#endif                         /* __KERNEL__ */
diff --git a/include/asm-ppc64/hvcserver.h b/include/asm-ppc64/hvcserver.h
new file mode 100644 (file)
index 0000000..cee9a14
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * hvcserver.h
+ * Copyright (C) 2004 Ryan S Arnold, IBM Corporation
+ *
+ * PPC64 virtual I/O console server support.
+ *
+ * This program is free software; 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 _PPC64_HVCSERVER_H
+#define _PPC64_HVCSERVER_H
+
+#include <linux/list.h>
+
+/* Converged Location Code length */
+#define HVCS_CLC_LENGTH        79
+
+struct hvcs_partner_info {
+       struct list_head node;
+       unsigned int unit_address;
+       unsigned int partition_ID;
+       char location_code[HVCS_CLC_LENGTH + 1]; /* CLC + 1 null-term char */
+};
+
+extern int hvcs_free_partner_info(struct list_head *head);
+extern int hvcs_get_partner_info(unsigned int unit_address,
+               struct list_head *head, unsigned long *pi_buff);
+extern int hvcs_register_connection(unsigned int unit_address,
+               unsigned int p_partition_ID, unsigned int p_unit_address);
+extern int hvcs_free_connection(unsigned int unit_address);
+
+#endif /* _PPC64_HVCSERVER_H */
diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h
new file mode 100644 (file)
index 0000000..27b9af1
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef __ASM_SH64_PAGE_H
+#define __ASM_SH64_PAGE_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * include/asm-sh64/page.h
+ *
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003, 2004  Paul Mundt
+ *
+ * benedict.gaster@superh.com 19th, 24th July 2002.
+ *
+ * Modified to take account of enabling for D-CACHE support.
+ *
+ */
+
+#include <linux/config.h>
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT     12
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE      4096
+#else
+#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#endif
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+#define PTE_MASK       PAGE_MASK
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+#define HPAGE_SHIFT    16
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+#define HPAGE_SHIFT    20
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB)
+#define HPAGE_SHIFT    29
+#endif
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HPAGE_SIZE             (1UL << HPAGE_SHIFT)
+#define HPAGE_MASK             (~(HPAGE_SIZE-1))
+#define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT-PAGE_SHIFT)
+#endif
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+extern struct page *mem_map;
+extern void sh64_page_clear(void *page);
+extern void sh64_page_copy(void *from, void *to);
+
+#define clear_page(page)               sh64_page_clear(page)
+#define copy_page(to,from)             sh64_page_copy(from, to)
+
+#if defined(CONFIG_DCACHE_DISABLED)
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+#else
+
+extern void clear_user_page(void *to, unsigned long address, struct page *pg);
+extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
+
+#endif /* defined(CONFIG_DCACHE_DISABLED) */
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)     ((x).pte)
+#define pmd_val(x)     ((x).pmd)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
+
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/*
+ * Kconfig defined.
+ */
+#define __MEMORY_START         (CONFIG_MEMORY_START)
+#define PAGE_OFFSET            (CONFIG_CACHED_MEMORY_OFFSET)
+
+#define __pa(x)                        ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x)                        ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define MAP_NR(addr)           ((__pa(addr)-__MEMORY_START) >> PAGE_SHIFT)
+#define VALID_PAGE(page)       ((page - mem_map) < max_mapnr)
+
+#define phys_to_page(phys)     (mem_map + (((phys) - __MEMORY_START) >> PAGE_SHIFT))
+#define page_to_phys(page)     (((page - mem_map) << PAGE_SHIFT) + __MEMORY_START)
+
+/* PFN start number, because of __MEMORY_START */
+#define PFN_START              (__MEMORY_START >> PAGE_SHIFT)
+
+#define pfn_to_page(pfn)       (mem_map + (pfn) - PFN_START)
+#define page_to_pfn(page)      ((unsigned long)((page) - mem_map) + PFN_START)
+#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_valid(pfn)         (((pfn) - PFN_START) < max_mapnr)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#ifndef __ASSEMBLY__
+
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+       int order;
+
+       size = (size-1) >> (PAGE_SHIFT-1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+
+#endif
+
+#define devmem_is_allowed(x) 1
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH64_PAGE_H */
diff --git a/include/asm-um/cpufeature.h b/include/asm-um/cpufeature.h
new file mode 100644 (file)
index 0000000..fb7bd42
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __UM_CPUFEATURE_H
+#define __UM_CPUFEATURE_H
+
+#include "asm/arch/cpufeature.h"
+
+#endif
diff --git a/include/asm-um/local.h b/include/asm-um/local.h
new file mode 100644 (file)
index 0000000..9a280c5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __UM_LOCAL_H
+#define __UM_LOCAL_H
+
+#include "asm/arch/local.h"
+
+#endif
diff --git a/include/asm-um/module-generic.h b/include/asm-um/module-generic.h
new file mode 100644 (file)
index 0000000..5a265f5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __UM_MODULE_GENERIC_H
+#define __UM_MODULE_GENERIC_H
+
+#include "asm/arch/module.h"
+
+#endif
diff --git a/include/asm-um/module-i386.h b/include/asm-um/module-i386.h
new file mode 100644 (file)
index 0000000..5ead4a0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __UM_MODULE_I386_H
+#define __UM_MODULE_I386_H
+
+/* UML is simple */
+struct mod_arch_specific
+{
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif
diff --git a/include/asm-um/sections.h b/include/asm-um/sections.h
new file mode 100644 (file)
index 0000000..6b0231e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _UM_SECTIONS_H
+#define _UM_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/include/linux/ghash.h b/include/linux/ghash.h
new file mode 100644 (file)
index 0000000..a247988
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * include/linux/ghash.h -- generic hashing with fuzzy retrieval
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ *
+ * The algorithms implemented here seem to be a completely new invention,
+ * and I'll publish the fundamentals in a paper.
+ */
+
+#ifndef _GHASH_H
+#define _GHASH_H
+/* HASHSIZE _must_ be a power of two!!! */
+
+
+#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+       TYPE * hashtable[HASHSIZE];\
+       TYPE * sorted_list;\
+       int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+       TYPE * next_hash;\
+       TYPE * prev_hash;\
+       TYPE * next_sorted;\
+       TYPE * prev_sorted;\
+};
+
+#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       int ix = HASHFN(elem->KEY);\
+       TYPE ** base = &tbl->hashtable[ix];\
+       TYPE * ptr = *base;\
+       TYPE * prev = NULL;\
+\
+       tbl->nr_entries++;\
+       while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+               base = &ptr->PTRS.next_hash;\
+               prev = ptr;\
+               ptr = *base;\
+       }\
+       elem->PTRS.next_hash = ptr;\
+       elem->PTRS.prev_hash = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_hash = elem;\
+       }\
+       *base = elem;\
+\
+       ptr = prev;\
+       if(!ptr) {\
+               ptr = tbl->sorted_list;\
+               prev = NULL;\
+       } else {\
+               prev = ptr->PTRS.prev_sorted;\
+       }\
+       while(ptr) {\
+               TYPE * next = ptr->PTRS.next_hash;\
+               if(next && KEYCMP(next->KEY, elem->KEY)) {\
+                       prev = ptr;\
+                       ptr = next;\
+               } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
+                       prev = ptr;\
+                       ptr = ptr->PTRS.next_sorted;\
+               } else\
+                       break;\
+       }\
+       elem->PTRS.next_sorted = ptr;\
+       elem->PTRS.prev_sorted = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_sorted = elem;\
+       }\
+       if(prev) {\
+               prev->PTRS.next_sorted = elem;\
+       } else {\
+               tbl->sorted_list = elem;\
+       }\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       TYPE * next = elem->PTRS.next_hash;\
+       TYPE * prev = elem->PTRS.prev_hash;\
+\
+       tbl->nr_entries--;\
+       if(next)\
+               next->PTRS.prev_hash = prev;\
+       if(prev)\
+               prev->PTRS.next_hash = next;\
+       else {\
+               int ix = HASHFN(elem->KEY);\
+               tbl->hashtable[ix] = next;\
+       }\
+\
+       next = elem->PTRS.next_sorted;\
+       prev = elem->PTRS.prev_sorted;\
+       if(next)\
+               next->PTRS.prev_sorted = prev;\
+       if(prev)\
+               prev->PTRS.next_sorted = next;\
+       else\
+               tbl->sorted_list = next;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix = hashfn(pos);\
+       TYPE * ptr = tbl->hashtable[ix];\
+       while(ptr && KEYCMP(ptr->KEY, pos))\
+               ptr = ptr->PTRS.next_hash;\
+       if(ptr && !KEYEQ(ptr->KEY, pos))\
+               ptr = NULL;\
+       return ptr;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix;\
+       int offset;\
+       TYPE * ptr;\
+       TYPE * next;\
+\
+       ptr = tbl->sorted_list;\
+       if(!ptr || KEYCMP(pos, ptr->KEY))\
+               return NULL;\
+       ix = HASHFN(pos);\
+       offset = HASHSIZE;\
+       do {\
+               offset >>= 1;\
+               next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
+               if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
+                  && KEYCMP(ptr->KEY, next->KEY))\
+                       ptr = next;\
+       } while(offset);\
+\
+       for(;;) {\
+               next = ptr->PTRS.next_hash;\
+               if(next) {\
+                       if(KEYCMP(next->KEY, pos)) {\
+                               ptr = next;\
+                               continue;\
+                       }\
+               }\
+               next = ptr->PTRS.next_sorted;\
+               if(next && KEYCMP(next->KEY, pos)) {\
+                       ptr = next;\
+                       continue;\
+               }\
+               return ptr;\
+       }\
+       return NULL;\
+}
+
+/* LINKAGE - empty or "static", depending on whether you want the definitions to
+ *     be public or not
+ * NAME - a string to stick in names to make this hash table type distinct from
+ *     any others
+ * HASHSIZE - number of buckets
+ * TYPE - type of data contained in the buckets - must be a structure, one 
+ *     field is of type NAME_ptrs, another is the hash key
+ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
+ *     field
+ * KEYTYPE - type of the key field within TYPE
+ * KEY - name of the key field within TYPE
+ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
+ *     prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, 
+ *     non-zero for not equal
+ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
+ *     it returns a number in the range 0 ... HASHSIZE - 1
+ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
+ * DEF_HASH.
+ */
+
+#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+       TYPE * hashtable[HASHSIZE];\
+       int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+       TYPE * next_hash;\
+       TYPE * prev_hash;\
+};
+
+#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       int ix = HASHFN(elem->KEY);\
+       TYPE ** base = &tbl->hashtable[ix];\
+       TYPE * ptr = *base;\
+       TYPE * prev = NULL;\
+\
+       tbl->nr_entries++;\
+       while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+               base = &ptr->PTRS.next_hash;\
+               prev = ptr;\
+               ptr = *base;\
+       }\
+       elem->PTRS.next_hash = ptr;\
+       elem->PTRS.prev_hash = prev;\
+       if(ptr) {\
+               ptr->PTRS.prev_hash = elem;\
+       }\
+       *base = elem;\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+       TYPE * next = elem->PTRS.next_hash;\
+       TYPE * prev = elem->PTRS.prev_hash;\
+\
+       tbl->nr_entries--;\
+       if(next)\
+               next->PTRS.prev_hash = prev;\
+       if(prev)\
+               prev->PTRS.next_hash = next;\
+       else {\
+               int ix = HASHFN(elem->KEY);\
+               tbl->hashtable[ix] = next;\
+       }\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+       int ix = HASHFN(pos);\
+       TYPE * ptr = tbl->hashtable[ix];\
+       while(ptr && KEYCMP(ptr->KEY, pos))\
+               ptr = ptr->PTRS.next_hash;\
+       return ptr;\
+}
+
+#endif
diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h
new file mode 100644 (file)
index 0000000..05aa497
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * For boards with physically mapped flash and using 
+ * drivers/mtd/maps/physmap.c mapping driver.
+ *
+ * $Id: physmap.h,v 1.3 2004/07/21 00:16:15 jwboyer Exp $
+ *
+ * Copyright (C) 2003 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; 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.
+ *
+ */
+
+#ifndef __LINUX_MTD_PHYSMAP__
+
+#include <linux/config.h>
+
+#if defined(CONFIG_MTD_PHYSMAP) 
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+/*
+ * The map_info for physmap.  Board can override size, buswidth, phys,
+ * (*set_vpp)(), etc in their initial setup routine.
+ */
+extern struct map_info physmap_map;
+
+/*
+ * Board needs to specify the exact mapping during their setup time.
+ */
+static inline void physmap_configure(unsigned long addr, unsigned long size, int bankwidth, void (*set_vpp)(struct map_info *, int) )
+{
+       physmap_map.phys = addr;
+       physmap_map.size = size;
+       physmap_map.bankwidth = bankwidth;
+       physmap_map.set_vpp = set_vpp;
+}
+
+#if defined(CONFIG_MTD_PARTITIONS)
+
+/*
+ * Machines that wish to do flash partition may want to call this function in 
+ * their setup routine.  
+ *
+ *     physmap_set_partitions(mypartitions, num_parts);
+ *
+ * Note that one can always override this hard-coded partition with 
+ * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS).
+ */
+void physmap_set_partitions(struct mtd_partition *parts, int num_parts);
+
+#endif /* defined(CONFIG_MTD_PARTITIONS) */
+#endif /* defined(CONFIG_MTD) */
+
+#endif /* __LINUX_MTD_PHYSMAP__ */
+
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
new file mode 100644 (file)
index 0000000..0fbec88
--- /dev/null
@@ -0,0 +1,310 @@
+/* PPTP constants and structs */
+#ifndef _CONNTRACK_PPTP_H
+#define _CONNTRACK_PPTP_H
+
+/* state of the control session */
+enum pptp_ctrlsess_state {
+       PPTP_SESSION_NONE,                      /* no session present */
+       PPTP_SESSION_ERROR,                     /* some session error */
+       PPTP_SESSION_STOPREQ,                   /* stop_sess request seen */
+       PPTP_SESSION_REQUESTED,                 /* start_sess request seen */
+       PPTP_SESSION_CONFIRMED,                 /* session established */
+};
+
+/* state of the call inside the control session */
+enum pptp_ctrlcall_state {
+       PPTP_CALL_NONE,
+       PPTP_CALL_ERROR,
+       PPTP_CALL_OUT_REQ,
+       PPTP_CALL_OUT_CONF,
+       PPTP_CALL_IN_REQ,
+       PPTP_CALL_IN_REP,
+       PPTP_CALL_IN_CONF,
+       PPTP_CALL_CLEAR_REQ,
+};
+
+
+/* conntrack private data */
+struct ip_ct_pptp_master {
+       enum pptp_ctrlsess_state sstate;        /* session state */
+
+       /* everything below is going to be per-expectation in newnat,
+        * since there could be more than one call within one session */
+       enum pptp_ctrlcall_state cstate;        /* call state */
+       u_int16_t pac_call_id;                  /* call id of PAC, host byte order */
+       u_int16_t pns_call_id;                  /* call id of PNS, host byte order */
+};
+
+/* conntrack_expect private member */
+struct ip_ct_pptp_expect {
+       enum pptp_ctrlcall_state cstate;        /* call state */
+       u_int16_t pac_call_id;                  /* call id of PAC */
+       u_int16_t pns_call_id;                  /* call id of PNS */
+};
+
+
+#ifdef __KERNEL__
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+DECLARE_LOCK_EXTERN(ip_pptp_lock);
+
+#define IP_CONNTR_PPTP         PPTP_CONTROL_PORT
+
+#define PPTP_CONTROL_PORT      1723
+
+#define PPTP_PACKET_CONTROL    1
+#define PPTP_PACKET_MGMT       2
+
+#define PPTP_MAGIC_COOKIE      0x1a2b3c4d
+
+struct pptp_pkt_hdr {
+       __u16   packetLength;
+       __u16   packetType;
+       __u32   magicCookie;
+};
+
+/* PptpControlMessageType values */
+#define PPTP_START_SESSION_REQUEST     1
+#define PPTP_START_SESSION_REPLY       2
+#define PPTP_STOP_SESSION_REQUEST      3
+#define PPTP_STOP_SESSION_REPLY                4
+#define PPTP_ECHO_REQUEST              5
+#define PPTP_ECHO_REPLY                        6
+#define PPTP_OUT_CALL_REQUEST          7
+#define PPTP_OUT_CALL_REPLY            8
+#define PPTP_IN_CALL_REQUEST           9
+#define PPTP_IN_CALL_REPLY             10
+#define PPTP_IN_CALL_CONNECT           11
+#define PPTP_CALL_CLEAR_REQUEST                12
+#define PPTP_CALL_DISCONNECT_NOTIFY    13
+#define PPTP_WAN_ERROR_NOTIFY          14
+#define PPTP_SET_LINK_INFO             15
+
+#define PPTP_MSG_MAX                   15
+
+/* PptpGeneralError values */
+#define PPTP_ERROR_CODE_NONE           0
+#define PPTP_NOT_CONNECTED             1
+#define PPTP_BAD_FORMAT                        2
+#define PPTP_BAD_VALUE                 3
+#define PPTP_NO_RESOURCE               4
+#define PPTP_BAD_CALLID                        5
+#define PPTP_REMOVE_DEVICE_ERROR       6
+
+struct PptpControlHeader {
+       __u16   messageType;
+       __u16   reserved;
+};
+
+/* FramingCapability Bitmap Values */
+#define PPTP_FRAME_CAP_ASYNC           0x1
+#define PPTP_FRAME_CAP_SYNC            0x2
+
+/* BearerCapability Bitmap Values */
+#define PPTP_BEARER_CAP_ANALOG         0x1
+#define PPTP_BEARER_CAP_DIGITAL                0x2
+
+struct PptpStartSessionRequest {
+       __u16   protocolVersion;
+       __u8    reserved1;
+       __u8    reserved2;
+       __u32   framingCapability;
+       __u32   bearerCapability;
+       __u16   maxChannels;
+       __u16   firmwareRevision;
+       __u8    hostName[64];
+       __u8    vendorString[64];
+};
+
+/* PptpStartSessionResultCode Values */
+#define PPTP_START_OK                  1
+#define PPTP_START_GENERAL_ERROR       2
+#define PPTP_START_ALREADY_CONNECTED   3
+#define PPTP_START_NOT_AUTHORIZED      4
+#define PPTP_START_UNKNOWN_PROTOCOL    5
+
+struct PptpStartSessionReply {
+       __u16   protocolVersion;
+       __u8    resultCode;
+       __u8    generalErrorCode;
+       __u32   framingCapability;
+       __u32   bearerCapability;
+       __u16   maxChannels;
+       __u16   firmwareRevision;
+       __u8    hostName[64];
+       __u8    vendorString[64];
+};
+
+/* PptpStopReasons */
+#define PPTP_STOP_NONE                 1
+#define PPTP_STOP_PROTOCOL             2
+#define PPTP_STOP_LOCAL_SHUTDOWN       3
+
+struct PptpStopSessionRequest {
+       __u8    reason;
+};
+
+/* PptpStopSessionResultCode */
+#define PPTP_STOP_OK                   1
+#define PPTP_STOP_GENERAL_ERROR                2
+
+struct PptpStopSessionReply {
+       __u8    resultCode;
+       __u8    generalErrorCode;
+};
+
+struct PptpEchoRequest {
+       __u32 identNumber;
+};
+
+/* PptpEchoReplyResultCode */
+#define PPTP_ECHO_OK                   1
+#define PPTP_ECHO_GENERAL_ERROR                2
+
+struct PptpEchoReply {
+       __u32   identNumber;
+       __u8    resultCode;
+       __u8    generalErrorCode;
+       __u16   reserved;
+};
+
+/* PptpFramingType */
+#define PPTP_ASYNC_FRAMING             1
+#define PPTP_SYNC_FRAMING              2
+#define PPTP_DONT_CARE_FRAMING         3
+
+/* PptpCallBearerType */
+#define PPTP_ANALOG_TYPE               1
+#define PPTP_DIGITAL_TYPE              2
+#define PPTP_DONT_CARE_BEARER_TYPE     3
+
+struct PptpOutCallRequest {
+       __u16   callID;
+       __u16   callSerialNumber;
+       __u32   minBPS;
+       __u32   maxBPS;
+       __u32   bearerType;
+       __u32   framingType;
+       __u16   packetWindow;
+       __u16   packetProcDelay;
+       __u16   reserved1;
+       __u16   phoneNumberLength;
+       __u16   reserved2;
+       __u8    phoneNumber[64];
+       __u8    subAddress[64];
+};
+
+/* PptpCallResultCode */
+#define PPTP_OUTCALL_CONNECT           1
+#define PPTP_OUTCALL_GENERAL_ERROR     2
+#define PPTP_OUTCALL_NO_CARRIER                3
+#define PPTP_OUTCALL_BUSY              4
+#define PPTP_OUTCALL_NO_DIAL_TONE      5
+#define PPTP_OUTCALL_TIMEOUT           6
+#define PPTP_OUTCALL_DONT_ACCEPT       7
+
+struct PptpOutCallReply {
+       __u16   callID;
+       __u16   peersCallID;
+       __u8    resultCode;
+       __u8    generalErrorCode;
+       __u16   causeCode;
+       __u32   connectSpeed;
+       __u16   packetWindow;
+       __u16   packetProcDelay;
+       __u32   physChannelID;
+};
+
+struct PptpInCallRequest {
+       __u16   callID;
+       __u16   callSerialNumber;
+       __u32   callBearerType;
+       __u32   physChannelID;
+       __u16   dialedNumberLength;
+       __u16   dialingNumberLength;
+       __u8    dialedNumber[64];
+       __u8    dialingNumber[64];
+       __u8    subAddress[64];
+};
+
+/* PptpInCallResultCode */
+#define PPTP_INCALL_ACCEPT             1
+#define PPTP_INCALL_GENERAL_ERROR      2
+#define PPTP_INCALL_DONT_ACCEPT                3
+
+struct PptpInCallReply {
+       __u16   callID;
+       __u16   peersCallID;
+       __u8    resultCode;
+       __u8    generalErrorCode;
+       __u16   packetWindow;
+       __u16   packetProcDelay;
+       __u16   reserved;
+};
+
+struct PptpInCallConnected {
+       __u16   peersCallID;
+       __u16   reserved;
+       __u32   connectSpeed;
+       __u16   packetWindow;
+       __u16   packetProcDelay;
+       __u32   callFramingType;
+};
+
+struct PptpClearCallRequest {
+       __u16   callID;
+       __u16   reserved;
+};
+
+struct PptpCallDisconnectNotify {
+       __u16   callID;
+       __u8    resultCode;
+       __u8    generalErrorCode;
+       __u16   causeCode;
+       __u16   reserved;
+       __u8    callStatistics[128];
+};
+
+struct PptpWanErrorNotify {
+       __u16   peersCallID;
+       __u16   reserved;
+       __u32   crcErrors;
+       __u32   framingErrors;
+       __u32   hardwareOverRuns;
+       __u32   bufferOverRuns;
+       __u32   timeoutErrors;
+       __u32   alignmentErrors;
+};
+
+struct PptpSetLinkInfo {
+       __u16   peersCallID;
+       __u16   reserved;
+       __u32   sendAccm;
+       __u32   recvAccm;
+};
+
+
+struct pptp_priv_data {
+       __u16   call_id;
+       __u16   mcall_id;
+       __u16   pcall_id;
+};
+
+union pptp_ctrl_union {
+               struct PptpStartSessionRequest  sreq;
+               struct PptpStartSessionReply    srep;
+               struct PptpStopSessionRequest   streq;
+               struct PptpStopSessionReply     strep;
+                struct PptpOutCallRequest       ocreq;
+                struct PptpOutCallReply         ocack;
+                struct PptpInCallRequest        icreq;
+                struct PptpInCallReply          icack;
+                struct PptpInCallConnected      iccon;
+               struct PptpClearCallRequest     clrreq;
+                struct PptpCallDisconnectNotify disc;
+                struct PptpWanErrorNotify       wanerr;
+                struct PptpSetLinkInfo          setlink;
+};
+
+#endif /* __KERNEL__ */
+#endif /* _CONNTRACK_PPTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
new file mode 100644 (file)
index 0000000..0764685
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef _CONNTRACK_PROTO_GRE_H
+#define _CONNTRACK_PROTO_GRE_H
+#include <asm/byteorder.h>
+
+/* GRE PROTOCOL HEADER */
+
+/* GRE Version field */
+#define GRE_VERSION_1701       0x0
+#define GRE_VERSION_PPTP       0x1
+
+/* GRE Protocol field */
+#define GRE_PROTOCOL_PPTP      0x880B
+
+/* GRE Flags */
+#define GRE_FLAG_C             0x80
+#define GRE_FLAG_R             0x40
+#define GRE_FLAG_K             0x20
+#define GRE_FLAG_S             0x10
+#define GRE_FLAG_A             0x80
+
+#define GRE_IS_C(f)    ((f)&GRE_FLAG_C)
+#define GRE_IS_R(f)    ((f)&GRE_FLAG_R)
+#define GRE_IS_K(f)    ((f)&GRE_FLAG_K)
+#define GRE_IS_S(f)    ((f)&GRE_FLAG_S)
+#define GRE_IS_A(f)    ((f)&GRE_FLAG_A)
+
+/* GRE is a mess: Four different standards */
+struct gre_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u16   rec:3,
+               srr:1,
+               seq:1,
+               key:1,
+               routing:1,
+               csum:1,
+               version:3,
+               reserved:4,
+               ack:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u16   csum:1,
+               routing:1,
+               key:1,
+               seq:1,
+               srr:1,
+               rec:3,
+               ack:1,
+               reserved:4,
+               version:3;
+#else
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+       __u16   protocol;
+};
+
+/* modified GRE header for PPTP */
+struct gre_hdr_pptp {
+       __u8  flags;            /* bitfield */
+       __u8  version;          /* should be GRE_VERSION_PPTP */
+       __u16 protocol;         /* should be GRE_PROTOCOL_PPTP */
+       __u16 payload_len;      /* size of ppp payload, not inc. gre header */
+       __u16 call_id;          /* peer's call_id for this session */
+       __u32 seq;              /* sequence number.  Present if S==1 */
+       __u32 ack;              /* seq number of highest packet recieved by */
+                               /*  sender in this session */
+};
+
+
+/* this is part of ip_conntrack */
+struct ip_ct_gre {
+       unsigned int stream_timeout;
+       unsigned int timeout;
+};
+
+/* this is part of ip_conntrack_expect */
+struct ip_ct_gre_expect {
+       struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
+};
+
+#ifdef __KERNEL__
+struct ip_conntrack_expect;
+
+/* structure for original <-> reply keymap */
+struct ip_ct_gre_keymap {
+       struct list_head list;
+
+       struct ip_conntrack_tuple tuple;
+};
+
+
+/* add new tuple->key_reply pair to keymap */
+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
+                        struct ip_conntrack_tuple *t,
+                        int reply);
+
+/* change an existing keymap entry */
+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
+                            struct ip_conntrack_tuple *t);
+
+/* delete keymap entries */
+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
+
+
+/* get pointer to gre key, if present */
+static inline u_int32_t *gre_key(struct gre_hdr *greh)
+{
+       if (!greh->key)
+               return NULL;
+       if (greh->csum || greh->routing)
+               return (u_int32_t *) (greh+sizeof(*greh)+4);
+       return (u_int32_t *) (greh+sizeof(*greh));
+}
+
+/* get pointer ot gre csum, if present */
+static inline u_int16_t *gre_csum(struct gre_hdr *greh)
+{
+       if (!greh->csum)
+               return NULL;
+       return (u_int16_t *) (greh+sizeof(*greh));
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _CONNTRACK_PROTO_GRE_H */
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h
new file mode 100644 (file)
index 0000000..eaf66c2
--- /dev/null
@@ -0,0 +1,11 @@
+/* PPTP constants and structs */
+#ifndef _NAT_PPTP_H
+#define _NAT_PPTP_H
+
+/* conntrack private data */
+struct ip_nat_pptp {
+       u_int16_t pns_call_id;          /* NAT'ed PNS call id */
+       u_int16_t pac_call_id;          /* NAT'ed PAC call id */
+};
+
+#endif /* _NAT_PPTP_H */
diff --git a/include/linux/proc_mm.h b/include/linux/proc_mm.h
new file mode 100644 (file)
index 0000000..254f8b4
--- /dev/null
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PROC_MM_H
+#define __PROC_MM_H
+
+#include "linux/sched.h"
+
+#define MM_MMAP 54
+#define MM_MUNMAP 55
+#define MM_MPROTECT 56
+#define MM_COPY_SEGMENTS 57
+
+struct mm_mmap {
+       unsigned long addr;
+       unsigned long len;
+       unsigned long prot;
+       unsigned long flags;
+       unsigned long fd;
+       unsigned long offset;
+};
+
+struct mm_munmap {
+       unsigned long addr;
+       unsigned long len;      
+};
+
+struct mm_mprotect {
+       unsigned long addr;
+       unsigned long len;
+        unsigned int prot;
+};
+
+struct proc_mm_op {
+       int op;
+       union {
+               struct mm_mmap mmap;
+               struct mm_munmap munmap;
+               struct mm_mprotect mprotect;
+               int copy_segments;
+       } u;
+};
+
+extern struct mm_struct *proc_mm_get_mm(int fd);
+
+#endif
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
new file mode 100644 (file)
index 0000000..4db25d5
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Definitions for MIBs
+ *
+ * Author: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
+ */
+
+#ifndef _LINUX_SNMP_H
+#define _LINUX_SNMP_H
+
+/* ipstats mib definitions */
+/*
+ * RFC 1213:  MIB-II
+ * RFC 2011 (updates 1213):  SNMPv2-MIB-IP
+ * RFC 2863:  Interfaces Group MIB
+ * RFC 2465:  IPv6 MIB: General Group
+ * draft-ietf-ipv6-rfc2011-update-10.txt: MIB for IP: IP Statistics Tables
+ */
+enum
+{
+       IPSTATS_MIB_NUM = 0,
+       IPSTATS_MIB_INRECEIVES,                 /* InReceives */
+       IPSTATS_MIB_INHDRERRORS,                /* InHdrErrors */
+       IPSTATS_MIB_INTOOBIGERRORS,             /* InTooBigErrors */
+       IPSTATS_MIB_INNOROUTES,                 /* InNoRoutes */
+       IPSTATS_MIB_INADDRERRORS,               /* InAddrErrors */
+       IPSTATS_MIB_INUNKNOWNPROTOS,            /* InUnknownProtos */
+       IPSTATS_MIB_INTRUNCATEDPKTS,            /* InTruncatedPkts */
+       IPSTATS_MIB_INDISCARDS,                 /* InDiscards */
+       IPSTATS_MIB_INDELIVERS,                 /* InDelivers */
+       IPSTATS_MIB_OUTFORWDATAGRAMS,           /* OutForwDatagrams */
+       IPSTATS_MIB_OUTREQUESTS,                /* OutRequests */
+       IPSTATS_MIB_OUTDISCARDS,                /* OutDiscards */
+       IPSTATS_MIB_OUTNOROUTES,                /* OutNoRoutes */
+       IPSTATS_MIB_REASMTIMEOUT,               /* ReasmTimeout */
+       IPSTATS_MIB_REASMREQDS,                 /* ReasmReqds */
+       IPSTATS_MIB_REASMOKS,                   /* ReasmOKs */
+       IPSTATS_MIB_REASMFAILS,                 /* ReasmFails */
+       IPSTATS_MIB_FRAGOKS,                    /* FragOKs */
+       IPSTATS_MIB_FRAGFAILS,                  /* FragFails */
+       IPSTATS_MIB_FRAGCREATES,                /* FragCreates */
+       IPSTATS_MIB_INMCASTPKTS,                /* InMcastPkts */
+       IPSTATS_MIB_OUTMCASTPKTS,               /* OutMcastPkts */
+       __IPSTATS_MIB_MAX
+};
+
+/* icmp mib definitions */
+/*
+ * RFC 1213:  MIB-II ICMP Group
+ * RFC 2011 (updates 1213):  SNMPv2 MIB for IP: ICMP group
+ */
+enum
+{
+       ICMP_MIB_NUM = 0,
+       ICMP_MIB_INMSGS,                        /* InMsgs */
+       ICMP_MIB_INERRORS,                      /* InErrors */
+       ICMP_MIB_INDESTUNREACHS,                /* InDestUnreachs */
+       ICMP_MIB_INTIMEEXCDS,                   /* InTimeExcds */
+       ICMP_MIB_INPARMPROBS,                   /* InParmProbs */
+       ICMP_MIB_INSRCQUENCHS,                  /* InSrcQuenchs */
+       ICMP_MIB_INREDIRECTS,                   /* InRedirects */
+       ICMP_MIB_INECHOS,                       /* InEchos */
+       ICMP_MIB_INECHOREPS,                    /* InEchoReps */
+       ICMP_MIB_INTIMESTAMPS,                  /* InTimestamps */
+       ICMP_MIB_INTIMESTAMPREPS,               /* InTimestampReps */
+       ICMP_MIB_INADDRMASKS,                   /* InAddrMasks */
+       ICMP_MIB_INADDRMASKREPS,                /* InAddrMaskReps */
+       ICMP_MIB_OUTMSGS,                       /* OutMsgs */
+       ICMP_MIB_OUTERRORS,                     /* OutErrors */
+       ICMP_MIB_OUTDESTUNREACHS,               /* OutDestUnreachs */
+       ICMP_MIB_OUTTIMEEXCDS,                  /* OutTimeExcds */
+       ICMP_MIB_OUTPARMPROBS,                  /* OutParmProbs */
+       ICMP_MIB_OUTSRCQUENCHS,                 /* OutSrcQuenchs */
+       ICMP_MIB_OUTREDIRECTS,                  /* OutRedirects */
+       ICMP_MIB_OUTECHOS,                      /* OutEchos */
+       ICMP_MIB_OUTECHOREPS,                   /* OutEchoReps */
+       ICMP_MIB_OUTTIMESTAMPS,                 /* OutTimestamps */
+       ICMP_MIB_OUTTIMESTAMPREPS,              /* OutTimestampReps */
+       ICMP_MIB_OUTADDRMASKS,                  /* OutAddrMasks */
+       ICMP_MIB_OUTADDRMASKREPS,               /* OutAddrMaskReps */
+       __ICMP_MIB_MAX
+};
+
+/* icmp6 mib definitions */
+/*
+ * RFC 2466:  ICMPv6-MIB
+ */
+enum
+{
+       ICMP6_MIB_NUM = 0,
+       ICMP6_MIB_INMSGS,                       /* InMsgs */
+       ICMP6_MIB_INERRORS,                     /* InErrors */
+       ICMP6_MIB_INDESTUNREACHS,               /* InDestUnreachs */
+       ICMP6_MIB_INPKTTOOBIGS,                 /* InPktTooBigs */
+       ICMP6_MIB_INTIMEEXCDS,                  /* InTimeExcds */
+       ICMP6_MIB_INPARMPROBLEMS,               /* InParmProblems */
+       ICMP6_MIB_INECHOS,                      /* InEchos */
+       ICMP6_MIB_INECHOREPLIES,                /* InEchoReplies */
+       ICMP6_MIB_INGROUPMEMBQUERIES,           /* InGroupMembQueries */
+       ICMP6_MIB_INGROUPMEMBRESPONSES,         /* InGroupMembResponses */
+       ICMP6_MIB_INGROUPMEMBREDUCTIONS,        /* InGroupMembReductions */
+       ICMP6_MIB_INROUTERSOLICITS,             /* InRouterSolicits */
+       ICMP6_MIB_INROUTERADVERTISEMENTS,       /* InRouterAdvertisements */
+       ICMP6_MIB_INNEIGHBORSOLICITS,           /* InNeighborSolicits */
+       ICMP6_MIB_INNEIGHBORADVERTISEMENTS,     /* InNeighborAdvertisements */
+       ICMP6_MIB_INREDIRECTS,                  /* InRedirects */
+       ICMP6_MIB_OUTMSGS,                      /* OutMsgs */
+       ICMP6_MIB_OUTDESTUNREACHS,              /* OutDestUnreachs */
+       ICMP6_MIB_OUTPKTTOOBIGS,                /* OutPktTooBigs */
+       ICMP6_MIB_OUTTIMEEXCDS,                 /* OutTimeExcds */
+       ICMP6_MIB_OUTPARMPROBLEMS,              /* OutParmProblems */
+       ICMP6_MIB_OUTECHOREPLIES,               /* OutEchoReplies */
+       ICMP6_MIB_OUTROUTERSOLICITS,            /* OutRouterSolicits */
+       ICMP6_MIB_OUTNEIGHBORSOLICITS,          /* OutNeighborSolicits */
+       ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS,    /* OutNeighborAdvertisements */
+       ICMP6_MIB_OUTREDIRECTS,                 /* OutRedirects */
+       ICMP6_MIB_OUTGROUPMEMBRESPONSES,        /* OutGroupMembResponses */
+       ICMP6_MIB_OUTGROUPMEMBREDUCTIONS,       /* OutGroupMembReductions */
+       __ICMP6_MIB_MAX
+};
+
+/* tcp mib definitions */
+/*
+ * RFC 1213:  MIB-II TCP group
+ * RFC 2012 (updates 1213):  SNMPv2-MIB-TCP
+ */
+enum
+{
+       TCP_MIB_NUM = 0,
+       TCP_MIB_RTOALGORITHM,                   /* RtoAlgorithm */
+       TCP_MIB_RTOMIN,                         /* RtoMin */
+       TCP_MIB_RTOMAX,                         /* RtoMax */
+       TCP_MIB_MAXCONN,                        /* MaxConn */
+       TCP_MIB_ACTIVEOPENS,                    /* ActiveOpens */
+       TCP_MIB_PASSIVEOPENS,                   /* PassiveOpens */
+       TCP_MIB_ATTEMPTFAILS,                   /* AttemptFails */
+       TCP_MIB_ESTABRESETS,                    /* EstabResets */
+       TCP_MIB_CURRESTAB,                      /* CurrEstab */
+       TCP_MIB_INSEGS,                         /* InSegs */
+       TCP_MIB_OUTSEGS,                        /* OutSegs */
+       TCP_MIB_RETRANSSEGS,                    /* RetransSegs */
+       TCP_MIB_INERRS,                         /* InErrs */
+       TCP_MIB_OUTRSTS,                        /* OutRsts */
+       __TCP_MIB_MAX
+};
+
+/* udp mib definitions */
+/*
+ * RFC 1213:  MIB-II UDP group
+ * RFC 2013 (updates 1213):  SNMPv2-MIB-UDP
+ */
+enum
+{
+       UDP_MIB_NUM = 0,
+       UDP_MIB_INDATAGRAMS,                    /* InDatagrams */
+       UDP_MIB_NOPORTS,                        /* NoPorts */
+       UDP_MIB_INERRORS,                       /* InErrors */
+       UDP_MIB_OUTDATAGRAMS,                   /* OutDatagrams */
+       __UDP_MIB_MAX
+};
+
+/* sctp mib definitions */
+/*
+ * draft-ietf-sigtran-sctp-mib-07.txt
+ */
+enum
+{
+       SCTP_MIB_NUM = 0,
+       SCTP_MIB_CURRESTAB,                     /* CurrEstab */
+       SCTP_MIB_ACTIVEESTABS,                  /* ActiveEstabs */
+       SCTP_MIB_PASSIVEESTABS,                 /* PassiveEstabs */
+       SCTP_MIB_ABORTEDS,                      /* Aborteds */
+       SCTP_MIB_SHUTDOWNS,                     /* Shutdowns */
+       SCTP_MIB_OUTOFBLUES,                    /* OutOfBlues */
+       SCTP_MIB_CHECKSUMERRORS,                /* ChecksumErrors */
+       SCTP_MIB_OUTCTRLCHUNKS,                 /* OutCtrlChunks */
+       SCTP_MIB_OUTORDERCHUNKS,                /* OutOrderChunks */
+       SCTP_MIB_OUTUNORDERCHUNKS,              /* OutUnorderChunks */
+       SCTP_MIB_INCTRLCHUNKS,                  /* InCtrlChunks */
+       SCTP_MIB_INORDERCHUNKS,                 /* InOrderChunks */
+       SCTP_MIB_INUNORDERCHUNKS,               /* InUnorderChunks */
+       SCTP_MIB_FRAGUSRMSGS,                   /* FragUsrMsgs */
+       SCTP_MIB_REASMUSRMSGS,                  /* ReasmUsrMsgs */
+       SCTP_MIB_OUTSCTPPACKS,                  /* OutSCTPPacks */
+       SCTP_MIB_INSCTPPACKS,                   /* InSCTPPacks */
+       SCTP_MIB_RTOALGORITHM,                  /* RtoAlgorithm */
+       SCTP_MIB_RTOMIN,                        /* RtoMin */
+       SCTP_MIB_RTOMAX,                        /* RtoMax */
+       SCTP_MIB_RTOINITIAL,                    /* RtoInitial */
+       SCTP_MIB_VALCOOKIELIFE,                 /* ValCookieLife */
+       SCTP_MIB_MAXINITRETR,                   /* MaxInitRetr */
+       __SCTP_MIB_MAX
+};
+
+/* linux mib definitions */
+enum
+{
+       LINUX_MIB_NUM = 0,
+       LINUX_MIB_SYNCOOKIESSENT,               /* SyncookiesSent */
+       LINUX_MIB_SYNCOOKIESRECV,               /* SyncookiesRecv */
+       LINUX_MIB_SYNCOOKIESFAILED,             /* SyncookiesFailed */
+       LINUX_MIB_EMBRYONICRSTS,                /* EmbryonicRsts */
+       LINUX_MIB_PRUNECALLED,                  /* PruneCalled */
+       LINUX_MIB_RCVPRUNED,                    /* RcvPruned */
+       LINUX_MIB_OFOPRUNED,                    /* OfoPruned */
+       LINUX_MIB_OUTOFWINDOWICMPS,             /* OutOfWindowIcmps */
+       LINUX_MIB_LOCKDROPPEDICMPS,             /* LockDroppedIcmps */
+       LINUX_MIB_ARPFILTER,                    /* ArpFilter */
+       LINUX_MIB_TIMEWAITED,                   /* TimeWaited */
+       LINUX_MIB_TIMEWAITRECYCLED,             /* TimeWaitRecycled */
+       LINUX_MIB_TIMEWAITKILLED,               /* TimeWaitKilled */
+       LINUX_MIB_PAWSPASSIVEREJECTED,          /* PAWSPassiveRejected */
+       LINUX_MIB_PAWSACTIVEREJECTED,           /* PAWSActiveRejected */
+       LINUX_MIB_PAWSESTABREJECTED,            /* PAWSEstabRejected */
+       LINUX_MIB_DELAYEDACKS,                  /* DelayedACKs */
+       LINUX_MIB_DELAYEDACKLOCKED,             /* DelayedACKLocked */
+       LINUX_MIB_DELAYEDACKLOST,               /* DelayedACKLost */
+       LINUX_MIB_LISTENOVERFLOWS,              /* ListenOverflows */
+       LINUX_MIB_LISTENDROPS,                  /* ListenDrops */
+       LINUX_MIB_TCPPREQUEUED,                 /* TCPPrequeued */
+       LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG,     /* TCPDirectCopyFromBacklog */
+       LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE,    /* TCPDirectCopyFromPrequeue */
+       LINUX_MIB_TCPPREQUEUEDROPPED,           /* TCPPrequeueDropped */
+       LINUX_MIB_TCPHPHITS,                    /* TCPHPHits */
+       LINUX_MIB_TCPHPHITSTOUSER,              /* TCPHPHitsToUser */
+       LINUX_MIB_TCPPUREACKS,                  /* TCPPureAcks */
+       LINUX_MIB_TCPHPACKS,                    /* TCPHPAcks */
+       LINUX_MIB_TCPRENORECOVERY,              /* TCPRenoRecovery */
+       LINUX_MIB_TCPSACKRECOVERY,              /* TCPSackRecovery */
+       LINUX_MIB_TCPSACKRENEGING,              /* TCPSACKReneging */
+       LINUX_MIB_TCPFACKREORDER,               /* TCPFACKReorder */
+       LINUX_MIB_TCPSACKREORDER,               /* TCPSACKReorder */
+       LINUX_MIB_TCPRENOREORDER,               /* TCPRenoReorder */
+       LINUX_MIB_TCPTSREORDER,                 /* TCPTSReorder */
+       LINUX_MIB_TCPFULLUNDO,                  /* TCPFullUndo */
+       LINUX_MIB_TCPPARTIALUNDO,               /* TCPPartialUndo */
+       LINUX_MIB_TCPDSACKUNDO,                 /* TCPDSACKUndo */
+       LINUX_MIB_TCPLOSSUNDO,                  /* TCPLossUndo */
+       LINUX_MIB_TCPLOSS,                      /* TCPLoss */
+       LINUX_MIB_TCPLOSTRETRANSMIT,            /* TCPLostRetransmit */
+       LINUX_MIB_TCPRENOFAILURES,              /* TCPRenoFailures */
+       LINUX_MIB_TCPSACKFAILURES,              /* TCPSackFailures */
+       LINUX_MIB_TCPLOSSFAILURES,              /* TCPLossFailures */
+       LINUX_MIB_TCPFASTRETRANS,               /* TCPFastRetrans */
+       LINUX_MIB_TCPFORWARDRETRANS,            /* TCPForwardRetrans */
+       LINUX_MIB_TCPSLOWSTARTRETRANS,          /* TCPSlowStartRetrans */
+       LINUX_MIB_TCPTIMEOUTS,                  /* TCPTimeouts */
+       LINUX_MIB_TCPRENORECOVERYFAIL,          /* TCPRenoRecoveryFail */
+       LINUX_MIB_TCPSACKRECOVERYFAIL,          /* TCPSackRecoveryFail */
+       LINUX_MIB_TCPSCHEDULERFAILED,           /* TCPSchedulerFailed */
+       LINUX_MIB_TCPRCVCOLLAPSED,              /* TCPRcvCollapsed */
+       LINUX_MIB_TCPDSACKOLDSENT,              /* TCPDSACKOldSent */
+       LINUX_MIB_TCPDSACKOFOSENT,              /* TCPDSACKOfoSent */
+       LINUX_MIB_TCPDSACKRECV,                 /* TCPDSACKRecv */
+       LINUX_MIB_TCPDSACKOFORECV,              /* TCPDSACKOfoRecv */
+       LINUX_MIB_TCPABORTONSYN,                /* TCPAbortOnSyn */
+       LINUX_MIB_TCPABORTONDATA,               /* TCPAbortOnData */
+       LINUX_MIB_TCPABORTONCLOSE,              /* TCPAbortOnClose */
+       LINUX_MIB_TCPABORTONMEMORY,             /* TCPAbortOnMemory */
+       LINUX_MIB_TCPABORTONTIMEOUT,            /* TCPAbortOnTimeout */
+       LINUX_MIB_TCPABORTONLINGER,             /* TCPAbortOnLinger */
+       LINUX_MIB_TCPABORTFAILED,               /* TCPAbortFailed */
+       LINUX_MIB_TCPMEMORYPRESSURES,           /* TCPMemoryPressures */
+       __LINUX_MIB_MAX
+};
+
+#endif /* _LINUX_SNMP_H */
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
new file mode 100644 (file)
index 0000000..e872ad7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * $Id: mtd-abi.h,v 1.5 2004/06/22 09:29:35 gleixner Exp $
+ *
+ * Portions of MTD ABI definition which are shared by kernel and user space 
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+struct erase_info_user {
+       uint32_t start;
+       uint32_t length;
+};
+
+struct mtd_oob_buf {
+       uint32_t start;
+       uint32_t length;
+       unsigned char __user *ptr;
+};
+
+#define MTD_ABSENT             0
+#define MTD_RAM                        1
+#define MTD_ROM                        2
+#define MTD_NORFLASH           3
+#define MTD_NANDFLASH          4
+#define MTD_PEROM              5
+#define MTD_OTHER              14
+#define MTD_UNKNOWN            15
+
+#define MTD_CLEAR_BITS         1       // Bits can be cleared (flash)
+#define MTD_SET_BITS           2       // Bits can be set
+#define MTD_ERASEABLE          4       // Has an erase function
+#define MTD_WRITEB_WRITEABLE   8       // Direct IO is possible
+#define MTD_VOLATILE           16      // Set for RAMs
+#define MTD_XIP                        32      // eXecute-In-Place possible
+#define MTD_OOB                        64      // Out-of-band data (NAND flash)
+#define MTD_ECC                        128     // Device capable of automatic ECC
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM            0
+#define MTD_CAP_RAM            (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
+#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)
+#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
+#define MTD_WRITEABLE          (MTD_CLEAR_BITS|MTD_SET_BITS)
+
+
+// Types of automatic ECC/Checksum available
+#define MTD_ECC_NONE           0       // No automatic ECC available
+#define MTD_ECC_RS_DiskOnChip  1       // Automatic ECC on DiskOnChip
+#define MTD_ECC_SW             2       // SW ECC for Toshiba & Samsung devices
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF                0       // Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE      1       // Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE  2       // Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY  3       // Use the given placement in the structure (Do not store ecc result on read)
+
+struct mtd_info_user {
+       uint8_t type;
+       uint32_t flags;
+       uint32_t size;   // Total size of the MTD
+       uint32_t erasesize;
+       uint32_t oobblock;  // Size of OOB blocks (e.g. 512)
+       uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+       uint32_t ecctype;
+       uint32_t eccsize;
+};
+
+struct region_info_user {
+       uint32_t offset;                /* At which this region starts, 
+                                        * from the beginning of the MTD */
+       uint32_t erasesize;             /* For this region */
+       uint32_t numblocks;             /* Number of blocks in this region */
+       uint32_t regionindex;
+};
+
+#define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
+#define MEMERASE                _IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT      _IOR('M', 7, int)
+#define MEMGETREGIONINFO       _IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL           _IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK         _IOW('M', 11, loff_t)
+#define MEMSETBADBLOCK         _IOW('M', 12, loff_t)
+
+struct nand_oobinfo {
+       uint32_t useecc;
+       uint32_t eccbytes;
+       uint32_t oobfree[8][2];
+       uint32_t eccpos[32];
+};
+
+#endif /* __MTD_ABI_H__ */
diff --git a/mm/proc_mm.c b/mm/proc_mm.c
new file mode 100644 (file)
index 0000000..5ceb506
--- /dev/null
@@ -0,0 +1,174 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/init.h"
+#include "linux/proc_fs.h"
+#include "linux/proc_mm.h"
+#include "linux/file.h"
+#include "asm/uaccess.h"
+#include "asm/mmu_context.h"
+
+static struct file_operations proc_mm_fops;
+
+struct mm_struct *proc_mm_get_mm(int fd)
+{
+       struct mm_struct *ret = ERR_PTR(-EBADF);
+       struct file *file;
+
+       file = fget(fd);
+       if (!file)
+               goto out;
+
+       ret = ERR_PTR(-EINVAL);
+       if(file->f_op != &proc_mm_fops)
+               goto out_fput;
+
+       ret = file->private_data;
+ out_fput:
+       fput(file);
+ out:
+       return(ret);
+}
+
+extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
+                    unsigned long len, unsigned long prot, 
+                    unsigned long flags, unsigned long fd,
+                    unsigned long pgoff);
+
+static ssize_t write_proc_mm(struct file *file, const char *buffer,
+                            size_t count, loff_t *ppos)
+{
+       struct mm_struct *mm = file->private_data;
+       struct proc_mm_op req;
+       int n, ret;
+
+       if(count > sizeof(req))
+               return(-EINVAL);
+
+       n = copy_from_user(&req, buffer, count);
+       if(n != 0)
+               return(-EFAULT);
+
+       ret = count;
+       switch(req.op){
+       case MM_MMAP: {
+               struct mm_mmap *map = &req.u.mmap;
+
+               ret = do_mmap2(mm, map->addr, map->len, map->prot, 
+                              map->flags, map->fd, map->offset >> PAGE_SHIFT);
+               if((ret & ~PAGE_MASK) == 0)
+                       ret = count;
+       
+               break;
+       }
+       case MM_MUNMAP: {
+               struct mm_munmap *unmap = &req.u.munmap;
+
+               down_write(&mm->mmap_sem);
+               ret = do_munmap(mm, unmap->addr, unmap->len);
+               up_write(&mm->mmap_sem);
+
+               if(ret == 0)
+                       ret = count;
+               break;
+       }
+       case MM_MPROTECT: {
+               struct mm_mprotect *protect = &req.u.mprotect;
+
+               ret = do_mprotect(mm, protect->addr, protect->len, 
+                                 protect->prot);
+               if(ret == 0)
+                       ret = count;
+               break;
+       }
+
+       case MM_COPY_SEGMENTS: {
+               struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
+
+               if(IS_ERR(from)){
+                       ret = PTR_ERR(from);
+                       break;
+               }
+
+               mm_copy_segments(from, mm);
+               break;
+       }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return(ret);
+}
+
+static int open_proc_mm(struct inode *inode, struct file *file)
+{
+       struct mm_struct *mm = mm_alloc();
+       int ret;
+
+       ret = -ENOMEM;
+       if(mm == NULL)
+               goto out_mem;
+
+       ret = init_new_context(current, mm);
+       if(ret)
+               goto out_free;
+
+       spin_lock(&mmlist_lock);
+       list_add(&mm->mmlist, &current->mm->mmlist);
+       mmlist_nr++;
+       spin_unlock(&mmlist_lock);
+
+       file->private_data = mm;
+
+       return(0);
+
+ out_free:
+       mmput(mm);
+ out_mem:
+       return(ret);
+}
+
+static int release_proc_mm(struct inode *inode, struct file *file)
+{
+       struct mm_struct *mm = file->private_data;
+
+       mmput(mm);
+       return(0);
+}
+
+static struct file_operations proc_mm_fops = {
+       .open           = open_proc_mm,
+       .release        = release_proc_mm,
+       .write          = write_proc_mm,
+};
+
+static int make_proc_mm(void)
+{
+       struct proc_dir_entry *ent;
+
+       ent = create_proc_entry("mm", 0222, &proc_root);
+       if(ent == NULL){
+               printk("make_proc_mm : Failed to register /proc/mm\n");
+               return(0);
+       }
+       ent->proc_fops = &proc_mm_fops;
+
+       return(0);
+}
+
+__initcall(make_proc_mm);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/mm/thrash.c b/mm/thrash.c
new file mode 100644 (file)
index 0000000..7183937
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * mm/thrash.c
+ *
+ * Copyright (C) 2004, Red Hat, Inc.
+ * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
+ * Released under the GPL, see the file COPYING for details.
+ *
+ * Simple token based thrashing protection, using the algorithm
+ * described in:  http://www.cs.wm.edu/~sjiang/token.pdf
+ */
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/swap.h>
+
+static spinlock_t swap_token_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long swap_token_timeout;
+unsigned long swap_token_check;
+struct mm_struct * swap_token_mm = &init_mm;
+
+#define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2)
+#define SWAP_TOKEN_TIMEOUT (HZ * 300)
+
+/*
+ * Take the token away if the process had no page faults
+ * in the last interval, or if it has held the token for
+ * too long.
+ */
+#define SWAP_TOKEN_ENOUGH_RSS 1
+#define SWAP_TOKEN_TIMED_OUT 2
+static int should_release_swap_token(struct mm_struct *mm)
+{
+       int ret = 0;
+       if (!mm->recent_pagein)
+               ret = SWAP_TOKEN_ENOUGH_RSS;
+       else if (time_after(jiffies, swap_token_timeout))
+               ret = SWAP_TOKEN_TIMED_OUT;
+       mm->recent_pagein = 0;
+       return ret;
+}
+
+/*
+ * Try to grab the swapout protection token.  We only try to
+ * grab it once every TOKEN_CHECK_INTERVAL, both to prevent
+ * SMP lock contention and to check that the process that held
+ * the token before is no longer thrashing.
+ */
+void grab_swap_token(void)
+{
+       struct mm_struct *mm;
+       int reason;
+
+       /* We have the token. Let others know we still need it. */
+       if (has_swap_token(current->mm)) {
+               current->mm->recent_pagein = 1;
+               return;
+       }
+
+       if (time_after(jiffies, swap_token_check)) {
+
+               /* Can't get swapout protection if we exceed our RSS limit. */
+               // if (current->mm->rss > current->mm->rlimit_rss)
+               //      return;
+
+               /* ... or if we recently held the token. */
+               if (time_before(jiffies, current->mm->swap_token_time))
+                       return;
+
+               if (!spin_trylock(&swap_token_lock))
+                       return;
+
+               swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
+
+               mm = swap_token_mm;
+               if ((reason = should_release_swap_token(mm))) {
+                       unsigned long eligible = jiffies;
+                       if (reason == SWAP_TOKEN_TIMED_OUT) {
+                               eligible += SWAP_TOKEN_TIMEOUT;
+                       }
+                       mm->swap_token_time = eligible;
+                       swap_token_timeout = jiffies + SWAP_TOKEN_TIMEOUT;
+                       swap_token_mm = current->mm;
+               }
+               spin_unlock(&swap_token_lock);
+       }
+       return;
+}
+
+/* Called on process exit. */
+void __put_swap_token(struct mm_struct *mm)
+{
+       spin_lock(&swap_token_lock);
+       if (likely(mm == swap_token_mm)) {
+               swap_token_mm = &init_mm;
+               swap_token_check = jiffies;
+       }
+       spin_unlock(&swap_token_lock);
+}
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
new file mode 100644 (file)
index 0000000..ee652ae
--- /dev/null
@@ -0,0 +1,645 @@
+/* 
+   HIDP implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   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 OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/ioctl.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <net/sock.h>
+
+#include <linux/input.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "hidp.h"
+
+#ifndef CONFIG_BT_HIDP_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "1.0"
+
+static DECLARE_RWSEM(hidp_session_sem);
+static LIST_HEAD(hidp_session_list);
+
+static unsigned char hidp_keycode[256] = {
+         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+        27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+        72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
+       191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
+       115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
+       122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+       150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
+{
+       struct hidp_session *session;
+       struct list_head *p;
+
+       BT_DBG("");
+
+       list_for_each(p, &hidp_session_list) {
+               session = list_entry(p, struct hidp_session, list);
+               if (!bacmp(bdaddr, &session->bdaddr))
+                       return session;
+       }
+       return NULL;
+}
+
+static void __hidp_link_session(struct hidp_session *session)
+{
+       __module_get(THIS_MODULE);
+       list_add(&session->list, &hidp_session_list);
+}
+
+static void __hidp_unlink_session(struct hidp_session *session)
+{
+       list_del(&session->list);
+       module_put(THIS_MODULE);
+}
+
+static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
+{
+       bacpy(&ci->bdaddr, &session->bdaddr);
+
+       ci->flags = session->flags;
+       ci->state = session->state;
+
+       ci->vendor  = 0x0000;
+       ci->product = 0x0000;
+       ci->version = 0x0000;
+       memset(ci->name, 0, 128);
+
+       if (session->input) {
+               ci->vendor  = session->input->id.vendor;
+               ci->product = session->input->id.product;
+               ci->version = session->input->id.version;
+               if (session->input->name)
+                       strncpy(ci->name, session->input->name, 128);
+               else
+                       strncpy(ci->name, "HID Boot Device", 128);
+       }
+}
+
+static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct hidp_session *session = dev->private;
+       struct sk_buff *skb;
+       unsigned char newleds;
+
+       BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
+
+       if (type != EV_LED)
+               return -1;
+
+       newleds = (!!test_bit(LED_KANA,    dev->led) << 3) |
+                 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+                 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
+                 (!!test_bit(LED_CAPSL,   dev->led) << 1) |
+                 (!!test_bit(LED_NUML,    dev->led));
+
+       if (session->leds == newleds)
+               return 0;
+
+       session->leds = newleds;
+
+       if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
+               BT_ERR("Can't allocate memory for new frame");
+               return -ENOMEM;
+       }
+
+       *skb_put(skb, 1) = 0xa2;
+       *skb_put(skb, 1) = 0x01;
+       *skb_put(skb, 1) = newleds;
+
+       skb_queue_tail(&session->intr_transmit, skb);
+
+       hidp_schedule(session);
+
+       return 0;
+}
+
+static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
+{
+       struct input_dev *dev = session->input;
+       unsigned char *keys = session->keys;
+       unsigned char *udata = skb->data + 1;
+       signed char *sdata = skb->data + 1;
+       int i, size = skb->len - 1;
+
+       switch (skb->data[0]) {
+       case 0x01:      /* Keyboard report */
+               for (i = 0; i < 8; i++)
+                       input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
+
+               for (i = 2; i < 8; i++) {
+                       if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
+                               if (hidp_keycode[keys[i]])
+                                       input_report_key(dev, hidp_keycode[keys[i]], 0);
+                               else
+                                       BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
+                       }
+
+                       if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
+                               if (hidp_keycode[udata[i]])
+                                       input_report_key(dev, hidp_keycode[udata[i]], 1);
+                               else
+                                       BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
+                       }
+               }
+
+               memcpy(keys, udata, 8);
+               break;
+
+       case 0x02:      /* Mouse report */
+               input_report_key(dev, BTN_LEFT,   sdata[0] & 0x01);
+               input_report_key(dev, BTN_RIGHT,  sdata[0] & 0x02);
+               input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
+               input_report_key(dev, BTN_SIDE,   sdata[0] & 0x08);
+               input_report_key(dev, BTN_EXTRA,  sdata[0] & 0x10);
+
+               input_report_rel(dev, REL_X, sdata[1]);
+               input_report_rel(dev, REL_Y, sdata[2]);
+
+               if (size > 3)
+                       input_report_rel(dev, REL_WHEEL, sdata[3]);
+               break;
+       }
+
+       input_sync(dev);
+}
+
+static void hidp_idle_timeout(unsigned long arg)
+{
+       struct hidp_session *session = (struct hidp_session *) arg;
+
+       atomic_inc(&session->terminate);
+       hidp_schedule(session);
+}
+
+static inline void hidp_set_timer(struct hidp_session *session)
+{
+       if (session->idle_to > 0)
+               mod_timer(&session->timer, jiffies + HZ * session->idle_to);
+}
+
+static inline void hidp_del_timer(struct hidp_session *session)
+{
+       if (session->idle_to > 0)
+               del_timer(&session->timer);
+}
+
+static inline void hidp_send_message(struct hidp_session *session, unsigned char hdr)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p", session);
+
+       if (!(skb = alloc_skb(1, GFP_ATOMIC))) {
+               BT_ERR("Can't allocate memory for message");
+               return;
+       }
+
+       *skb_put(skb, 1) = hdr;
+
+       skb_queue_tail(&session->ctrl_transmit, skb);
+
+       hidp_schedule(session);
+}
+
+static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff *skb)
+{
+       __u8 hdr;
+
+       BT_DBG("session %p skb %p len %d", session, skb, skb->len);
+
+       hdr = skb->data[0];
+       skb_pull(skb, 1);
+
+       if (hdr == 0xa1) {
+               hidp_set_timer(session);
+
+               if (session->input)
+                       hidp_input_report(session, skb);
+       } else {
+               BT_DBG("Unsupported protocol header 0x%02x", hdr);
+       }
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
+{
+       struct kvec iv = { data, len };
+       struct msghdr msg;
+
+       BT_DBG("sock %p data %p len %d", sock, data, len);
+
+       if (!len)
+               return 0;
+
+       memset(&msg, 0, sizeof(msg));
+
+       return kernel_sendmsg(sock, &msg, &iv, 1, len);
+}
+
+static int hidp_process_transmit(struct hidp_session *session)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p", session);
+
+       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
+               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->ctrl_transmit, skb);
+                       break;
+               }
+
+               hidp_set_timer(session);
+               kfree_skb(skb);
+       }
+
+       while ((skb = skb_dequeue(&session->intr_transmit))) {
+               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->intr_transmit, skb);
+                       break;
+               }
+
+               hidp_set_timer(session);
+               kfree_skb(skb);
+       }
+
+       return skb_queue_len(&session->ctrl_transmit) +
+                               skb_queue_len(&session->intr_transmit);
+}
+
+static int hidp_session(void *arg)
+{
+       struct hidp_session *session = arg;
+       struct sock *ctrl_sk = session->ctrl_sock->sk;
+       struct sock *intr_sk = session->intr_sock->sk;
+       struct sk_buff *skb;
+       int vendor = 0x0000, product = 0x0000;
+       wait_queue_t ctrl_wait, intr_wait;
+       unsigned long timeo = HZ;
+
+       BT_DBG("session %p", session);
+
+       if (session->input) {
+               vendor  = session->input->id.vendor;
+               product = session->input->id.product;
+       }
+
+       daemonize("khidpd_%04x%04x", vendor, product);
+       set_user_nice(current, -15);
+       current->flags |= PF_NOFREEZE;
+
+       init_waitqueue_entry(&ctrl_wait, current);
+       init_waitqueue_entry(&intr_wait, current);
+       add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
+       add_wait_queue(intr_sk->sk_sleep, &intr_wait);
+       while (!atomic_read(&session->terminate)) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
+                       break;
+
+               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
+                       skb_orphan(skb);
+                       hidp_recv_frame(session, skb);
+               }
+
+               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
+                       skb_orphan(skb);
+                       hidp_recv_frame(session, skb);
+               }
+
+               hidp_process_transmit(session);
+
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
+       remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
+
+       down_write(&hidp_session_sem);
+
+       hidp_del_timer(session);
+
+       if (intr_sk->sk_state != BT_CONNECTED) {
+               init_waitqueue_entry(&ctrl_wait, current);
+               add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
+               while (timeo && ctrl_sk->sk_state != BT_CLOSED) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       timeo = schedule_timeout(timeo);
+               }
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
+               timeo = HZ;
+       }
+
+       fput(session->ctrl_sock->file);
+
+       init_waitqueue_entry(&intr_wait, current);
+       add_wait_queue(intr_sk->sk_sleep, &intr_wait);
+       while (timeo && intr_sk->sk_state != BT_CLOSED) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               timeo = schedule_timeout(timeo);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
+
+       fput(session->intr_sock->file);
+
+       __hidp_unlink_session(session);
+
+       if (session->input) {
+               input_unregister_device(session->input);
+               kfree(session->input);
+       }
+
+       up_write(&hidp_session_sem);
+
+       kfree(session);
+       return 0;
+}
+
+static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
+{
+       struct input_dev *input = session->input;
+       int i;
+
+       input->private = session;
+
+       input->id.bustype = BUS_BLUETOOTH;
+       input->id.vendor  = req->vendor;
+       input->id.product = req->product;
+       input->id.version = req->version;
+
+       if (req->subclass & 0x40) {
+               set_bit(EV_KEY, input->evbit);
+               set_bit(EV_LED, input->evbit);
+               set_bit(EV_REP, input->evbit);
+
+               set_bit(LED_NUML,    input->ledbit);
+               set_bit(LED_CAPSL,   input->ledbit);
+               set_bit(LED_SCROLLL, input->ledbit);
+               set_bit(LED_COMPOSE, input->ledbit);
+               set_bit(LED_KANA,    input->ledbit);
+
+               for (i = 0; i < sizeof(hidp_keycode); i++)
+                       set_bit(hidp_keycode[i], input->keybit);
+               clear_bit(0, input->keybit);
+       }
+
+       if (req->subclass & 0x80) {
+               input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+               input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+               input->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+               input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+               input->relbit[0] |= BIT(REL_WHEEL);
+       }
+
+       input->event = hidp_input_event;
+
+       input_register_device(input);
+}
+
+int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
+{
+       struct hidp_session *session, *s;
+       int err;
+
+       BT_DBG("");
+
+       if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
+                       bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
+               return -ENOTUNIQ;
+
+       session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL);
+       if (!session) 
+               return -ENOMEM;
+       memset(session, 0, sizeof(struct hidp_session));
+
+       session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
+       if (!session->input) {
+               kfree(session);
+               return -ENOMEM;
+       }
+       memset(session->input, 0, sizeof(struct input_dev));
+
+       down_write(&hidp_session_sem);
+
+       s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
+       if (s && s->state == BT_CONNECTED) {
+               err = -EEXIST;
+               goto failed;
+       }
+
+       bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
+
+       session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
+       session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
+
+       BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
+
+       session->ctrl_sock = ctrl_sock;
+       session->intr_sock = intr_sock;
+       session->state     = BT_CONNECTED;
+
+       init_timer(&session->timer);
+
+       session->timer.function = hidp_idle_timeout;
+       session->timer.data     = (unsigned long) session;
+
+       skb_queue_head_init(&session->ctrl_transmit);
+       skb_queue_head_init(&session->intr_transmit);
+
+       session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
+       session->idle_to = req->idle_to;
+
+       if (session->input)
+               hidp_setup_input(session, req);
+
+       __hidp_link_session(session);
+
+       hidp_set_timer(session);
+
+       err = kernel_thread(hidp_session, session, CLONE_KERNEL);
+       if (err < 0)
+               goto unlink;
+
+       if (session->input) {
+               hidp_send_message(session, 0x70);
+               session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+
+               session->leds = 0xff;
+               hidp_input_event(session->input, EV_LED, 0, 0);
+       }
+
+       up_write(&hidp_session_sem);
+       return 0;
+
+unlink:
+       hidp_del_timer(session);
+
+       __hidp_unlink_session(session);
+
+       if (session->input)
+               input_unregister_device(session->input);
+
+failed:
+       up_write(&hidp_session_sem);
+
+       if (session->input)
+               kfree(session->input);
+
+       kfree(session);
+       return err;
+}
+
+int hidp_del_connection(struct hidp_conndel_req *req)
+{
+       struct hidp_session *session;
+       int err = 0;
+
+       BT_DBG("");
+
+       down_read(&hidp_session_sem);
+
+       session = __hidp_get_session(&req->bdaddr);
+       if (session) {
+               if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
+                       hidp_send_message(session, 0x15);
+               } else {
+                       /* Flush the transmit queues */
+                       skb_queue_purge(&session->ctrl_transmit);
+                       skb_queue_purge(&session->intr_transmit);
+
+                       /* Kill session thread */
+                       atomic_inc(&session->terminate);
+                       hidp_schedule(session);
+               }
+       } else
+               err = -ENOENT;
+
+       up_read(&hidp_session_sem);
+       return err;
+}
+
+int hidp_get_connlist(struct hidp_connlist_req *req)
+{
+       struct list_head *p;
+       int err = 0, n = 0;
+
+       BT_DBG("");
+
+       down_read(&hidp_session_sem);
+
+       list_for_each(p, &hidp_session_list) {
+               struct hidp_session *session;
+               struct hidp_conninfo ci;
+
+               session = list_entry(p, struct hidp_session, list);
+
+               __hidp_copy_session(session, &ci);
+
+               if (copy_to_user(req->ci, &ci, sizeof(ci))) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (++n >= req->cnum)
+                       break;
+
+               req->ci++;
+       }
+       req->cnum = n;
+
+       up_read(&hidp_session_sem);
+       return err;
+}
+
+int hidp_get_conninfo(struct hidp_conninfo *ci)
+{
+       struct hidp_session *session;
+       int err = 0;
+
+       down_read(&hidp_session_sem);
+
+       session = __hidp_get_session(&ci->bdaddr);
+       if (session)
+               __hidp_copy_session(session, ci);
+       else
+               err = -ENOENT;
+
+       up_read(&hidp_session_sem);
+       return err;
+}
+
+static int __init hidp_init(void)
+{
+       l2cap_load();
+
+       BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
+
+       return hidp_init_sockets();
+}
+
+static void __exit hidp_exit(void)
+{
+       hidp_cleanup_sockets();
+}
+
+module_init(hidp_init);
+module_exit(hidp_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("bt-proto-6");
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
new file mode 100644 (file)
index 0000000..f84e104
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *     common UDP/RAW code
+ *     Linux INET implementation
+ *
+ * Authors:
+ *     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/route.h>
+
+int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       struct inet_opt *inet = inet_sk(sk);
+       struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+       struct rtable *rt;
+       u32 saddr;
+       int oif;
+       int err;
+
+       
+       if (addr_len < sizeof(*usin)) 
+               return -EINVAL;
+
+       if (usin->sin_family != AF_INET) 
+               return -EAFNOSUPPORT;
+
+       sk_dst_reset(sk);
+
+       oif = sk->sk_bound_dev_if;
+       saddr = inet->saddr;
+       if (MULTICAST(usin->sin_addr.s_addr)) {
+               if (!oif)
+                       oif = inet->mc_index;
+               if (!saddr)
+                       saddr = inet->mc_addr;
+       }
+       err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
+                              RT_CONN_FLAGS(sk), oif,
+                              sk->sk_protocol,
+                              inet->sport, usin->sin_port, sk);
+       if (err)
+               return err;
+       if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
+               ip_rt_put(rt);
+               return -EACCES;
+       }
+       if (!inet->saddr)
+               inet->saddr = rt->rt_src;       /* Update source address */
+       if (!inet->rcv_saddr)
+               inet->rcv_saddr = rt->rt_src;
+       inet->daddr = rt->rt_dst;
+       inet->dport = usin->sin_port;
+       sk->sk_state = TCP_ESTABLISHED;
+       inet->id = jiffies;
+
+       sk_dst_set(sk, &rt->u.dst);
+       return(0);
+}
+
+EXPORT_SYMBOL(ip4_datagram_connect);
+
diff --git a/net/ipv4/netfilter/ip_conntrack_pptp.c b/net/ipv4/netfilter/ip_conntrack_pptp.c
new file mode 100644 (file)
index 0000000..29ab1a4
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ * ip_conntrack_pptp.c - Version 2.0
+ *
+ * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
+ * PPTP is a a protocol for creating virtual private networks.
+ * It is a specification defined by Microsoft and some vendors
+ * working with Microsoft.  PPTP is built on top of a modified
+ * version of the Internet Generic Routing Encapsulation Protocol.
+ * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
+ * PPTP can be found in RFC 2637
+ *
+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ *
+ * Limitations:
+ *      - We blindly assume that control connections are always
+ *        established in PNS->PAC direction.  This is a violation
+ *        of RFFC2673
+ *
+ * TODO: - finish support for multiple calls within one session
+ *        (needs expect reservations in newnat)
+ *      - testing of incoming PPTP calls 
+ *
+ * Changes: 
+ *     2002-02-05 - Version 1.3
+ *       - Call ip_conntrack_unexpect_related() from 
+ *         pptp_timeout_related() to destroy expectations in case
+ *         CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
+ *         (Philip Craig <philipc@snapgear.com>)
+ *       - Add Version information at module loadtime
+ *     2002-02-10 - Version 1.6
+ *       - move to C99 style initializers
+ *       - remove second expectation if first arrives
+ *     2004-10-22 - Version 2.0
+ *       - merge Mandrake's 2.6.x port with recent 2.6.x API changes
+ *       - fix lots of linear skb assumptions from Mandrake's port
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+
+#define IP_CT_PPTP_VERSION "2.0"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
+
+DECLARE_LOCK(ip_pptp_lock);
+
+#if 0
+#include "ip_conntrack_pptp_priv.h"
+#define DEBUGP(format, args...)        printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define SECS *HZ
+#define MINS * 60 SECS
+#define HOURS * 60 MINS
+#define DAYS * 24 HOURS
+
+#define PPTP_GRE_TIMEOUT               (10 MINS)
+#define PPTP_GRE_STREAM_TIMEOUT        (5 DAYS)
+
+static int pptp_expectfn(struct ip_conntrack *ct)
+{
+       struct ip_conntrack *master;
+       struct ip_conntrack_expect *exp;
+
+       DEBUGP("increasing timeouts\n");
+       /* increase timeout of GRE data channel conntrack entry */
+       ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
+       ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
+
+       master = master_ct(ct);
+       if (!master) {
+               DEBUGP(" no master!!!\n");
+               return 0;
+       }
+
+       exp = ct->master;
+       if (!exp) {
+               DEBUGP("no expectation!!\n");
+               return 0;
+       }
+
+       DEBUGP("completing tuples with ct info\n");
+       /* we can do this, since we're unconfirmed */
+       if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
+               htonl(master->help.ct_pptp_info.pac_call_id)) { 
+               /* assume PNS->PAC */
+               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
+                       htonl(master->help.ct_pptp_info.pns_call_id);
+               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
+                       htonl(master->help.ct_pptp_info.pns_call_id);
+       } else {
+               /* assume PAC->PNS */
+               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
+                       htonl(master->help.ct_pptp_info.pac_call_id);
+               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
+                       htonl(master->help.ct_pptp_info.pac_call_id);
+       }
+       
+       /* delete other expectation */
+       if (exp->expected_list.next != &exp->expected_list) {
+               struct ip_conntrack_expect *other_exp;
+               struct list_head *cur_item, *next;
+
+               for (cur_item = master->sibling_list.next;
+                    cur_item != &master->sibling_list; cur_item = next) {
+                       next = cur_item->next;
+                       other_exp = list_entry(cur_item,
+                                              struct ip_conntrack_expect,
+                                              expected_list);
+                       /* remove only if occurred at same sequence number */
+                       if (other_exp != exp && other_exp->seq == exp->seq) {
+                               DEBUGP("unexpecting other direction\n");
+                               ip_ct_gre_keymap_destroy(other_exp);
+                               ip_conntrack_unexpect_related(other_exp);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* timeout GRE data connections */
+static int pptp_timeout_related(struct ip_conntrack *ct)
+{
+       struct list_head *cur_item, *next;
+       struct ip_conntrack_expect *exp;
+
+       /* FIXME: do we have to lock something ? */
+       for (cur_item = ct->sibling_list.next;
+           cur_item != &ct->sibling_list; cur_item = next) {
+               next = cur_item->next;
+               exp = list_entry(cur_item, struct ip_conntrack_expect,
+                                expected_list);
+
+               ip_ct_gre_keymap_destroy(exp);
+               if (!exp->sibling) {
+                       ip_conntrack_unexpect_related(exp);
+                       continue;
+               }
+
+               DEBUGP("setting timeout of conntrack %p to 0\n",
+                       exp->sibling);
+               exp->sibling->proto.gre.timeout = 0;
+               exp->sibling->proto.gre.stream_timeout = 0;
+               /* refresh_acct will not modify counters if skb == NULL */
+               ip_ct_refresh_acct(exp->sibling, 0, NULL, 0);
+       }
+
+       return 0;
+}
+
+/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
+static inline int
+exp_gre(struct ip_conntrack *master,
+       u_int32_t seq,
+       u_int16_t callid,
+       u_int16_t peer_callid)
+{
+       struct ip_conntrack_tuple inv_tuple;
+       struct ip_conntrack_tuple exp_tuples[] = {
+               /* tuple in original direction, PNS->PAC */
+               { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
+                          .u = { .gre = { .key = htonl(ntohs(peer_callid)) } }
+                        },
+                 .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+                          .u = { .gre = { .key = htonl(ntohs(callid)) } },
+                          .protonum = IPPROTO_GRE
+                        },
+                },
+               /* tuple in reply direction, PAC->PNS */
+               { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
+                          .u = { .gre = { .key = htonl(ntohs(callid)) } }
+                        },
+                 .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
+                          .u = { .gre = { .key = htonl(ntohs(peer_callid)) } },
+                          .protonum = IPPROTO_GRE
+                        },
+                }
+       }, *exp_tuple;
+
+       for (exp_tuple = exp_tuples; exp_tuple < &exp_tuples[2]; exp_tuple++) {
+               struct ip_conntrack_expect *exp;
+
+               exp = ip_conntrack_expect_alloc();
+               if (exp == NULL)
+                       return 1;
+
+               memcpy(&exp->tuple, exp_tuple, sizeof(exp->tuple));
+
+               exp->mask.src.ip = 0xffffffff;
+               exp->mask.src.u.all = 0;
+               exp->mask.dst.u.all = 0;
+               exp->mask.dst.u.gre.key = 0xffffffff;
+               exp->mask.dst.ip = 0xffffffff;
+               exp->mask.dst.protonum = 0xffff;
+                       
+               exp->seq = seq;
+               exp->expectfn = pptp_expectfn;
+
+               exp->help.exp_pptp_info.pac_call_id = ntohs(callid);
+               exp->help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
+
+               DEBUGP("calling expect_related ");
+               DUMP_TUPLE_RAW(&exp->tuple);
+       
+               /* Add GRE keymap entries */
+               if (ip_ct_gre_keymap_add(exp, &exp->tuple, 0) != 0) {
+                       kfree(exp);
+                       return 1;
+               }
+
+               invert_tuplepr(&inv_tuple, &exp->tuple);
+               if (ip_ct_gre_keymap_add(exp, &inv_tuple, 1) != 0) {
+                       ip_ct_gre_keymap_destroy(exp);
+                       kfree(exp);
+                       return 1;
+               }
+       
+               if (ip_conntrack_expect_related(exp, master) != 0) {
+                       ip_ct_gre_keymap_destroy(exp);
+                       kfree(exp);
+                       DEBUGP("cannot expect_related()\n");
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static inline int 
+pptp_inbound_pkt(struct sk_buff *skb,
+                struct tcphdr *tcph,
+                unsigned int ctlhoff,
+                size_t datalen,
+                struct ip_conntrack *ct)
+{
+       struct PptpControlHeader _ctlh, *ctlh;
+       unsigned int reqlen;
+       union pptp_ctrl_union _pptpReq, *pptpReq;
+       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+       u_int16_t msg, *cid, *pcid;
+       u_int32_t seq;  
+
+       ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
+       if (unlikely(!ctlh)) {
+               DEBUGP("error during skb_header_pointer\n");
+               return NF_ACCEPT;
+       }
+
+       reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
+       pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(struct pptp_pkt_hdr),
+                                    reqlen, &_pptpReq);
+       if (unlikely(!pptpReq)) {
+               DEBUGP("error during skb_header_pointer\n");
+               return NF_ACCEPT;
+       }
+
+       msg = ntohs(ctlh->messageType);
+       DEBUGP("inbound control message %s\n", strMName[msg]);
+
+       switch (msg) {
+       case PPTP_START_SESSION_REPLY:
+               if (reqlen < sizeof(_pptpReq.srep)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server confirms new control session */
+               if (info->sstate < PPTP_SESSION_REQUESTED) {
+                       DEBUGP("%s without START_SESS_REQUEST\n",
+                               strMName[msg]);
+                       break;
+               }
+               if (pptpReq->srep.resultCode == PPTP_START_OK)
+                       info->sstate = PPTP_SESSION_CONFIRMED;
+               else 
+                       info->sstate = PPTP_SESSION_ERROR;
+               break;
+
+       case PPTP_STOP_SESSION_REPLY:
+               if (reqlen < sizeof(_pptpReq.strep)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server confirms end of control session */
+               if (info->sstate > PPTP_SESSION_STOPREQ) {
+                       DEBUGP("%s without STOP_SESS_REQUEST\n",
+                               strMName[msg]);
+                       break;
+               }
+               if (pptpReq->strep.resultCode == PPTP_STOP_OK)
+                       info->sstate = PPTP_SESSION_NONE;
+               else
+                       info->sstate = PPTP_SESSION_ERROR;
+               break;
+
+       case PPTP_OUT_CALL_REPLY:
+               if (reqlen < sizeof(_pptpReq.ocack)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server accepted call, we now expect GRE frames */
+               if (info->sstate != PPTP_SESSION_CONFIRMED) {
+                       DEBUGP("%s but no session\n", strMName[msg]);
+                       break;
+               }
+               if (info->cstate != PPTP_CALL_OUT_REQ &&
+                   info->cstate != PPTP_CALL_OUT_CONF) {
+                       DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
+                       break;
+               }
+               if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) {
+                       info->cstate = PPTP_CALL_NONE;
+                       break;
+               }
+
+               cid = &pptpReq->ocack.callID;
+               pcid = &pptpReq->ocack.peersCallID;
+
+               info->pac_call_id = ntohs(*cid);
+               
+               if (htons(info->pns_call_id) != *pcid) {
+                       DEBUGP("%s for unknown callid %u\n",
+                               strMName[msg], ntohs(*pcid));
+                       break;
+               }
+
+               DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], 
+                       ntohs(*cid), ntohs(*pcid));
+               
+               info->cstate = PPTP_CALL_OUT_CONF;
+
+               seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
+                                      + sizeof(struct PptpControlHeader)
+                                      + ((void *)pcid - (void *)pptpReq);
+                       
+               if (exp_gre(ct, seq, *cid, *pcid) != 0)
+                       printk("ip_conntrack_pptp: error during exp_gre\n");
+               break;
+
+       case PPTP_IN_CALL_REQUEST:
+               if (reqlen < sizeof(_pptpReq.icack)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server tells us about incoming call request */
+               if (info->sstate != PPTP_SESSION_CONFIRMED) {
+                       DEBUGP("%s but no session\n", strMName[msg]);
+                       break;
+               }
+               pcid = &pptpReq->icack.peersCallID;
+               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
+               info->cstate = PPTP_CALL_IN_REQ;
+               info->pac_call_id = ntohs(*pcid);
+               break;
+
+       case PPTP_IN_CALL_CONNECT:
+               if (reqlen < sizeof(_pptpReq.iccon)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server tells us about incoming call established */
+               if (info->sstate != PPTP_SESSION_CONFIRMED) {
+                       DEBUGP("%s but no session\n", strMName[msg]);
+                       break;
+               }
+               if (info->sstate != PPTP_CALL_IN_REP
+                   && info->sstate != PPTP_CALL_IN_CONF) {
+                       DEBUGP("%s but never sent IN_CALL_REPLY\n",
+                               strMName[msg]);
+                       break;
+               }
+
+               pcid = &pptpReq->iccon.peersCallID;
+               cid = &info->pac_call_id;
+
+               if (info->pns_call_id != ntohs(*pcid)) {
+                       DEBUGP("%s for unknown CallID %u\n", 
+                               strMName[msg], ntohs(*cid));
+                       break;
+               }
+
+               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
+               info->cstate = PPTP_CALL_IN_CONF;
+
+               /* we expect a GRE connection from PAC to PNS */
+               seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
+                                      + sizeof(struct PptpControlHeader)
+                                      + ((void *)pcid - (void *)pptpReq);
+                       
+               if (exp_gre(ct, seq, *cid, *pcid) != 0)
+                       printk("ip_conntrack_pptp: error during exp_gre\n");
+
+               break;
+
+       case PPTP_CALL_DISCONNECT_NOTIFY:
+               if (reqlen < sizeof(_pptpReq.disc)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* server confirms disconnect */
+               cid = &pptpReq->disc.callID;
+               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
+               info->cstate = PPTP_CALL_NONE;
+
+               /* untrack this call id, unexpect GRE packets */
+               pptp_timeout_related(ct);
+               break;
+
+       case PPTP_WAN_ERROR_NOTIFY:
+               break;
+
+       case PPTP_ECHO_REQUEST:
+       case PPTP_ECHO_REPLY:
+               /* I don't have to explain these ;) */
+               break;
+       default:
+               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
+                       ? strMName[msg]:strMName[0], msg);
+               break;
+       }
+
+       return NF_ACCEPT;
+
+}
+
+static inline int
+pptp_outbound_pkt(struct sk_buff *skb,
+                 struct tcphdr *tcph,
+                 unsigned int ctlhoff,
+                 size_t datalen,
+                 struct ip_conntrack *ct)
+{
+       struct PptpControlHeader _ctlh, *ctlh;
+       unsigned int reqlen;
+       union pptp_ctrl_union _pptpReq, *pptpReq;
+       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+       u_int16_t msg, *cid, *pcid;
+
+       ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
+       if (!ctlh)
+               return NF_ACCEPT;
+       
+       reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
+       pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(_ctlh), reqlen, 
+                                    &_pptpReq);
+       if (!pptpReq)
+               return NF_ACCEPT;
+
+       msg = ntohs(ctlh->messageType);
+       DEBUGP("outbound control message %s\n", strMName[msg]);
+
+       switch (msg) {
+       case PPTP_START_SESSION_REQUEST:
+               /* client requests for new control session */
+               if (info->sstate != PPTP_SESSION_NONE) {
+                       DEBUGP("%s but we already have one",
+                               strMName[msg]);
+               }
+               info->sstate = PPTP_SESSION_REQUESTED;
+               break;
+       case PPTP_STOP_SESSION_REQUEST:
+               /* client requests end of control session */
+               info->sstate = PPTP_SESSION_STOPREQ;
+               break;
+
+       case PPTP_OUT_CALL_REQUEST:
+               if (reqlen < sizeof(_pptpReq.ocreq)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* client initiating connection to server */
+               if (info->sstate != PPTP_SESSION_CONFIRMED) {
+                       DEBUGP("%s but no session\n",
+                               strMName[msg]);
+                       break;
+               }
+               info->cstate = PPTP_CALL_OUT_REQ;
+               /* track PNS call id */
+               cid = &pptpReq->ocreq.callID;
+               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
+               info->pns_call_id = ntohs(*cid);
+               break;
+       case PPTP_IN_CALL_REPLY:
+               if (reqlen < sizeof(_pptpReq.icack)) {
+                       DEBUGP("%s: short packet\n", strMName[msg]);
+                       break;
+               }
+
+               /* client answers incoming call */
+               if (info->cstate != PPTP_CALL_IN_REQ
+                   && info->cstate != PPTP_CALL_IN_REP) {
+                       DEBUGP("%s without incall_req\n", 
+                               strMName[msg]);
+                       break;
+               }
+               if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) {
+                       info->cstate = PPTP_CALL_NONE;
+                       break;
+               }
+               pcid = &pptpReq->icack.peersCallID;
+               if (info->pac_call_id != ntohs(*pcid)) {
+                       DEBUGP("%s for unknown call %u\n", 
+                               strMName[msg], ntohs(*pcid));
+                       break;
+               }
+               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
+               /* part two of the three-way handshake */
+               info->cstate = PPTP_CALL_IN_REP;
+               info->pns_call_id = ntohs(pptpReq->icack.callID);
+               break;
+
+       case PPTP_CALL_CLEAR_REQUEST:
+               /* client requests hangup of call */
+               if (info->sstate != PPTP_SESSION_CONFIRMED) {
+                       DEBUGP("CLEAR_CALL but no session\n");
+                       break;
+               }
+               /* FUTURE: iterate over all calls and check if
+                * call ID is valid.  We don't do this without newnat,
+                * because we only know about last call */
+               info->cstate = PPTP_CALL_CLEAR_REQ;
+               break;
+       case PPTP_SET_LINK_INFO:
+               break;
+       case PPTP_ECHO_REQUEST:
+       case PPTP_ECHO_REPLY:
+               /* I don't have to explain these ;) */
+               break;
+       default:
+               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 
+                       strMName[msg]:strMName[0], msg);
+               /* unknown: no need to create GRE masq table entry */
+               break;
+       }
+
+       return NF_ACCEPT;
+}
+
+
+/* track caller id inside control connection, call expect_related */
+static int 
+conntrack_pptp_help(struct sk_buff *skb,
+                   struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+
+{
+       struct pptp_pkt_hdr _pptph, *pptph;
+       
+       struct tcphdr _tcph, *tcph;
+       u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
+       u_int32_t datalen;
+       void *datalimit;
+       int dir = CTINFO2DIR(ctinfo);
+       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+       unsigned int nexthdr_off;
+
+       int oldsstate, oldcstate;
+       int ret;
+
+       /* don't do any tracking before tcp handshake complete */
+       if (ctinfo != IP_CT_ESTABLISHED 
+           && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
+               DEBUGP("ctinfo = %u, skipping\n", ctinfo);
+               return NF_ACCEPT;
+       }
+       
+       nexthdr_off = skb->nh.iph->ihl*4;
+       tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_tcph),
+                                 &_tcph);
+       if (!tcph)
+               return NF_ACCEPT;
+
+       /* not a complete TCP header? */
+       if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
+               DEBUGP("tcplen = %u\n", tcplen);
+               return NF_ACCEPT;
+       }
+
+
+       datalen = tcplen - tcph->doff * 4;
+
+       /* checksum invalid? */
+       if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr,
+                       csum_partial((char *) tcph, tcplen, 0))) {
+               printk(KERN_NOTICE __FILE__ ": bad csum\n");
+               /* W2K PPTP server sends TCP packets with wrong checksum :(( */
+               //return NF_ACCEPT;
+       }
+
+       if (tcph->fin || tcph->rst) {
+               DEBUGP("RST/FIN received, timeouting GRE\n");
+               /* can't do this after real newnat */
+               info->cstate = PPTP_CALL_NONE;
+
+               /* untrack this call id, unexpect GRE packets */
+               pptp_timeout_related(ct);
+       }
+
+       nexthdr_off += tcph->doff*4;
+       pptph = skb_header_pointer(skb, skb->nh.iph->ihl*4 + tcph->doff*4,
+                                  sizeof(_pptph), &_pptph);
+       if (!pptph) {
+               DEBUGP("no full PPTP header, can't track\n");
+               return NF_ACCEPT;
+       }
+
+       datalimit = (void *) pptph + datalen;
+
+       /* if it's not a control message we can't do anything with it */
+       if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
+           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
+               DEBUGP("not a control packet\n");
+               return NF_ACCEPT;
+       }
+
+       oldsstate = info->sstate;
+       oldcstate = info->cstate;
+
+       LOCK_BH(&ip_pptp_lock);
+
+       nexthdr_off += sizeof(_pptph);
+       /* FIXME: We just blindly assume that the control connection is always
+        * established from PNS->PAC.  However, RFC makes no guarantee */
+       if (dir == IP_CT_DIR_ORIGINAL)
+               /* client -> server (PNS -> PAC) */
+               ret = pptp_outbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
+       else
+               /* server -> client (PAC -> PNS) */
+               ret = pptp_inbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
+       DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
+               oldsstate, info->sstate, oldcstate, info->cstate);
+       UNLOCK_BH(&ip_pptp_lock);
+
+       return ret;
+}
+
+/* control protocol helper */
+static struct ip_conntrack_helper pptp = { 
+       .list = { NULL, NULL },
+       .name = "pptp", 
+       .flags = IP_CT_HELPER_F_REUSE_EXPECT,
+       .me = THIS_MODULE,
+       .max_expected = 2,
+       .timeout = 0,
+       .tuple = { .src = { .ip = 0, 
+                           .u = { .tcp = { .port =  
+                                   __constant_htons(PPTP_CONTROL_PORT) } } 
+                         }, 
+                  .dst = { .ip = 0, 
+                           .u = { .all = 0 },
+                           .protonum = IPPROTO_TCP
+                         } 
+                },
+       .mask = { .src = { .ip = 0, 
+                          .u = { .tcp = { .port = 0xffff } } 
+                        }, 
+                 .dst = { .ip = 0, 
+                          .u = { .all = 0 },
+                          .protonum = 0xffff 
+                        } 
+               },
+       .help = conntrack_pptp_help
+};
+
+/* ip_conntrack_pptp initialization */
+static int __init init(void)
+{
+       int retcode;
+
+       DEBUGP(__FILE__ ": registering helper\n");
+       if ((retcode = ip_conntrack_helper_register(&pptp))) {
+               printk(KERN_ERR "Unable to register conntrack application "
+                               "helper for pptp: %d\n", retcode);
+               return -EIO;
+       }
+
+       printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ip_conntrack_helper_unregister(&pptp);
+       printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
+
+EXPORT_SYMBOL(ip_pptp_lock);
diff --git a/net/ipv4/netfilter/ip_conntrack_pptp_priv.h b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
new file mode 100644 (file)
index 0000000..6b52564
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _IP_CT_PPTP_PRIV_H
+#define _IP_CT_PPTP_PRIV_H
+
+/* PptpControlMessageType names */
+static const char *strMName[] = {
+       "UNKNOWN_MESSAGE",
+       "START_SESSION_REQUEST",
+       "START_SESSION_REPLY",
+       "STOP_SESSION_REQUEST",
+       "STOP_SESSION_REPLY",
+       "ECHO_REQUEST",
+       "ECHO_REPLY",
+       "OUT_CALL_REQUEST",
+       "OUT_CALL_REPLY",
+       "IN_CALL_REQUEST",
+       "IN_CALL_REPLY",
+       "IN_CALL_CONNECT",
+       "CALL_CLEAR_REQUEST",
+       "CALL_DISCONNECT_NOTIFY",
+       "WAN_ERROR_NOTIFY",
+       "SET_LINK_INFO"
+};
+
+#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
new file mode 100644 (file)
index 0000000..013f759
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * ip_conntrack_proto_gre.c - Version 2.0 
+ *
+ * Connection tracking protocol helper module for GRE.
+ *
+ * GRE is a generic encapsulation protocol, which is generally not very
+ * suited for NAT, as it has no protocol-specific part as port numbers.
+ *
+ * It has an optional key field, which may help us distinguishing two 
+ * connections between the same two hosts.
+ *
+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
+ *
+ * PPTP is built on top of a modified version of GRE, and has a mandatory
+ * field called "CallID", which serves us for the same purpose as the key
+ * field in plain GRE.
+ *
+ * Documentation about PPTP can be found in RFC 2637
+ *
+ * (C) 2000-2004 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/list.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+DECLARE_RWLOCK(ip_ct_gre_lock);
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
+
+#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+
+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
+
+/* shamelessly stolen from ip_conntrack_proto_udp.c */
+#define GRE_TIMEOUT            (30*HZ)
+#define GRE_STREAM_TIMEOUT     (180*HZ)
+
+#if 0
+#define DEBUGP(format, args...)        printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
+#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \
+                       NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
+                       NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key))
+#else
+#define DEBUGP(x, args...)
+#define DUMP_TUPLE_GRE(x)
+#endif
+                               
+/* GRE KEYMAP HANDLING FUNCTIONS */
+static LIST_HEAD(gre_keymap_list);
+
+static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
+                               const struct ip_conntrack_tuple *t)
+{
+       return ((km->tuple.src.ip == t->src.ip) &&
+               (km->tuple.dst.ip == t->dst.ip) &&
+               (km->tuple.dst.protonum == t->dst.protonum) &&
+               (km->tuple.dst.u.all == t->dst.u.all));
+}
+
+/* look up the source key for a given tuple */
+static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
+{
+       struct ip_ct_gre_keymap *km;
+       u_int32_t key;
+
+       READ_LOCK(&ip_ct_gre_lock);
+       km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
+                       struct ip_ct_gre_keymap *, t);
+       if (!km) {
+               READ_UNLOCK(&ip_ct_gre_lock);
+               return 0;
+       }
+
+       key = km->tuple.src.u.gre.key;
+       READ_UNLOCK(&ip_ct_gre_lock);
+
+       return key;
+}
+
+/* add a single keymap entry, associate with specified expect */
+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
+                        struct ip_conntrack_tuple *t, int reply)
+{
+       struct ip_ct_gre_keymap *km;
+
+       km = kmalloc(sizeof(*km), GFP_ATOMIC);
+       if (!km)
+               return -1;
+
+       /* initializing list head should be sufficient */
+       memset(km, 0, sizeof(*km));
+
+       memcpy(&km->tuple, t, sizeof(*t));
+
+       if (!reply)
+               exp->proto.gre.keymap_orig = km;
+       else
+               exp->proto.gre.keymap_reply = km;
+
+       DEBUGP("adding new entry %p: ", km);
+       DUMP_TUPLE_GRE(&km->tuple);
+
+       WRITE_LOCK(&ip_ct_gre_lock);
+       list_append(&gre_keymap_list, km);
+       WRITE_UNLOCK(&ip_ct_gre_lock);
+
+       return 0;
+}
+
+/* change the tuple of a keymap entry (used by nat helper) */
+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
+                            struct ip_conntrack_tuple *t)
+{
+        if (!km)
+        {
+                printk(KERN_WARNING
+                        "NULL GRE conntrack keymap change requested\n");
+                return;
+        }
+
+       DEBUGP("changing entry %p to: ", km);
+       DUMP_TUPLE_GRE(t);
+
+       WRITE_LOCK(&ip_ct_gre_lock);
+       memcpy(&km->tuple, t, sizeof(km->tuple));
+       WRITE_UNLOCK(&ip_ct_gre_lock);
+}
+
+/* destroy the keymap entries associated with specified expect */
+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
+{
+       DEBUGP("entering for exp %p\n", exp);
+       WRITE_LOCK(&ip_ct_gre_lock);
+       if (exp->proto.gre.keymap_orig) {
+               DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
+               list_del(&exp->proto.gre.keymap_orig->list);
+               kfree(exp->proto.gre.keymap_orig);
+               exp->proto.gre.keymap_orig = NULL;
+       }
+       if (exp->proto.gre.keymap_reply) {
+               DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
+               list_del(&exp->proto.gre.keymap_reply->list);
+               kfree(exp->proto.gre.keymap_reply);
+               exp->proto.gre.keymap_reply = NULL;
+       }
+       WRITE_UNLOCK(&ip_ct_gre_lock);
+}
+
+
+/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
+
+/* invert gre part of tuple */
+static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
+                           const struct ip_conntrack_tuple *orig)
+{
+       tuple->dst.u.gre.key = orig->src.u.gre.key;
+       tuple->src.u.gre.key = orig->dst.u.gre.key;
+
+       return 1;
+}
+
+/* gre hdr info to tuple */
+static int gre_pkt_to_tuple(const struct sk_buff *skb,
+                          unsigned int dataoff,
+                          struct ip_conntrack_tuple *tuple)
+{
+       struct gre_hdr _grehdr, *grehdr;
+       struct gre_hdr_pptp _pgrehdr, *pgrehdr;
+       u_int32_t srckey;
+
+       grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
+       /* PPTP header is variable length, only need up to the call_id field */
+       pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
+
+       if (!grehdr || !pgrehdr)
+               return 0;
+
+       switch (grehdr->version) {
+               case GRE_VERSION_1701:
+                       if (!grehdr->key) {
+                               DEBUGP("Can't track GRE without key\n");
+                               return 0;
+                       }
+                       tuple->dst.u.gre.key = *(gre_key(grehdr));
+                       break;
+
+               case GRE_VERSION_PPTP:
+                       if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
+                               DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
+                               return 0;
+                       }
+                       tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
+                       break;
+
+               default:
+                       printk(KERN_WARNING "unknown GRE version %hu\n",
+                               grehdr->version);
+                       return 0;
+       }
+
+       srckey = gre_keymap_lookup(tuple);
+
+       tuple->src.u.gre.key = srckey;
+#if 0
+       DEBUGP("found src key %x for tuple ", ntohl(srckey));
+       DUMP_TUPLE_GRE(tuple);
+#endif
+
+       return 1;
+}
+
+/* print gre part of tuple */
+static unsigned int gre_print_tuple(char *buffer,
+                                   const struct ip_conntrack_tuple *tuple)
+{
+       return sprintf(buffer, "srckey=0x%x dstkey=0x%x ", 
+                      ntohl(tuple->src.u.gre.key),
+                      ntohl(tuple->dst.u.gre.key));
+}
+
+/* print private data for conntrack */
+static unsigned int gre_print_conntrack(char *buffer,
+                                       const struct ip_conntrack *ct)
+{
+       return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
+                      (ct->proto.gre.timeout / HZ),
+                      (ct->proto.gre.stream_timeout / HZ));
+}
+
+/* Returns verdict for packet, and may modify conntrack */
+static int gre_packet(struct ip_conntrack *ct,
+                     const struct sk_buff *skb,
+                     enum ip_conntrack_info conntrackinfo)
+{
+       /* If we've seen traffic both ways, this is a GRE connection.
+        * Extend timeout. */
+       if (ct->status & IPS_SEEN_REPLY) {
+               ip_ct_refresh_acct(ct, conntrackinfo, skb,
+                                  ct->proto.gre.stream_timeout);
+               /* Also, more likely to be important, and not a probe. */
+               set_bit(IPS_ASSURED_BIT, &ct->status);
+       } else
+               ip_ct_refresh_acct(ct, conntrackinfo, skb,
+                                  ct->proto.gre.timeout);
+       
+       return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int gre_new(struct ip_conntrack *ct,
+                  const struct sk_buff *skb)
+{ 
+       DEBUGP(": ");
+       DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+
+       /* initialize to sane value.  Ideally a conntrack helper
+        * (e.g. in case of pptp) is increasing them */
+       ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
+       ct->proto.gre.timeout = GRE_TIMEOUT;
+
+       return 1;
+}
+
+/* Called when a conntrack entry has already been removed from the hashes
+ * and is about to be deleted from memory */
+static void gre_destroy(struct ip_conntrack *ct)
+{
+       struct ip_conntrack_expect *master = ct->master;
+
+       DEBUGP(" entering\n");
+
+       if (!master) {
+               DEBUGP("no master exp for ct %p\n", ct);
+               return;
+       }
+
+       ip_ct_gre_keymap_destroy(master);
+}
+
+/* protocol helper struct */
+static struct ip_conntrack_protocol gre = { 
+       .proto           = IPPROTO_GRE,
+       .name            = "gre", 
+       .pkt_to_tuple    = gre_pkt_to_tuple,
+       .invert_tuple    = gre_invert_tuple,
+       .print_tuple     = gre_print_tuple,
+       .print_conntrack = gre_print_conntrack,
+       .packet          = gre_packet,
+       .new             = gre_new,
+       .destroy         = gre_destroy,
+       .exp_matches_pkt = NULL,
+       .me              = THIS_MODULE
+};
+
+/* ip_conntrack_proto_gre initialization */
+static int __init init(void)
+{
+       int retcode;
+
+       if ((retcode = ip_conntrack_protocol_register(&gre))) {
+               printk(KERN_ERR "Unable to register conntrack protocol "
+                      "helper for gre: %d\n", retcode);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       struct list_head *pos, *n;
+
+       /* delete all keymap entries */
+       WRITE_LOCK(&ip_ct_gre_lock);
+       list_for_each_safe(pos, n, &gre_keymap_list) {
+               DEBUGP("deleting keymap %p at module unload time\n", pos);
+               list_del(pos);
+               kfree(pos);
+       }
+       WRITE_UNLOCK(&ip_ct_gre_lock);
+
+       ip_conntrack_protocol_unregister(&gre); 
+}
+
+EXPORT_SYMBOL(ip_ct_gre_keymap_add);
+EXPORT_SYMBOL(ip_ct_gre_keymap_change);
+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_pptp.c b/net/ipv4/netfilter/ip_nat_pptp.c
new file mode 100644 (file)
index 0000000..2bbb815
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * ip_nat_pptp.c       - Version 2.0
+ *
+ * NAT support for PPTP (Point to Point Tunneling Protocol).
+ * PPTP is a a protocol for creating virtual private networks.
+ * It is a specification defined by Microsoft and some vendors
+ * working with Microsoft.  PPTP is built on top of a modified
+ * version of the Internet Generic Routing Encapsulation Protocol.
+ * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
+ * PPTP can be found in RFC 2637
+ *
+ * (C) 2000-2004 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ *
+ * TODO: - Support for multiple calls within one session
+ *        (needs netfilter newnat code)
+ *      - NAT to a unique tuple, not to TCP source port
+ *        (needs netfilter tuple reservation)
+ *
+ * Changes:
+ *     2002-02-10 - Version 1.3
+ *       - Use ip_nat_mangle_tcp_packet() because of cloned skb's
+ *        in local connections (Philip Craig <philipc@snapgear.com>)
+ *       - add checks for magicCookie and pptp version
+ *       - make argument list of pptp_{out,in}bound_packet() shorter
+ *       - move to C99 style initializers
+ *       - print version number at module loadtime
+ *     2003-09-22 - Version 1.5
+ *       - use SNATed tcp sourceport as callid, since we get called before
+ *        TCP header is mangled (Philip Craig <philipc@snapgear.com>)
+ *     2004-10-22 - Version 2.0
+ *       - kernel 2.6.x version
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_pptp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+
+#define IP_NAT_PPTP_VERSION "2.0"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
+
+
+#if 0
+#include "ip_conntrack_pptp_priv.h"
+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
+                                      ": " format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static unsigned int
+pptp_nat_expected(struct sk_buff **pskb,
+                 unsigned int hooknum,
+                 struct ip_conntrack *ct,
+                 struct ip_nat_info *info)
+{
+       struct ip_conntrack *master = master_ct(ct);
+       struct ip_nat_multi_range mr;
+       struct ip_ct_pptp_master *ct_pptp_info;
+       struct ip_nat_pptp *nat_pptp_info;
+       u_int32_t newip, newcid;
+       int ret;
+
+       IP_NF_ASSERT(info);
+       IP_NF_ASSERT(master);
+       IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+       DEBUGP("we have a connection!\n");
+
+       LOCK_BH(&ip_pptp_lock);
+       ct_pptp_info = &master->help.ct_pptp_info;
+       nat_pptp_info = &master->nat.help.nat_pptp_info;
+
+       /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
+        * (unmanipulated) values */
+       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
+               DEBUGP("completing tuples with NAT info \n");
+               /* we can do this, since we're unconfirmed */
+               if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
+                       htonl(ct_pptp_info->pac_call_id)) {     
+                       /* assume PNS->PAC */
+                       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
+                               htonl(nat_pptp_info->pns_call_id);
+                       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
+                               htonl(nat_pptp_info->pns_call_id);
+                       newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+                       newcid = htonl(nat_pptp_info->pac_call_id);
+               } else {
+                       /* assume PAC->PNS */
+                       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
+                               htonl(nat_pptp_info->pac_call_id);
+                       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
+                               htonl(nat_pptp_info->pac_call_id);
+                       newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+                       newcid = htonl(nat_pptp_info->pns_call_id);
+               }
+       } else {
+               if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
+                       htonl(ct_pptp_info->pac_call_id)) {     
+                       /* assume PNS->PAC */
+                       newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+                       newcid = htonl(ct_pptp_info->pns_call_id);
+               }
+               else {
+                       /* assume PAC->PNS */
+                       newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+                       newcid = htonl(ct_pptp_info->pac_call_id);
+               }
+       }
+
+       mr.rangesize = 1;
+       mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
+       mr.range[0].min_ip = mr.range[0].max_ip = newip;
+       mr.range[0].min = mr.range[0].max = 
+               ((union ip_conntrack_manip_proto ) { newcid }); 
+       DEBUGP("change ip to %u.%u.%u.%u\n", 
+               NIPQUAD(newip));
+       DEBUGP("change key to 0x%x\n", ntohl(newcid));
+       ret = ip_nat_setup_info(ct, &mr, hooknum);
+
+       UNLOCK_BH(&ip_pptp_lock);
+
+       return ret;
+
+}
+
+/* outbound packets == from PNS to PAC */
+static inline unsigned int
+pptp_outbound_pkt(struct sk_buff **pskb,
+                 struct ip_conntrack *ct,
+                 enum ip_conntrack_info ctinfo,
+                 struct ip_conntrack_expect *exp)
+
+{
+       struct iphdr *iph = (*pskb)->nh.iph;
+       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
+       struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) 
+                                       ((void *)tcph + tcph->doff*4);
+
+       struct PptpControlHeader *ctlh;
+       union pptp_ctrl_union *pptpReq;
+       struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
+       struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
+
+       u_int16_t msg, *cid = NULL, new_callid;
+
+       /* FIXME: size checks !!! */
+       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
+       pptpReq = (void *) ((void *) ctlh + sizeof(*ctlh));
+
+       new_callid = htons(ct_pptp_info->pns_call_id);
+       
+       switch (msg = ntohs(ctlh->messageType)) {
+               case PPTP_OUT_CALL_REQUEST:
+                       cid = &pptpReq->ocreq.callID;
+                       /* FIXME: ideally we would want to reserve a call ID
+                        * here.  current netfilter NAT core is not able to do
+                        * this :( For now we use TCP source port. This breaks
+                        * multiple calls within one control session */
+
+                       /* save original call ID in nat_info */
+                       nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
+
+                       /* don't use tcph->source since we are at a DSTmanip
+                        * hook (e.g. PREROUTING) and pkt is not mangled yet */
+                       new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
+
+                       /* save new call ID in ct info */
+                       ct_pptp_info->pns_call_id = ntohs(new_callid);
+                       break;
+               case PPTP_IN_CALL_REPLY:
+                       cid = &pptpReq->icreq.callID;
+                       break;
+               case PPTP_CALL_CLEAR_REQUEST:
+                       cid = &pptpReq->clrreq.callID;
+                       break;
+               default:
+                       DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
+                             (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
+                       /* fall through */
+
+               case PPTP_SET_LINK_INFO:
+                       /* only need to NAT in case PAC is behind NAT box */
+               case PPTP_START_SESSION_REQUEST:
+               case PPTP_START_SESSION_REPLY:
+               case PPTP_STOP_SESSION_REQUEST:
+               case PPTP_STOP_SESSION_REPLY:
+               case PPTP_ECHO_REQUEST:
+               case PPTP_ECHO_REPLY:
+                       /* no need to alter packet */
+                       return NF_ACCEPT;
+       }
+
+       IP_NF_ASSERT(cid);
+
+       DEBUGP("altering call id from 0x%04x to 0x%04x\n",
+               ntohs(*cid), ntohs(new_callid));
+
+       /* mangle packet */
+       ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
+                                sizeof(new_callid), (char *)&new_callid,
+                                sizeof(new_callid));
+
+       return NF_ACCEPT;
+}
+
+/* inbound packets == from PAC to PNS */
+static inline unsigned int
+pptp_inbound_pkt(struct sk_buff **pskb,
+                struct ip_conntrack *ct,
+                enum ip_conntrack_info ctinfo,
+                struct ip_conntrack_expect *oldexp)
+{
+       struct iphdr *iph = (*pskb)->nh.iph;
+       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
+       struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) 
+                                       ((void *)tcph + tcph->doff*4);
+
+       struct PptpControlHeader *ctlh;
+       union pptp_ctrl_union *pptpReq;
+       struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
+       struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
+
+       u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
+       u_int32_t old_dst_ip;
+
+       struct ip_conntrack_tuple t, inv_t;
+       struct ip_conntrack_tuple *orig_t, *reply_t;
+
+       /* FIXME: size checks !!! */
+       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
+       pptpReq = (void *) ((void *) ctlh + sizeof(*ctlh));
+
+       new_pcid = htons(nat_pptp_info->pns_call_id);
+
+       switch (msg = ntohs(ctlh->messageType)) {
+       case PPTP_OUT_CALL_REPLY:
+               pcid = &pptpReq->ocack.peersCallID;     
+               cid = &pptpReq->ocack.callID;
+               if (!oldexp) {
+                       DEBUGP("outcall but no expectation\n");
+                       break;
+               }
+               old_dst_ip = oldexp->tuple.dst.ip;
+               t = oldexp->tuple;
+               invert_tuplepr(&inv_t, &t);
+
+               /* save original PAC call ID in nat_info */
+               nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
+
+               /* alter expectation */
+               orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+               reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+               if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
+                       /* expectation for PNS->PAC direction */
+                       t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
+                       t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
+                       inv_t.src.ip = reply_t->src.ip;
+                       inv_t.dst.ip = reply_t->dst.ip;
+                       inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
+                       inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
+               } else {
+                       /* expectation for PAC->PNS direction */
+                       t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
+                       t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
+                       inv_t.src.ip = orig_t->src.ip;
+                       inv_t.dst.ip = orig_t->dst.ip;
+                       inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
+                       inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
+               }
+
+               if (!ip_conntrack_change_expect(oldexp, &t)) {
+                       DEBUGP("successfully changed expect\n");
+               } else {
+                       DEBUGP("can't change expect\n");
+               }
+               ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
+               ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
+               break;
+       case PPTP_IN_CALL_CONNECT:
+               pcid = &pptpReq->iccon.peersCallID;
+               if (!oldexp)
+                       break;
+               old_dst_ip = oldexp->tuple.dst.ip;
+               t = oldexp->tuple;
+
+               /* alter expectation, no need for callID */
+               if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
+                       /* expectation for PNS->PAC direction */
+                       t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+               } else {
+                       /* expectation for PAC->PNS direction */
+                       t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+               }
+
+               if (!ip_conntrack_change_expect(oldexp, &t)) {
+                       DEBUGP("successfully changed expect\n");
+               } else {
+                       DEBUGP("can't change expect\n");
+               }
+               break;
+       case PPTP_IN_CALL_REQUEST:
+               /* only need to nat in case PAC is behind NAT box */
+               break;
+       case PPTP_WAN_ERROR_NOTIFY:
+               pcid = &pptpReq->wanerr.peersCallID;
+               break;
+       case PPTP_CALL_DISCONNECT_NOTIFY:
+               pcid = &pptpReq->disc.callID;
+               break;
+
+       default:
+               DEBUGP("unknown inbound packet %s\n",
+                       (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
+               /* fall through */
+
+       case PPTP_START_SESSION_REQUEST:
+       case PPTP_START_SESSION_REPLY:
+       case PPTP_STOP_SESSION_REQUEST:
+       case PPTP_STOP_SESSION_REPLY:
+       case PPTP_ECHO_REQUEST:
+       case PPTP_ECHO_REPLY:
+               /* no need to alter packet */
+               return NF_ACCEPT;
+       }
+
+       /* mangle packet */
+       IP_NF_ASSERT(pcid);
+       DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
+               ntohs(*pcid), ntohs(new_pcid));
+       ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
+                                sizeof(new_pcid), (char *)&new_pcid, 
+                                sizeof(new_pcid));
+
+       if (new_cid) {
+               IP_NF_ASSERT(cid);
+               DEBUGP("altering call id from 0x%04x to 0x%04x\n",
+                       ntohs(*cid), ntohs(new_cid));
+               ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
+                                        (void *)cid - (void *)pptph, 
+                                        sizeof(new_cid), (char *)&new_cid, 
+                                        sizeof(new_cid));
+       }
+
+       /* great, at least we don't need to resize packets */
+       return NF_ACCEPT;
+}
+
+
+static unsigned int tcp_help(struct ip_conntrack *ct,
+                            struct ip_conntrack_expect *exp,
+                            struct ip_nat_info *info,
+                            enum ip_conntrack_info ctinfo,
+                            unsigned int hooknum, struct sk_buff **pskb)
+{
+       struct iphdr *iph = (*pskb)->nh.iph;
+       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
+       unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+       struct pptp_pkt_hdr *pptph;
+
+       int dir;
+
+       DEBUGP("entering\n");
+
+       /* Only mangle things once: DST for original direction
+          and SRC for reply direction. */
+       dir = CTINFO2DIR(ctinfo);
+       if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
+            && dir == IP_CT_DIR_ORIGINAL)
+             || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
+                 && dir == IP_CT_DIR_REPLY))) {
+               DEBUGP("Not touching dir %s at hook %s\n",
+                      dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+                      hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+                      : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+                      : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
+                      : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
+               return NF_ACCEPT;
+       }
+
+       /* if packet is too small, just skip it */
+       if (datalen < sizeof(struct pptp_pkt_hdr)+
+                     sizeof(struct PptpControlHeader)) {
+               DEBUGP("pptp packet too short\n");
+               return NF_ACCEPT;       
+       }
+
+       pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
+
+       /* if it's not a control message, we can't handle it */
+       if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
+           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
+               DEBUGP("not a pptp control packet\n");
+               return NF_ACCEPT;
+       }
+
+       LOCK_BH(&ip_pptp_lock);
+
+       if (dir == IP_CT_DIR_ORIGINAL) {
+               /* reuqests sent by client to server (PNS->PAC) */
+               pptp_outbound_pkt(pskb, ct, ctinfo, exp);
+       } else {
+               /* response from the server to the client (PAC->PNS) */
+               pptp_inbound_pkt(pskb, ct, ctinfo, exp);
+       }
+
+       UNLOCK_BH(&ip_pptp_lock);
+
+       return NF_ACCEPT;
+}
+
+/* nat helper struct for control connection */
+static struct ip_nat_helper pptp_tcp_helper = { 
+       .list = { NULL, NULL },
+       .name = "pptp", 
+       .flags = IP_NAT_HELPER_F_ALWAYS, 
+       .me = THIS_MODULE,
+       .tuple = { .src = { .ip = 0, 
+                           .u = { .tcp = { .port = 
+                                       __constant_htons(PPTP_CONTROL_PORT) } 
+                                } 
+                         },
+                  .dst = { .ip = 0, 
+                           .u = { .all = 0 }, 
+                           .protonum = IPPROTO_TCP 
+                         } 
+                },
+
+       .mask = { .src = { .ip = 0, 
+                          .u = { .tcp = { .port = 0xFFFF } } 
+                        },
+                 .dst = { .ip = 0, 
+                          .u = { .all = 0 }, 
+                          .protonum = 0xFFFF 
+                        } 
+               },
+       .help = tcp_help, 
+       .expect = pptp_nat_expected 
+};
+
+                         
+static int __init init(void)
+{
+       DEBUGP("%s: registering NAT helper\n", __FILE__);
+       if (ip_nat_helper_register(&pptp_tcp_helper)) {
+               printk(KERN_ERR "Unable to register NAT application helper "
+                               "for pptp\n");
+               return -EIO;
+       }
+
+       printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       DEBUGP("cleanup_module\n" );
+       ip_nat_helper_unregister(&pptp_tcp_helper);
+       printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c
new file mode 100644 (file)
index 0000000..5691a10
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * ip_nat_proto_gre.c - Version 2.0
+ *
+ * NAT protocol helper module for GRE.
+ *
+ * GRE is a generic encapsulation protocol, which is generally not very
+ * suited for NAT, as it has no protocol-specific part as port numbers.
+ *
+ * It has an optional key field, which may help us distinguishing two 
+ * connections between the same two hosts.
+ *
+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
+ *
+ * PPTP is built on top of a modified version of GRE, and has a mandatory
+ * field called "CallID", which serves us for the same purpose as the key
+ * field in plain GRE.
+ *
+ * Documentation about PPTP can be found in RFC 2637
+ *
+ * (C) 2000-2004 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
+
+#if 0
+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
+                                      ": " format, ## args)
+#else
+#define DEBUGP(x, args...)
+#endif
+
+/* is key in given range between min and max */
+static int
+gre_in_range(const struct ip_conntrack_tuple *tuple,
+            enum ip_nat_manip_type maniptype,
+            const union ip_conntrack_manip_proto *min,
+            const union ip_conntrack_manip_proto *max)
+{
+       u_int32_t key;
+
+       if (maniptype == IP_NAT_MANIP_SRC)
+               key = tuple->src.u.gre.key;
+       else
+               key = tuple->dst.u.gre.key;
+
+       return ntohl(key) >= ntohl(min->gre.key)
+               && ntohl(key) <= ntohl(max->gre.key);
+}
+
+/* generate unique tuple ... */
+static int 
+gre_unique_tuple(struct ip_conntrack_tuple *tuple,
+                const struct ip_nat_range *range,
+                enum ip_nat_manip_type maniptype,
+                const struct ip_conntrack *conntrack)
+{
+       u_int32_t min, i, range_size;
+       u_int32_t key = 0, *keyptr;
+
+       if (maniptype == IP_NAT_MANIP_SRC)
+               keyptr = &tuple->src.u.gre.key;
+       else
+               keyptr = &tuple->dst.u.gre.key;
+
+       if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
+               DEBUGP("%p: NATing GRE PPTP\n", conntrack);
+               min = 1;
+               range_size = 0xffff;
+       } else {
+               min = ntohl(range->min.gre.key);
+               range_size = ntohl(range->max.gre.key) - min + 1;
+       }
+
+       DEBUGP("min = %u, range_size = %u\n", min, range_size); 
+
+       for (i = 0; i < range_size; i++, key++) {
+               *keyptr = htonl(min + key % range_size);
+               if (!ip_nat_used_tuple(tuple, conntrack))
+                       return 1;
+       }
+
+       DEBUGP("%p: no NAT mapping\n", conntrack);
+
+       return 0;
+}
+
+/* manipulate a GRE packet according to maniptype */
+static int
+gre_manip_pkt(struct sk_buff **pskb,
+             unsigned int hdroff,
+             const struct ip_conntrack_manip *manip,
+             enum ip_nat_manip_type maniptype)
+{
+       struct gre_hdr *greh;
+       struct gre_hdr_pptp *pgreh;
+
+       if (!skb_ip_make_writable(pskb, hdroff + sizeof(*pgreh)))
+               return 0;
+
+       greh = (void *)(*pskb)->data + hdroff;
+       pgreh = (struct gre_hdr_pptp *) greh;
+
+       /* we only have destination manip of a packet, since 'source key' 
+        * is not present in the packet itself */
+       if (maniptype == IP_NAT_MANIP_DST) {
+               /* key manipulation is always dest */
+               switch (greh->version) {
+               case 0:
+                       if (!greh->key) {
+                               DEBUGP("can't nat GRE w/o key\n");
+                               break;
+                       }
+                       if (greh->csum) {
+                               /* FIXME: Never tested this code... */
+                               *(gre_csum(greh)) = 
+                                       ip_nat_cheat_check(~*(gre_key(greh)),
+                                                       manip->u.gre.key,
+                                                       *(gre_csum(greh)));
+                       }
+                       *(gre_key(greh)) = manip->u.gre.key;
+                       break;
+               case GRE_VERSION_PPTP:
+                       DEBUGP("call_id -> 0x%04x\n", 
+                               ntohl(manip->u.gre.key));
+                       pgreh->call_id = htons(ntohl(manip->u.gre.key));
+                       break;
+               default:
+                       DEBUGP("can't nat unknown GRE version\n");
+                       return 0;
+                       break;
+               }
+       }
+       return 1;
+}
+
+/* print out a nat tuple */
+static unsigned int 
+gre_print(char *buffer, 
+         const struct ip_conntrack_tuple *match,
+         const struct ip_conntrack_tuple *mask)
+{
+       unsigned int len = 0;
+
+       if (mask->src.u.gre.key)
+               len += sprintf(buffer + len, "srckey=0x%x ", 
+                               ntohl(match->src.u.gre.key));
+
+       if (mask->dst.u.gre.key)
+               len += sprintf(buffer + len, "dstkey=0x%x ",
+                               ntohl(match->src.u.gre.key));
+
+       return len;
+}
+
+/* print a range of keys */
+static unsigned int 
+gre_print_range(char *buffer, const struct ip_nat_range *range)
+{
+       if (range->min.gre.key != 0 
+           || range->max.gre.key != 0xFFFF) {
+               if (range->min.gre.key == range->max.gre.key)
+                       return sprintf(buffer, "key 0x%x ",
+                                       ntohl(range->min.gre.key));
+               else
+                       return sprintf(buffer, "keys 0x%u-0x%u ",
+                                       ntohl(range->min.gre.key),
+                                       ntohl(range->max.gre.key));
+       } else
+               return 0;
+}
+
+/* nat helper struct */
+static struct ip_nat_protocol gre = { 
+       .name           = "GRE", 
+       .protonum       = IPPROTO_GRE,
+       .manip_pkt      = gre_manip_pkt,
+       .in_range       = gre_in_range,
+       .unique_tuple   = gre_unique_tuple,
+       .print          = gre_print,
+       .print_range    = gre_print_range 
+};
+                                 
+static int __init init(void)
+{
+       if (ip_nat_protocol_register(&gre))
+               return -EIO;
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ip_nat_protocol_unregister(&gre);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
new file mode 100644 (file)
index 0000000..191cec7
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * xfrm4_output.c - Common IPsec encapsulation code for IPv4.
+ * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
+ * 
+ * This program is free software; 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.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <net/inet_ecn.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/icmp.h>
+
+/* Add encapsulation header.
+ *
+ * In transport mode, the IP header will be moved forward to make space
+ * for the encapsulation header.
+ *
+ * In tunnel mode, the top IP header will be constructed per RFC 2401.
+ * The following fields in it shall be filled in by x->type->output:
+ *     tot_len
+ *     check
+ *
+ * On exit, skb->h will be set to the start of the payload to be processed
+ * by x->type->output and skb->nh will be set to the top IP header.
+ */
+static void xfrm4_encap(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb->dst;
+       struct xfrm_state *x = dst->xfrm;
+       struct iphdr *iph, *top_iph;
+
+       iph = skb->nh.iph;
+       skb->h.ipiph = iph;
+
+       skb->nh.raw = skb_push(skb, x->props.header_len);
+       top_iph = skb->nh.iph;
+
+       if (!x->props.mode) {
+               skb->h.raw += iph->ihl*4;
+               memmove(top_iph, iph, iph->ihl*4);
+               return;
+       }
+
+       top_iph->ihl = 5;
+       top_iph->version = 4;
+
+       /* DS disclosed */
+       top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
+       if (x->props.flags & XFRM_STATE_NOECN)
+               IP_ECN_clear(top_iph);
+
+       top_iph->frag_off = iph->frag_off & htons(IP_DF);
+       if (!top_iph->frag_off)
+               __ip_select_ident(top_iph, dst, 0);
+
+       /* TTL disclosed */
+       top_iph->ttl = iph->ttl;
+
+       top_iph->saddr = x->props.saddr.a4;
+       top_iph->daddr = x->id.daddr.a4;
+       top_iph->protocol = IPPROTO_IPIP;
+
+       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+}
+
+static int xfrm4_tunnel_check_size(struct sk_buff *skb)
+{
+       int mtu, ret = 0;
+       struct dst_entry *dst;
+       struct iphdr *iph = skb->nh.iph;
+
+       if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
+               goto out;
+
+       IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       
+       if (!(iph->frag_off & htons(IP_DF)))
+               goto out;
+
+       dst = skb->dst;
+       mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
+       if (skb->len > mtu) {
+               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+               ret = -EMSGSIZE;
+       }
+out:
+       return ret;
+}
+
+int xfrm4_output(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct dst_entry *dst = skb->dst;
+       struct xfrm_state *x = dst->xfrm;
+       int err;
+       
+       if (skb->ip_summed == CHECKSUM_HW) {
+               err = skb_checksum_help(pskb, 0);
+               skb = *pskb;
+               if (err)
+                       goto error_nolock;
+       }
+
+       spin_lock_bh(&x->lock);
+       err = xfrm_state_check(x, skb);
+       if (err)
+               goto error;
+
+       if (x->props.mode) {
+               err = xfrm4_tunnel_check_size(skb);
+               if (err)
+                       goto error;
+       }
+
+       xfrm4_encap(skb);
+
+       err = x->type->output(pskb);
+       skb = *pskb;
+       if (err)
+               goto error;
+
+       x->curlft.bytes += skb->len;
+       x->curlft.packets++;
+
+       spin_unlock_bh(&x->lock);
+       
+       if (!(skb->dst = dst_pop(dst))) {
+               err = -EHOSTUNREACH;
+               goto error_nolock;
+       }
+       err = NET_XMIT_BYPASS;
+
+out_exit:
+       return err;
+error:
+       spin_unlock_bh(&x->lock);
+error_nolock:
+       kfree_skb(skb);
+       goto out_exit;
+}
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
new file mode 100644 (file)
index 0000000..712856f
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * xfrm6_output.c - Common IPsec encapsulation code for IPv6.
+ * Copyright (C) 2002 USAGI/WIDE Project
+ * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
+ * 
+ * This program is free software; 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.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/icmpv6.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * In transport mode, the IP header and mutable extension headers will be moved
+ * forward to make space for the encapsulation header.
+ *
+ * In tunnel mode, the top IP header will be constructed per RFC 2401.
+ * The following fields in it shall be filled in by x->type->output:
+ *     payload_len
+ *
+ * On exit, skb->h will be set to the start of the encapsulation header to be
+ * filled in by x->type->output and skb->nh will be set to the nextheader field
+ * of the extension header directly preceding the encapsulation header, or in
+ * its absence, that of the top IP header.  The value of skb->data will always
+ * point to the top IP header.
+ */
+static void xfrm6_encap(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb->dst;
+       struct xfrm_state *x = dst->xfrm;
+       struct ipv6hdr *iph, *top_iph;
+
+       skb_push(skb, x->props.header_len);
+       iph = skb->nh.ipv6h;
+
+       if (!x->props.mode) {
+               u8 *prevhdr;
+               int hdr_len;
+
+               hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
+               skb->nh.raw = prevhdr - x->props.header_len;
+               skb->h.raw = skb->data + hdr_len;
+               memmove(skb->data, iph, hdr_len);
+               return;
+       }
+
+       skb->nh.raw = skb->data;
+       top_iph = skb->nh.ipv6h;
+       skb->nh.raw = &top_iph->nexthdr;
+       skb->h.ipv6h = top_iph + 1;
+
+       top_iph->version = 6;
+       top_iph->priority = iph->priority;
+       if (x->props.flags & XFRM_STATE_NOECN)
+               IP6_ECN_clear(top_iph);
+       top_iph->flow_lbl[0] = iph->flow_lbl[0];
+       top_iph->flow_lbl[1] = iph->flow_lbl[1];
+       top_iph->flow_lbl[2] = iph->flow_lbl[2];
+       top_iph->nexthdr = IPPROTO_IPV6; 
+       top_iph->hop_limit = iph->hop_limit;
+       ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+       ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+}
+
+static int xfrm6_tunnel_check_size(struct sk_buff *skb)
+{
+       int mtu, ret = 0;
+       struct dst_entry *dst = skb->dst;
+
+       mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
+       if (mtu < IPV6_MIN_MTU)
+               mtu = IPV6_MIN_MTU;
+
+       if (skb->len > mtu) {
+               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+               ret = -EMSGSIZE;
+       }
+
+       return ret;
+}
+
+int xfrm6_output(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct dst_entry *dst = skb->dst;
+       struct xfrm_state *x = dst->xfrm;
+       int err;
+       
+       if (skb->ip_summed == CHECKSUM_HW) {
+               err = skb_checksum_help(pskb, 0);
+               skb = *pskb;
+               if (err)
+                       goto error_nolock;
+       }
+
+       spin_lock_bh(&x->lock);
+       err = xfrm_state_check(x, skb);
+       if (err)
+               goto error;
+
+       if (x->props.mode) {
+               err = xfrm6_tunnel_check_size(skb);
+               if (err)
+                       goto error;
+       }
+
+       xfrm6_encap(skb);
+
+       err = x->type->output(pskb);
+       skb = *pskb;
+       if (err)
+               goto error;
+
+       x->curlft.bytes += skb->len;
+       x->curlft.packets++;
+
+       spin_unlock_bh(&x->lock);
+
+       skb->nh.raw = skb->data;
+       
+       if (!(skb->dst = dst_pop(dst))) {
+               err = -EHOSTUNREACH;
+               goto error_nolock;
+       }
+       err = NET_XMIT_BYPASS;
+
+out_exit:
+       return err;
+error:
+       spin_unlock_bh(&x->lock);
+error_nolock:
+       kfree_skb(skb);
+       goto out_exit;
+}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
new file mode 100644 (file)
index 0000000..5766a13
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C)2003,2004 USAGI/WIDE Project
+ *
+ * This program is free software; 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
+ *
+ * Authors     Mitsuru KANDA  <mk@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *
+ * Based on net/ipv4/xfrm4_tunnel.c
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/xfrm.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
+# define X6TDEBUG      3
+#else
+# define X6TDEBUG      1
+#endif
+
+#define X6TPRINTK(fmt, args...)                printk(fmt, ## args)
+#define X6TNOPRINTK(fmt, args...)      do { ; } while(0)
+
+#if X6TDEBUG >= 1
+# define X6TPRINTK1    X6TPRINTK
+#else
+# define X6TPRINTK1    X6TNOPRINTK
+#endif
+
+#if X6TDEBUG >= 3
+# define X6TPRINTK3    X6TPRINTK
+#else
+# define X6TPRINTK3    X6TNOPRINTK
+#endif
+
+/*
+ * xfrm_tunnel_spi things are for allocating unique id ("spi") 
+ * per xfrm_address_t.
+ */
+struct xfrm6_tunnel_spi {
+       struct hlist_node list_byaddr;
+       struct hlist_node list_byspi;
+       xfrm_address_t addr;
+       u32 spi;
+       atomic_t refcnt;
+#ifdef XFRM6_TUNNEL_SPI_MAGIC
+       u32 magic;
+#endif
+};
+
+#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
+# define XFRM6_TUNNEL_SPI_MAGIC 0xdeadbeef
+#endif
+
+static rwlock_t xfrm6_tunnel_spi_lock = RW_LOCK_UNLOCKED;
+
+static u32 xfrm6_tunnel_spi;
+
+#define XFRM6_TUNNEL_SPI_MIN   1
+#define XFRM6_TUNNEL_SPI_MAX   0xffffffff
+
+static kmem_cache_t *xfrm6_tunnel_spi_kmem;
+
+#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
+#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
+
+static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
+static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
+
+#ifdef XFRM6_TUNNEL_SPI_MAGIC
+static int x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi,
+                            const char *name)
+{
+       if (unlikely(x6spi->magic != XFRM6_TUNNEL_SPI_MAGIC)) {
+               X6TPRINTK3(KERN_DEBUG "%s(): x6spi object "
+                                     "at %p has corrupted magic %08x "
+                                     "(should be %08x)\n",
+                          name, x6spi, x6spi->magic, XFRM6_TUNNEL_SPI_MAGIC);
+               return -1;
+       }
+       return 0;
+}
+#else
+static int inline x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi,
+                                   const char *name)
+{
+       return 0;
+}
+#endif
+
+#define X6SPI_CHECK_MAGIC(x6spi) x6spi_check_magic((x6spi), __FUNCTION__)
+
+
+static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
+{
+       unsigned h;
+
+       X6TPRINTK3(KERN_DEBUG "%s(addr=%p)\n", __FUNCTION__, addr);
+
+       h = addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3];
+       h ^= h >> 16;
+       h ^= h >> 8;
+       h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1;
+
+       X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, h);
+
+       return h;
+}
+
+static unsigned inline xfrm6_tunnel_spi_hash_byspi(u32 spi)
+{
+       return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE;
+}
+
+
+static int xfrm6_tunnel_spi_init(void)
+{
+       int i;
+
+       X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+       xfrm6_tunnel_spi = 0;
+       xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
+                                                 sizeof(struct xfrm6_tunnel_spi),
+                                                 0, SLAB_HWCACHE_ALIGN,
+                                                 NULL, NULL);
+       if (!xfrm6_tunnel_spi_kmem) {
+               X6TPRINTK1(KERN_ERR
+                          "%s(): failed to allocate xfrm6_tunnel_spi_kmem\n",
+                          __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+               INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]);
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+               INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]);
+       return 0;
+}
+
+static void xfrm6_tunnel_spi_fini(void)
+{
+       int i;
+
+       X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) {
+               if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i]))
+                       goto err;
+       }
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) {
+               if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
+                       goto err;
+       }
+       kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
+       xfrm6_tunnel_spi_kmem = NULL;
+       return;
+err:
+       X6TPRINTK1(KERN_ERR "%s(): table is not empty\n", __FUNCTION__);
+       return;
+}
+
+static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+{
+       struct xfrm6_tunnel_spi *x6spi;
+       struct hlist_node *pos;
+
+       X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr);
+
+       hlist_for_each_entry(x6spi, pos,
+                            &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
+                            list_byaddr) {
+               if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
+                       X6SPI_CHECK_MAGIC(x6spi);
+                       X6TPRINTK3(KERN_DEBUG "%s() = %p(%u)\n", __FUNCTION__, x6spi, x6spi->spi);
+                       return x6spi;
+               }
+       }
+
+       X6TPRINTK3(KERN_DEBUG "%s() = NULL(0)\n", __FUNCTION__);
+       return NULL;
+}
+
+u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+{
+       struct xfrm6_tunnel_spi *x6spi;
+       u32 spi;
+
+       X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr);
+
+       read_lock_bh(&xfrm6_tunnel_spi_lock);
+       x6spi = __xfrm6_tunnel_spi_lookup(saddr);
+       spi = x6spi ? x6spi->spi : 0;
+       read_unlock_bh(&xfrm6_tunnel_spi_lock);
+       return spi;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
+
+static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+{
+       u32 spi;
+       struct xfrm6_tunnel_spi *x6spi;
+       struct hlist_node *pos;
+       unsigned index;
+
+       X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr);
+
+       if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN ||
+           xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX)
+               xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN;
+       else
+               xfrm6_tunnel_spi++;
+
+       for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
+               index = xfrm6_tunnel_spi_hash_byspi(spi);
+               hlist_for_each_entry(x6spi, pos, 
+                                    &xfrm6_tunnel_spi_byspi[index], 
+                                    list_byspi) {
+                       if (x6spi->spi == spi)
+                               goto try_next_1;
+               }
+               xfrm6_tunnel_spi = spi;
+               goto alloc_spi;
+try_next_1:;
+       }
+       for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) {
+               index = xfrm6_tunnel_spi_hash_byspi(spi);
+               hlist_for_each_entry(x6spi, pos, 
+                                    &xfrm6_tunnel_spi_byspi[index], 
+                                    list_byspi) {
+                       if (x6spi->spi == spi)
+                               goto try_next_2;
+               }
+               xfrm6_tunnel_spi = spi;
+               goto alloc_spi;
+try_next_2:;
+       }
+       spi = 0;
+       goto out;
+alloc_spi:
+       X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for "
+                             "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 
+                             __FUNCTION__, 
+                             NIP6(*(struct in6_addr *)saddr));
+       x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC);
+       if (!x6spi) {
+               X6TPRINTK1(KERN_ERR "%s(): kmem_cache_alloc() failed\n", 
+                          __FUNCTION__);
+               goto out;
+       }
+#ifdef XFRM6_TUNNEL_SPI_MAGIC
+       x6spi->magic = XFRM6_TUNNEL_SPI_MAGIC;
+#endif
+       memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr));
+       x6spi->spi = spi;
+       atomic_set(&x6spi->refcnt, 1);
+
+       hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
+
+       index = xfrm6_tunnel_spi_hash_byaddr(saddr);
+       hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
+       X6SPI_CHECK_MAGIC(x6spi);
+out:
+       X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi);
+       return spi;
+}
+
+u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+{
+       struct xfrm6_tunnel_spi *x6spi;
+       u32 spi;
+
+       X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr);
+
+       write_lock_bh(&xfrm6_tunnel_spi_lock);
+       x6spi = __xfrm6_tunnel_spi_lookup(saddr);
+       if (x6spi) {
+               atomic_inc(&x6spi->refcnt);
+               spi = x6spi->spi;
+       } else
+               spi = __xfrm6_tunnel_alloc_spi(saddr);
+       write_unlock_bh(&xfrm6_tunnel_spi_lock);
+
+       X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi);
+
+       return spi;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
+
+void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
+{
+       struct xfrm6_tunnel_spi *x6spi;
+       struct hlist_node *pos, *n;
+
+       X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr);
+
+       write_lock_bh(&xfrm6_tunnel_spi_lock);
+
+       hlist_for_each_entry_safe(x6spi, pos, n, 
+                                 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
+                                 list_byaddr)
+       {
+               if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
+                       X6TPRINTK3(KERN_DEBUG "%s(): x6spi object "
+                                             "for %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
+                                             "found at %p\n",
+                                  __FUNCTION__, 
+                                  NIP6(*(struct in6_addr *)saddr),
+                                  x6spi);
+                       X6SPI_CHECK_MAGIC(x6spi);
+                       if (atomic_dec_and_test(&x6spi->refcnt)) {
+                               hlist_del(&x6spi->list_byaddr);
+                               hlist_del(&x6spi->list_byspi);
+                               kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi);
+                               break;
+                       }
+               }
+       }
+       write_unlock_bh(&xfrm6_tunnel_spi_lock);
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
+
+static int xfrm6_tunnel_output(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct ipv6hdr *top_iph;
+
+       top_iph = (struct ipv6hdr *)skb->data;
+       top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
+       return 0;
+}
+
+static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 
+               return -EINVAL;
+
+       skb->mac.raw = skb->nh.raw;
+       skb->nh.raw = skb->data;
+       dst_release(skb->dst);
+       skb->dst = NULL;
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->pkt_type = PACKET_HOST;
+       netif_rx(skb);
+
+       return 0;
+}
+
+static struct xfrm6_tunnel *xfrm6_tunnel_handler;
+static DECLARE_MUTEX(xfrm6_tunnel_sem);
+
+int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
+{
+       int ret;
+
+       down(&xfrm6_tunnel_sem);
+       ret = 0;
+       if (xfrm6_tunnel_handler != NULL)
+               ret = -EINVAL;
+       if (!ret)
+               xfrm6_tunnel_handler = handler;
+       up(&xfrm6_tunnel_sem);
+
+       return ret;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_register);
+
+int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
+{
+       int ret;
+
+       down(&xfrm6_tunnel_sem);
+       ret = 0;
+       if (xfrm6_tunnel_handler != handler)
+               ret = -EINVAL;
+       if (!ret)
+               xfrm6_tunnel_handler = NULL;
+       up(&xfrm6_tunnel_sem);
+
+       synchronize_net();
+
+       return ret;
+}
+
+EXPORT_SYMBOL(xfrm6_tunnel_deregister);
+
+static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+       struct sk_buff *skb = *pskb;
+       struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
+       struct xfrm_state *x = NULL;
+       struct ipv6hdr *iph = skb->nh.ipv6h;
+       int err = 0;
+       u32 spi;
+
+       /* device-like_ip6ip6_handler() */
+       if (handler) {
+               err = handler->handler(pskb, nhoffp);
+               if (!err)
+                       goto out;
+       }
+
+       spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
+       x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, 
+                       spi,
+                       IPPROTO_IPV6, AF_INET6);
+
+       if (!x)
+               goto drop;
+
+       spin_lock(&x->lock);
+
+       if (unlikely(x->km.state != XFRM_STATE_VALID))
+               goto drop_unlock;
+
+       err = xfrm6_tunnel_input(x, NULL, skb);
+       if (err)
+               goto drop_unlock;
+
+       x->curlft.bytes += skb->len;
+       x->curlft.packets++; 
+       spin_unlock(&x->lock); 
+       xfrm_state_put(x); 
+
+out:
+       return 0;
+
+drop_unlock:
+       spin_unlock(&x->lock);
+       xfrm_state_put(x);
+drop:
+       kfree_skb(skb);
+       return -1;
+}
+
+static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                            int type, int code, int offset, __u32 info)
+{
+       struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
+
+       /* call here first for device-like ip6ip6 err handling */
+       if (handler) {
+               handler->err_handler(skb, opt, type, code, offset, info);
+               return;
+       }
+
+       /* xfrm6_tunnel native err handling */
+       switch (type) {
+       case ICMPV6_DEST_UNREACH: 
+               switch (code) {
+               case ICMPV6_NOROUTE: 
+               case ICMPV6_ADM_PROHIBITED:
+               case ICMPV6_NOT_NEIGHBOUR:
+               case ICMPV6_ADDR_UNREACH:
+               case ICMPV6_PORT_UNREACH:
+               default:
+                       X6TPRINTK3(KERN_DEBUG
+                                  "xfrm6_tunnel: Destination Unreach.\n");
+                       break;
+               }
+               break;
+       case ICMPV6_PKT_TOOBIG:
+                       X6TPRINTK3(KERN_DEBUG 
+                                  "xfrm6_tunnel: Packet Too Big.\n");
+               break;
+       case ICMPV6_TIME_EXCEED:
+               switch (code) {
+               case ICMPV6_EXC_HOPLIMIT:
+                       X6TPRINTK3(KERN_DEBUG
+                                  "xfrm6_tunnel: Too small Hoplimit.\n");
+                       break;
+               case ICMPV6_EXC_FRAGTIME:
+               default: 
+                       break;
+               }
+               break;
+       case ICMPV6_PARAMPROB:
+               switch (code) {
+               case ICMPV6_HDR_FIELD: break;
+               case ICMPV6_UNK_NEXTHDR: break;
+               case ICMPV6_UNK_OPTION: break;
+               }
+               break;
+       default:
+               break;
+       }
+       return;
+}
+
+static int xfrm6_tunnel_init_state(struct xfrm_state *x, void *args)
+{
+       if (!x->props.mode)
+               return -EINVAL;
+
+       x->props.header_len = sizeof(struct ipv6hdr);
+
+       return 0;
+}
+
+static void xfrm6_tunnel_destroy(struct xfrm_state *x)
+{
+       xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
+}
+
+static struct xfrm_type xfrm6_tunnel_type = {
+       .description    = "IP6IP6",
+       .owner          = THIS_MODULE,
+       .proto          = IPPROTO_IPV6,
+       .init_state     = xfrm6_tunnel_init_state,
+       .destructor     = xfrm6_tunnel_destroy,
+       .input          = xfrm6_tunnel_input,
+       .output         = xfrm6_tunnel_output,
+};
+
+static struct inet6_protocol xfrm6_tunnel_protocol = {
+       .handler        = xfrm6_tunnel_rcv,
+       .err_handler    = xfrm6_tunnel_err, 
+       .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+};
+
+void __init xfrm6_tunnel_init(void)
+{
+       X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+       if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) {
+               X6TPRINTK1(KERN_ERR
+                          "xfrm6_tunnel init: can't add xfrm type\n");
+               return;
+       }
+       if (inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) {
+               X6TPRINTK1(KERN_ERR
+                          "xfrm6_tunnel init(): can't add protocol\n");
+               xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+               return;
+       }
+       if (xfrm6_tunnel_spi_init() < 0) {
+               X6TPRINTK1(KERN_ERR
+                          "xfrm6_tunnel init: failed to initialize spi\n");
+               inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6);
+               xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+               return;
+       }
+}
+
+void __exit xfrm6_tunnel_fini(void)
+{
+       X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+       xfrm6_tunnel_spi_fini();
+       if (inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0)
+               X6TPRINTK1(KERN_ERR 
+                          "xfrm6_tunnel close: can't remove protocol\n");
+       if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0)
+               X6TPRINTK1(KERN_ERR
+                          "xfrm6_tunnel close: can't remove xfrm type\n");
+}
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
new file mode 100644 (file)
index 0000000..4d91d69
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * net/sched/sch_netem.c       Network emulator
+ *
+ *             This program is free software; 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.
+ *
+ * Authors:    Stephen Hemminger <shemminger@osdl.org>
+ *             Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+
+#include <net/pkt_sched.h>
+
+/*     Network emulator
+ *
+ *     This scheduler can alters spacing and order
+ *     Similar to NISTnet and BSD Dummynet.
+ */
+
+struct netem_sched_data {
+       struct Qdisc    *qdisc;
+       struct sk_buff_head delayed;
+       struct timer_list timer;
+
+       u32 latency;
+       u32 loss;
+       u32 limit;
+       u32 counter;
+       u32 gap;
+       u32 jitter;
+};
+
+/* Time stamp put into socket buffer control block */
+struct netem_skb_cb {
+       psched_time_t   time_to_send;
+};
+
+/* This is the distribution table for the normal distribution produced
+ * with NISTnet tools.
+ * The entries represent a scaled inverse of the cumulative distribution
+ * function.
+ */
+#define TABLESIZE      2048
+#define TABLEFACTOR    8192
+
+static const short disttable[TABLESIZE] = {
+       -31473,         -26739,         -25226,         -24269,
+       -23560,         -22993,         -22518,         -22109,
+       -21749,         -21426,         -21133,         -20865,
+       -20618,         -20389,         -20174,         -19972,
+       -19782,         -19601,         -19430,         -19267,
+       -19112,         -18962,         -18819,         -18681,
+       -18549,         -18421,         -18298,         -18178,
+       -18062,         -17950,         -17841,         -17735,
+       -17632,         -17532,         -17434,         -17339,
+       -17245,         -17155,         -17066,         -16979,
+       -16894,         -16811,         -16729,         -16649,
+       -16571,         -16494,         -16419,         -16345,
+       -16272,         -16201,         -16130,         -16061,
+       -15993,         -15926,         -15861,         -15796,
+       -15732,         -15669,         -15607,         -15546,
+       -15486,         -15426,         -15368,         -15310,
+       -15253,         -15196,         -15140,         -15086,
+       -15031,         -14977,         -14925,         -14872,
+       -14821,         -14769,         -14719,         -14669,
+       -14619,         -14570,         -14522,         -14473,
+       -14426,         -14379,         -14332,         -14286,
+       -14241,         -14196,         -14150,         -14106,
+       -14062,         -14019,         -13976,         -13933,
+       -13890,         -13848,         -13807,         -13765,
+       -13724,         -13684,         -13643,         -13604,
+       -13564,         -13525,         -13486,         -13447,
+       -13408,         -13370,         -13332,         -13295,
+       -13258,         -13221,         -13184,         -13147,
+       -13111,         -13075,         -13040,         -13004,
+       -12969,         -12934,         -12899,         -12865,
+       -12830,         -12796,         -12762,         -12729,
+       -12695,         -12662,         -12629,         -12596,
+       -12564,         -12531,         -12499,         -12467,
+       -12435,         -12404,         -12372,         -12341,
+       -12310,         -12279,         -12248,         -12218,
+       -12187,         -12157,         -12127,         -12097,
+       -12067,         -12038,         -12008,         -11979,
+       -11950,         -11921,         -11892,         -11863,
+       -11835,         -11806,         -11778,         -11750,
+       -11722,         -11694,         -11666,         -11639,
+       -11611,         -11584,         -11557,         -11530,
+       -11503,         -11476,         -11450,         -11423,
+       -11396,         -11370,         -11344,         -11318,
+       -11292,         -11266,         -11240,         -11214,
+       -11189,         -11164,         -11138,         -11113,
+       -11088,         -11063,         -11038,         -11013,
+       -10988,         -10964,         -10939,         -10915,
+       -10891,         -10866,         -10843,         -10818,
+       -10794,         -10770,         -10747,         -10723,
+       -10700,         -10676,         -10652,         -10630,
+       -10606,         -10583,         -10560,         -10537,
+       -10514,         -10491,         -10469,         -10446,
+       -10424,         -10401,         -10378,         -10356,
+       -10334,         -10312,         -10290,         -10267,
+       -10246,         -10224,         -10202,         -10180,
+       -10158,         -10137,         -10115,         -10094,
+       -10072,         -10051,         -10030,         -10009,
+       -9988,          -9967,          -9945,          -9925,
+       -9904,          -9883,          -9862,          -9842,
+       -9821,          -9800,          -9780,          -9760,
+       -9739,          -9719,          -9699,          -9678,
+       -9658,          -9638,          -9618,          -9599,
+       -9578,          -9559,          -9539,          -9519,
+       -9499,          -9480,          -9461,          -9441,
+       -9422,          -9402,          -9383,          -9363,
+       -9344,          -9325,          -9306,          -9287,
+       -9268,          -9249,          -9230,          -9211,
+       -9192,          -9173,          -9155,          -9136,
+       -9117,          -9098,          -9080,          -9062,
+       -9043,          -9025,          -9006,          -8988,
+       -8970,          -8951,          -8933,          -8915,
+       -8897,          -8879,          -8861,          -8843,
+       -8825,          -8807,          -8789,          -8772,
+       -8754,          -8736,          -8718,          -8701,
+       -8683,          -8665,          -8648,          -8630,
+       -8613,          -8595,          -8578,          -8561,
+       -8543,          -8526,          -8509,          -8492,
+       -8475,          -8458,          -8441,          -8423,
+       -8407,          -8390,          -8373,          -8356,
+       -8339,          -8322,          -8305,          -8289,
+       -8272,          -8255,          -8239,          -8222,
+       -8206,          -8189,          -8172,          -8156,
+       -8140,          -8123,          -8107,          -8090,
+       -8074,          -8058,          -8042,          -8025,
+       -8009,          -7993,          -7977,          -7961,
+       -7945,          -7929,          -7913,          -7897,
+       -7881,          -7865,          -7849,          -7833,
+       -7817,          -7802,          -7786,          -7770,
+       -7754,          -7739,          -7723,          -7707,
+       -7692,          -7676,          -7661,          -7645,
+       -7630,          -7614,          -7599,          -7583,
+       -7568,          -7553,          -7537,          -7522,
+       -7507,          -7492,          -7476,          -7461,
+       -7446,          -7431,          -7416,          -7401,
+       -7385,          -7370,          -7356,          -7340,
+       -7325,          -7311,          -7296,          -7281,
+       -7266,          -7251,          -7236,          -7221,
+       -7207,          -7192,          -7177,          -7162,
+       -7148,          -7133,          -7118,          -7104,
+       -7089,          -7075,          -7060,          -7046,
+       -7031,          -7016,          -7002,          -6988,
+       -6973,          -6959,          -6944,          -6930,
+       -6916,          -6901,          -6887,          -6873,
+       -6859,          -6844,          -6830,          -6816,
+       -6802,          -6788,          -6774,          -6760,
+       -6746,          -6731,          -6717,          -6704,
+       -6690,          -6675,          -6661,          -6647,
+       -6633,          -6620,          -6606,          -6592,
+       -6578,          -6564,          -6550,          -6537,
+       -6523,          -6509,          -6495,          -6482,
+       -6468,          -6454,          -6441,          -6427,
+       -6413,          -6400,          -6386,          -6373,
+       -6359,          -6346,          -6332,          -6318,
+       -6305,          -6291,          -6278,          -6264,
+       -6251,          -6238,          -6224,          -6211,
+       -6198,          -6184,          -6171,          -6158,
+       -6144,          -6131,          -6118,          -6105,
+       -6091,          -6078,          -6065,          -6052,
+       -6039,          -6025,          -6012,          -5999,
+       -5986,          -5973,          -5960,          -5947,
+       -5934,          -5921,          -5908,          -5895,
+       -5882,          -5869,          -5856,          -5843,
+       -5830,          -5817,          -5804,          -5791,
+       -5779,          -5766,          -5753,          -5740,
+       -5727,          -5714,          -5702,          -5689,
+       -5676,          -5663,          -5650,          -5638,
+       -5625,          -5612,          -5600,          -5587,
+       -5575,          -5562,          -5549,          -5537,
+       -5524,          -5512,          -5499,          -5486,
+       -5474,          -5461,          -5449,          -5436,
+       -5424,          -5411,          -5399,          -5386,
+       -5374,          -5362,          -5349,          -5337,
+       -5324,          -5312,          -5299,          -5287,
+       -5275,          -5263,          -5250,          -5238,
+       -5226,          -5213,          -5201,          -5189,
+       -5177,          -5164,          -5152,          -5140,
+       -5128,          -5115,          -5103,          -5091,
+       -5079,          -5067,          -5055,          -5043,
+       -5030,          -5018,          -5006,          -4994,
+       -4982,          -4970,          -4958,          -4946,
+       -4934,          -4922,          -4910,          -4898,
+       -4886,          -4874,          -4862,          -4850,
+       -4838,          -4826,          -4814,          -4803,
+       -4791,          -4778,          -4767,          -4755,
+       -4743,          -4731,          -4719,          -4708,
+       -4696,          -4684,          -4672,          -4660,
+       -4649,          -4637,          -4625,          -4613,
+       -4601,          -4590,          -4578,          -4566,
+       -4554,          -4543,          -4531,          -4520,
+       -4508,          -4496,          -4484,          -4473,
+       -4461,          -4449,          -4438,          -4427,
+       -4415,          -4403,          -4392,          -4380,
+       -4368,          -4357,          -4345,          -4334,
+       -4322,          -4311,          -4299,          -4288,
+       -4276,          -4265,          -4253,          -4242,
+       -4230,          -4219,          -4207,          -4196,
+       -4184,          -4173,          -4162,          -4150,
+       -4139,          -4128,          -4116,          -4105,
+       -4094,          -4082,          -4071,          -4060,
+       -4048,          -4037,          -4026,          -4014,
+       -4003,          -3992,          -3980,          -3969,
+       -3958,          -3946,          -3935,          -3924,
+       -3913,          -3901,          -3890,          -3879,
+       -3868,          -3857,          -3845,          -3834,
+       -3823,          -3812,          -3801,          -3790,
+       -3779,          -3767,          -3756,          -3745,
+       -3734,          -3723,          -3712,          -3700,
+       -3689,          -3678,          -3667,          -3656,
+       -3645,          -3634,          -3623,          -3612,
+       -3601,          -3590,          -3579,          -3568,
+       -3557,          -3545,          -3535,          -3524,
+       -3513,          -3502,          -3491,          -3480,
+       -3469,          -3458,          -3447,          -3436,
+       -3425,          -3414,          -3403,          -3392,
+       -3381,          -3370,          -3360,          -3348,
+       -3337,          -3327,          -3316,          -3305,
+       -3294,          -3283,          -3272,          -3262,
+       -3251,          -3240,          -3229,          -3218,
+       -3207,          -3197,          -3185,          -3175,
+       -3164,          -3153,          -3142,          -3132,
+       -3121,          -3110,          -3099,          -3088,
+       -3078,          -3067,          -3056,          -3045,
+       -3035,          -3024,          -3013,          -3003,
+       -2992,          -2981,          -2970,          -2960,
+       -2949,          -2938,          -2928,          -2917,
+       -2906,          -2895,          -2885,          -2874,
+       -2864,          -2853,          -2842,          -2832,
+       -2821,          -2810,          -2800,          -2789,
+       -2778,          -2768,          -2757,          -2747,
+       -2736,          -2725,          -2715,          -2704,
+       -2694,          -2683,          -2673,          -2662,
+       -2651,          -2641,          -2630,          -2620,
+       -2609,          -2599,          -2588,          -2578,
+       -2567,          -2556,          -2546,          -2535,
+       -2525,          -2515,          -2504,          -2493,
+       -2483,          -2472,          -2462,          -2451,
+       -2441,          -2431,          -2420,          -2410,
+       -2399,          -2389,          -2378,          -2367,
+       -2357,          -2347,          -2336,          -2326,
+       -2315,          -2305,          -2295,          -2284,
+       -2274,          -2263,          -2253,          -2243,
+       -2232,          -2222,          -2211,          -2201,
+       -2191,          -2180,          -2170,          -2159,
+       -2149,          -2139,          -2128,          -2118,
+       -2107,          -2097,          -2087,          -2076,
+       -2066,          -2056,          -2046,          -2035,
+       -2025,          -2014,          -2004,          -1994,
+       -1983,          -1973,          -1963,          -1953,
+       -1942,          -1932,          -1921,          -1911,
+       -1901,          -1891,          -1880,          -1870,
+       -1860,          -1849,          -1839,          -1829,
+       -1819,          -1808,          -1798,          -1788,
+       -1778,          -1767,          -1757,          -1747,
+       -1736,          -1726,          -1716,          -1706,
+       -1695,          -1685,          -1675,          -1665,
+       -1654,          -1644,          -1634,          -1624,
+       -1613,          -1603,          -1593,          -1583,
+       -1573,          -1563,          -1552,          -1542,
+       -1532,          -1522,          -1511,          -1501,
+       -1491,          -1481,          -1471,          -1461,
+       -1450,          -1440,          -1430,          -1420,
+       -1409,          -1400,          -1389,          -1379,
+       -1369,          -1359,          -1348,          -1339,
+       -1328,          -1318,          -1308,          -1298,
+       -1288,          -1278,          -1267,          -1257,
+       -1247,          -1237,          -1227,          -1217,
+       -1207,          -1196,          -1186,          -1176,
+       -1166,          -1156,          -1146,          -1135,
+       -1126,          -1115,          -1105,          -1095,
+       -1085,          -1075,          -1065,          -1055,
+       -1044,          -1034,          -1024,          -1014,
+       -1004,          -994,           -984,           -974,
+       -964,           -954,           -944,           -933,
+       -923,           -913,           -903,           -893,
+       -883,           -873,           -863,           -853,
+       -843,           -833,           -822,           -812,
+       -802,           -792,           -782,           -772,
+       -762,           -752,           -742,           -732,
+       -722,           -712,           -702,           -691,
+       -682,           -671,           -662,           -651,
+       -641,           -631,           -621,           -611,
+       -601,           -591,           -581,           -571,
+       -561,           -551,           -541,           -531,
+       -521,           -511,           -501,           -491,
+       -480,           -471,           -460,           -451,
+       -440,           -430,           -420,           -410,
+       -400,           -390,           -380,           -370,
+       -360,           -350,           -340,           -330,
+       -320,           -310,           -300,           -290,
+       -280,           -270,           -260,           -250,
+       -240,           -230,           -220,           -210,
+       -199,           -190,           -179,           -170,
+       -159,           -150,           -139,           -129,
+       -119,           -109,           -99,            -89,
+       -79,            -69,            -59,            -49,
+       -39,            -29,            -19,            -9,
+       1,              11,             21,             31,
+       41,             51,             61,             71,
+       81,             91,             101,            111,
+       121,            131,            141,            152,
+       161,            172,            181,            192,
+       202,            212,            222,            232,
+       242,            252,            262,            272,
+       282,            292,            302,            312,
+       322,            332,            342,            352,
+       362,            372,            382,            392,
+       402,            412,            422,            433,
+       442,            453,            462,            473,
+       483,            493,            503,            513,
+       523,            533,            543,            553,
+       563,            573,            583,            593,
+       603,            613,            623,            633,
+       643,            653,            664,            673,
+       684,            694,            704,            714,
+       724,            734,            744,            754,
+       764,            774,            784,            794,
+       804,            815,            825,            835,
+       845,            855,            865,            875,
+       885,            895,            905,            915,
+       925,            936,            946,            956,
+       966,            976,            986,            996,
+       1006,           1016,           1026,           1037,
+       1047,           1057,           1067,           1077,
+       1087,           1097,           1107,           1117,
+       1128,           1138,           1148,           1158,
+       1168,           1178,           1188,           1198,
+       1209,           1219,           1229,           1239,
+       1249,           1259,           1269,           1280,
+       1290,           1300,           1310,           1320,
+       1330,           1341,           1351,           1361,
+       1371,           1381,           1391,           1402,
+       1412,           1422,           1432,           1442,
+       1452,           1463,           1473,           1483,
+       1493,           1503,           1513,           1524,
+       1534,           1544,           1554,           1565,
+       1575,           1585,           1595,           1606,
+       1616,           1626,           1636,           1647,
+       1656,           1667,           1677,           1687,
+       1697,           1708,           1718,           1729,
+       1739,           1749,           1759,           1769,
+       1780,           1790,           1800,           1810,
+       1821,           1831,           1841,           1851,
+       1862,           1872,           1883,           1893,
+       1903,           1913,           1923,           1934,
+       1944,           1955,           1965,           1975,
+       1985,           1996,           2006,           2016,
+       2027,           2037,           2048,           2058,
+       2068,           2079,           2089,           2099,
+       2110,           2120,           2130,           2141,
+       2151,           2161,           2172,           2182,
+       2193,           2203,           2213,           2224,
+       2234,           2245,           2255,           2265,
+       2276,           2286,           2297,           2307,
+       2318,           2328,           2338,           2349,
+       2359,           2370,           2380,           2391,
+       2401,           2412,           2422,           2433,
+       2443,           2454,           2464,           2475,
+       2485,           2496,           2506,           2517,
+       2527,           2537,           2548,           2559,
+       2569,           2580,           2590,           2601,
+       2612,           2622,           2632,           2643,
+       2654,           2664,           2675,           2685,
+       2696,           2707,           2717,           2728,
+       2738,           2749,           2759,           2770,
+       2781,           2791,           2802,           2813,
+       2823,           2834,           2845,           2855,
+       2866,           2877,           2887,           2898,
+       2909,           2919,           2930,           2941,
+       2951,           2962,           2973,           2984,
+       2994,           3005,           3015,           3027,
+       3037,           3048,           3058,           3069,
+       3080,           3091,           3101,           3113,
+       3123,           3134,           3145,           3156,
+       3166,           3177,           3188,           3199,
+       3210,           3220,           3231,           3242,
+       3253,           3264,           3275,           3285,
+       3296,           3307,           3318,           3329,
+       3340,           3351,           3362,           3373,
+       3384,           3394,           3405,           3416,
+       3427,           3438,           3449,           3460,
+       3471,           3482,           3493,           3504,
+       3515,           3526,           3537,           3548,
+       3559,           3570,           3581,           3592,
+       3603,           3614,           3625,           3636,
+       3647,           3659,           3670,           3681,
+       3692,           3703,           3714,           3725,
+       3736,           3747,           3758,           3770,
+       3781,           3792,           3803,           3814,
+       3825,           3837,           3848,           3859,
+       3870,           3881,           3893,           3904,
+       3915,           3926,           3937,           3949,
+       3960,           3971,           3983,           3994,
+       4005,           4017,           4028,           4039,
+       4051,           4062,           4073,           4085,
+       4096,           4107,           4119,           4130,
+       4141,           4153,           4164,           4175,
+       4187,           4198,           4210,           4221,
+       4233,           4244,           4256,           4267,
+       4279,           4290,           4302,           4313,
+       4325,           4336,           4348,           4359,
+       4371,           4382,           4394,           4406,
+       4417,           4429,           4440,           4452,
+       4464,           4475,           4487,           4499,
+       4510,           4522,           4533,           4545,
+       4557,           4569,           4581,           4592,
+       4604,           4616,           4627,           4639,
+       4651,           4663,           4674,           4686,
+       4698,           4710,           4722,           4734,
+       4746,           4758,           4769,           4781,
+       4793,           4805,           4817,           4829,
+       4841,           4853,           4865,           4877,
+       4889,           4900,           4913,           4925,
+       4936,           4949,           4961,           4973,
+       4985,           4997,           5009,           5021,
+       5033,           5045,           5057,           5070,
+       5081,           5094,           5106,           5118,
+       5130,           5143,           5155,           5167,
+       5179,           5191,           5204,           5216,
+       5228,           5240,           5253,           5265,
+       5278,           5290,           5302,           5315,
+       5327,           5340,           5352,           5364,
+       5377,           5389,           5401,           5414,
+       5426,           5439,           5451,           5464,
+       5476,           5489,           5502,           5514,
+       5527,           5539,           5552,           5564,
+       5577,           5590,           5603,           5615,
+       5628,           5641,           5653,           5666,
+       5679,           5691,           5704,           5717,
+       5730,           5743,           5756,           5768,
+       5781,           5794,           5807,           5820,
+       5833,           5846,           5859,           5872,
+       5885,           5897,           5911,           5924,
+       5937,           5950,           5963,           5976,
+       5989,           6002,           6015,           6028,
+       6042,           6055,           6068,           6081,
+       6094,           6108,           6121,           6134,
+       6147,           6160,           6174,           6187,
+       6201,           6214,           6227,           6241,
+       6254,           6267,           6281,           6294,
+       6308,           6321,           6335,           6348,
+       6362,           6375,           6389,           6403,
+       6416,           6430,           6443,           6457,
+       6471,           6485,           6498,           6512,
+       6526,           6540,           6554,           6567,
+       6581,           6595,           6609,           6623,
+       6637,           6651,           6665,           6679,
+       6692,           6706,           6721,           6735,
+       6749,           6763,           6777,           6791,
+       6805,           6819,           6833,           6848,
+       6862,           6876,           6890,           6905,
+       6919,           6933,           6948,           6962,
+       6976,           6991,           7005,           7020,
+       7034,           7049,           7064,           7078,
+       7093,           7107,           7122,           7136,
+       7151,           7166,           7180,           7195,
+       7210,           7225,           7240,           7254,
+       7269,           7284,           7299,           7314,
+       7329,           7344,           7359,           7374,
+       7389,           7404,           7419,           7434,
+       7449,           7465,           7480,           7495,
+       7510,           7526,           7541,           7556,
+       7571,           7587,           7602,           7618,
+       7633,           7648,           7664,           7680,
+       7695,           7711,           7726,           7742,
+       7758,           7773,           7789,           7805,
+       7821,           7836,           7852,           7868,
+       7884,           7900,           7916,           7932,
+       7948,           7964,           7981,           7997,
+       8013,           8029,           8045,           8061,
+       8078,           8094,           8110,           8127,
+       8143,           8160,           8176,           8193,
+       8209,           8226,           8242,           8259,
+       8276,           8292,           8309,           8326,
+       8343,           8360,           8377,           8394,
+       8410,           8428,           8444,           8462,
+       8479,           8496,           8513,           8530,
+       8548,           8565,           8582,           8600,
+       8617,           8634,           8652,           8670,
+       8687,           8704,           8722,           8740,
+       8758,           8775,           8793,           8811,
+       8829,           8847,           8865,           8883,
+       8901,           8919,           8937,           8955,
+       8974,           8992,           9010,           9029,
+       9047,           9066,           9084,           9103,
+       9121,           9140,           9159,           9177,
+       9196,           9215,           9234,           9253,
+       9272,           9291,           9310,           9329,
+       9349,           9368,           9387,           9406,
+       9426,           9445,           9465,           9484,
+       9504,           9524,           9544,           9563,
+       9583,           9603,           9623,           9643,
+       9663,           9683,           9703,           9723,
+       9744,           9764,           9785,           9805,
+       9826,           9846,           9867,           9888,
+       9909,           9930,           9950,           9971,
+       9993,           10013,          10035,          10056,
+       10077,          10099,          10120,          10142,
+       10163,          10185,          10207,          10229,
+       10251,          10273,          10294,          10317,
+       10339,          10361,          10384,          10406,
+       10428,          10451,          10474,          10496,
+       10519,          10542,          10565,          10588,
+       10612,          10635,          10658,          10682,
+       10705,          10729,          10752,          10776,
+       10800,          10824,          10848,          10872,
+       10896,          10921,          10945,          10969,
+       10994,          11019,          11044,          11069,
+       11094,          11119,          11144,          11169,
+       11195,          11221,          11246,          11272,
+       11298,          11324,          11350,          11376,
+       11402,          11429,          11456,          11482,
+       11509,          11536,          11563,          11590,
+       11618,          11645,          11673,          11701,
+       11728,          11756,          11785,          11813,
+       11842,          11870,          11899,          11928,
+       11957,          11986,          12015,          12045,
+       12074,          12104,          12134,          12164,
+       12194,          12225,          12255,          12286,
+       12317,          12348,          12380,          12411,
+       12443,          12475,          12507,          12539,
+       12571,          12604,          12637,          12670,
+       12703,          12737,          12771,          12804,
+       12839,          12873,          12907,          12942,
+       12977,          13013,          13048,          13084,
+       13120,          13156,          13192,          13229,
+       13267,          13304,          13341,          13379,
+       13418,          13456,          13495,          13534,
+       13573,          13613,          13653,          13693,
+       13734,          13775,          13817,          13858,
+       13901,          13943,          13986,          14029,
+       14073,          14117,          14162,          14206,
+       14252,          14297,          14343,          14390,
+       14437,          14485,          14533,          14582,
+       14631,          14680,          14731,          14782,
+       14833,          14885,          14937,          14991,
+       15044,          15099,          15154,          15210,
+       15266,          15324,          15382,          15441,
+       15500,          15561,          15622,          15684,
+       15747,          15811,          15877,          15943,
+       16010,          16078,          16148,          16218,
+       16290,          16363,          16437,          16513,
+       16590,          16669,          16749,          16831,
+       16915,          17000,          17088,          17177,
+       17268,          17362,          17458,          17556,
+       17657,          17761,          17868,          17977,
+       18090,          18207,          18328,          18452,
+       18581,          18715,          18854,          18998,
+       19149,          19307,          19472,          19645,
+       19828,          20021,          20226,          20444,
+       20678,          20930,          21204,          21503,
+       21835,          22206,          22630,          23124,
+       23721,          24478,          25529,          27316,
+};
+
+/* tabledist - return a pseudo-randomly distributed value with mean mu and
+ * std deviation sigma.  Uses table lookup to approximate the desired
+ * distribution, and a uniformly-distributed pseudo-random source.
+ */
+static inline int tabledist(int mu, int sigma)
+{
+       int x;
+       int index;
+       int sigmamod, sigmadiv;
+
+       if (sigma == 0)
+               return mu;
+
+       index = (net_random() & (TABLESIZE-1));
+       sigmamod = sigma%TABLEFACTOR;
+       sigmadiv = sigma/TABLEFACTOR;
+       x = sigmamod*disttable[index];
+
+       if (x >= 0)
+               x += TABLEFACTOR/2;
+       else
+               x -= TABLEFACTOR/2;
+
+       x /= TABLEFACTOR;
+       x += sigmadiv*disttable[index];
+       x += mu;
+       return x;
+}
+
+/* Enqueue packets with underlying discipline (fifo)
+ * but mark them with current time first.
+ */
+static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
+       psched_time_t now;
+       long delay;
+
+       pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies);
+
+       /* Random packet drop 0 => none, ~0 => all */
+       if (q->loss && q->loss >= net_random()) {
+               sch->stats.drops++;
+               return 0;       /* lie about loss so TCP doesn't know */
+       }
+
+
+       /* If doing simple delay then gap == 0 so all packets
+        * go into the delayed holding queue
+        * otherwise if doing out of order only "1 out of gap"
+        * packets will be delayed.
+        */
+       if (q->counter < q->gap) {
+               int ret;
+
+               ++q->counter;
+               ret = q->qdisc->enqueue(skb, q->qdisc);
+               if (ret)
+                       sch->stats.drops++;
+               return ret;
+       }
+       
+       q->counter = 0;
+       
+       PSCHED_GET_TIME(now);
+       if (q->jitter) 
+               delay = tabledist(q->latency, q->jitter);
+       else
+               delay = q->latency;
+
+       PSCHED_TADD2(now, delay, cb->time_to_send);
+       
+       /* Always queue at tail to keep packets in order */
+       if (likely(q->delayed.qlen < q->limit)) {
+               __skb_queue_tail(&q->delayed, skb);
+               sch->q.qlen++;
+               sch->stats.bytes += skb->len;
+               sch->stats.packets++;
+               return 0;
+       }
+
+       sch->stats.drops++;
+       kfree_skb(skb);
+       return NET_XMIT_DROP;
+}
+
+/* Requeue packets but don't change time stamp */
+static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       int ret;
+
+       if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0)
+               sch->q.qlen++;
+
+       return ret;
+}
+
+static unsigned int netem_drop(struct Qdisc* sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       unsigned int len;
+
+       if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+               sch->q.qlen--;
+               sch->stats.drops++;
+       }
+       return len;
+}
+
+/* Dequeue packet.
+ *  Move all packets that are ready to send from the delay holding
+ *  list to the underlying qdisc, then just call dequeue
+ */
+static struct sk_buff *netem_dequeue(struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       struct sk_buff *skb;
+       psched_time_t now;
+
+       PSCHED_GET_TIME(now);
+       while ((skb = skb_peek(&q->delayed)) != NULL) {
+               const struct netem_skb_cb *cb
+                       = (const struct netem_skb_cb *)skb->cb;
+               long delay 
+                       = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
+               pr_debug("netem_dequeue: delay queue %p@%lu %ld\n",
+                        skb, jiffies, delay);
+
+               /* if more time remaining? */
+               if (delay > 0) {
+                       mod_timer(&q->timer, jiffies + delay);
+                       break;
+               }
+               __skb_unlink(skb, &q->delayed);
+
+               if (q->qdisc->enqueue(skb, q->qdisc))
+                       sch->stats.drops++;
+       }
+
+       skb = q->qdisc->dequeue(q->qdisc);
+       if (skb) 
+               sch->q.qlen--;
+       return skb;
+}
+
+static void netem_watchdog(unsigned long arg)
+{
+       struct Qdisc *sch = (struct Qdisc *)arg;
+
+       pr_debug("netem_watchdog: fired @%lu\n", jiffies);
+       netif_schedule(sch->dev);
+}
+
+static void netem_reset(struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+
+       qdisc_reset(q->qdisc);
+       skb_queue_purge(&q->delayed);
+
+       sch->q.qlen = 0;
+       del_timer_sync(&q->timer);
+}
+
+static int set_fifo_limit(struct Qdisc *q, int limit)
+{
+        struct rtattr *rta;
+       int ret = -ENOMEM;
+
+       rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
+       if (rta) {
+               rta->rta_type = RTM_NEWQDISC;
+               rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); 
+               ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
+               
+               ret = q->ops->change(q, rta);
+               kfree(rta);
+       }
+       return ret;
+}
+
+static int netem_change(struct Qdisc *sch, struct rtattr *opt)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       struct tc_netem_qopt *qopt = RTA_DATA(opt);
+       struct Qdisc *child;
+       int ret;
+
+       if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
+               return -EINVAL;
+
+       child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+       if (!child)
+               return -EINVAL;
+
+       ret = set_fifo_limit(child, qopt->limit);
+       if (ret) {
+               qdisc_destroy(child);
+               return ret;
+       }
+
+       sch_tree_lock(sch);
+       if (child) {
+               child = xchg(&q->qdisc, child);
+               if (child != &noop_qdisc)
+                       qdisc_destroy(child);
+       
+               q->latency = qopt->latency;
+               q->jitter = qopt->jitter;
+               q->limit = qopt->limit;
+               q->gap = qopt->gap;
+               q->loss = qopt->loss;
+       }
+       sch_tree_unlock(sch);
+
+       return 0;
+}
+
+static int netem_init(struct Qdisc *sch, struct rtattr *opt)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+
+       if (!opt)
+               return -EINVAL;
+
+       skb_queue_head_init(&q->delayed);
+       q->qdisc = &noop_qdisc;
+
+       init_timer(&q->timer);
+       q->timer.function = netem_watchdog;
+       q->timer.data = (unsigned long) sch;
+       q->counter = 0;
+
+       return netem_change(sch, opt);
+}
+
+static void netem_destroy(struct Qdisc *sch)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+
+       del_timer_sync(&q->timer);
+       qdisc_destroy(q->qdisc);
+}
+
+static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       unsigned char    *b = skb->tail;
+       struct tc_netem_qopt qopt;
+
+       qopt.latency = q->latency;
+       qopt.jitter = q->jitter;
+       qopt.limit = q->limit;
+       qopt.loss = q->loss;
+       qopt.gap = q->gap;
+
+       RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
+
+       return skb->len;
+
+rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
+                         struct sk_buff *skb, struct tcmsg *tcm)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+
+       if (cl != 1)    /* only one class */
+               return -ENOENT;
+
+       tcm->tcm_handle |= TC_H_MIN(1);
+       tcm->tcm_info = q->qdisc->handle;
+
+       return 0;
+}
+
+static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+                    struct Qdisc **old)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+
+       if (new == NULL)
+               new = &noop_qdisc;
+
+       sch_tree_lock(sch);
+       *old = xchg(&q->qdisc, new);
+       qdisc_reset(*old);
+       sch->q.qlen = 0;
+       sch_tree_unlock(sch);
+
+       return 0;
+}
+
+static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
+{
+       struct netem_sched_data *q = qdisc_priv(sch);
+       return q->qdisc;
+}
+
+static unsigned long netem_get(struct Qdisc *sch, u32 classid)
+{
+       return 1;
+}
+
+static void netem_put(struct Qdisc *sch, unsigned long arg)
+{
+}
+
+static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, 
+                           struct rtattr **tca, unsigned long *arg)
+{
+       return -ENOSYS;
+}
+
+static int netem_delete(struct Qdisc *sch, unsigned long arg)
+{
+       return -ENOSYS;
+}
+
+static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
+{
+       if (!walker->stop) {
+               if (walker->count >= walker->skip)
+                       if (walker->fn(sch, 1, walker) < 0) {
+                               walker->stop = 1;
+                               return;
+                       }
+               walker->count++;
+       }
+}
+
+static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+       return NULL;
+}
+
+static struct Qdisc_class_ops netem_class_ops = {
+       .graft          =       netem_graft,
+       .leaf           =       netem_leaf,
+       .get            =       netem_get,
+       .put            =       netem_put,
+       .change         =       netem_change_class,
+       .delete         =       netem_delete,
+       .walk           =       netem_walk,
+       .tcf_chain      =       netem_find_tcf,
+       .dump           =       netem_dump_class,
+};
+
+static struct Qdisc_ops netem_qdisc_ops = {
+       .id             =       "netem",
+       .cl_ops         =       &netem_class_ops,
+       .priv_size      =       sizeof(struct netem_sched_data),
+       .enqueue        =       netem_enqueue,
+       .dequeue        =       netem_dequeue,
+       .requeue        =       netem_requeue,
+       .drop           =       netem_drop,
+       .init           =       netem_init,
+       .reset          =       netem_reset,
+       .destroy        =       netem_destroy,
+       .change         =       netem_change,
+       .dump           =       netem_dump,
+       .owner          =       THIS_MODULE,
+};
+
+
+static int __init netem_module_init(void)
+{
+       return register_qdisc(&netem_qdisc_ops);
+}
+static void __exit netem_module_exit(void)
+{
+       unregister_qdisc(&netem_qdisc_ops);
+}
+module_init(netem_module_init)
+module_exit(netem_module_exit)
+MODULE_LICENSE("GPL");
diff --git a/scripts/mkmakefile b/scripts/mkmakefile
new file mode 100644 (file)
index 0000000..c4d621b
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Generates a small Makefile used in the root of the output
+# directory, to allow make to be started from there.
+# The Makefile also allow for more convinient build of external modules
+
+# Usage
+# $1 - Kernel src directory
+# $2 - Output directory
+# $3 - version
+# $4 - patchlevel
+
+
+cat << EOF
+# Automatically generated by $0: don't edit
+
+VERSION = $3
+PATCHLEVEL = $4
+
+KERNELSRC    := $1
+KERNELOUTPUT := $2
+
+MAKEFLAGS += --no-print-directory
+
+all:
+       \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT)
+
+%::
+       \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT) \$@
+
+EOF
+
diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile
new file mode 100644 (file)
index 0000000..f66bf52
--- /dev/null
@@ -0,0 +1,16 @@
+host-progs     := modpost mk_elfconfig
+always         := $(host-progs) empty.o
+
+modpost-objs   := modpost.o file2alias.o sumversion.o
+
+# dependencies on generated files need to be listed explicitly
+
+$(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h
+
+quiet_cmd_elfconfig = MKELF   $@
+      cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@
+
+$(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE
+       $(call if_changed,elfconfig)
+
+targets += elfconfig.h
diff --git a/scripts/mod/empty.c b/scripts/mod/empty.c
new file mode 100644 (file)
index 0000000..49839cc
--- /dev/null
@@ -0,0 +1 @@
+/* empty file to figure out endianness / word size */
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
new file mode 100644 (file)
index 0000000..f38c6d7
--- /dev/null
@@ -0,0 +1,282 @@
+/* Simple code to turn various tables in an ELF file into alias definitions.
+ * This deals with kernel datastructures where they should be
+ * dealt with: in the kernel source.
+ *
+ * Copyright 2002-2003  Rusty Russell, IBM Corporation
+ *           2003       Kai Germaschewski
+ *           
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "modpost.h"
+
+/* We use the ELF typedefs, since we can't rely on stdint.h being present. */
+
+#if KERNEL_ELFCLASS == ELFCLASS32
+typedef Elf32_Addr     kernel_ulong_t;
+#else
+typedef Elf64_Addr     kernel_ulong_t;
+#endif
+
+typedef Elf32_Word     __u32;
+typedef Elf32_Half     __u16;
+typedef unsigned char  __u8;
+
+/* Big exception to the "don't include kernel headers into userspace, which
+ * even potentially has different endianness and word sizes, since 
+ * we handle those differences explicitly below */
+#include "../../include/linux/mod_devicetable.h"
+
+#define ADD(str, sep, cond, field)                              \
+do {                                                            \
+        strcat(str, sep);                                       \
+        if (cond)                                               \
+                sprintf(str + strlen(str),                      \
+                        sizeof(field) == 1 ? "%02X" :           \
+                        sizeof(field) == 2 ? "%04X" :           \
+                        sizeof(field) == 4 ? "%08X" : "",       \
+                        field);                                 \
+        else                                                    \
+                sprintf(str + strlen(str), "*");                \
+} while(0)
+
+/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */
+static int do_usb_entry(const char *filename,
+                       struct usb_device_id *id, char *alias)
+{
+       id->match_flags = TO_NATIVE(id->match_flags);
+       id->idVendor = TO_NATIVE(id->idVendor);
+       id->idProduct = TO_NATIVE(id->idProduct);
+       id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
+       id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
+
+       /*
+        * Some modules (visor) have empty slots as placeholder for
+        * run-time specification that results in catch-all alias
+        */
+       if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
+               return 1;
+
+       strcpy(alias, "usb:");
+       ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
+           id->idVendor);
+       ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
+           id->idProduct);
+       ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
+           id->bcdDevice_lo);
+       ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
+           id->bcdDevice_hi);
+       ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
+           id->bDeviceClass);
+       ADD(alias, "dsc",
+           id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
+           id->bDeviceSubClass);
+       ADD(alias, "dp",
+           id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
+           id->bDeviceProtocol);
+       ADD(alias, "ic",
+           id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
+           id->bInterfaceClass);
+       ADD(alias, "isc",
+           id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+           id->bInterfaceSubClass);
+       ADD(alias, "ip",
+           id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+           id->bInterfaceProtocol);
+       return 1;
+}
+
+/* Looks like: ieee1394:venNmoNspNverN */
+static int do_ieee1394_entry(const char *filename,
+                            struct ieee1394_device_id *id, char *alias)
+{
+       id->match_flags = TO_NATIVE(id->match_flags);
+       id->vendor_id = TO_NATIVE(id->vendor_id);
+       id->model_id = TO_NATIVE(id->model_id);
+       id->specifier_id = TO_NATIVE(id->specifier_id);
+       id->version = TO_NATIVE(id->version);
+
+       strcpy(alias, "ieee1394:");
+       ADD(alias, "ven", id->match_flags & IEEE1394_MATCH_VENDOR_ID,
+           id->vendor_id);
+       ADD(alias, "mo", id->match_flags & IEEE1394_MATCH_MODEL_ID,
+           id->model_id);
+       ADD(alias, "sp", id->match_flags & IEEE1394_MATCH_SPECIFIER_ID,
+           id->specifier_id);
+       ADD(alias, "ver", id->match_flags & IEEE1394_MATCH_VERSION,
+           id->version);
+
+       return 1;
+}
+
+/* Looks like: pci:vNdNsvNsdNbcNscNiN. */
+static int do_pci_entry(const char *filename,
+                       struct pci_device_id *id, char *alias)
+{
+       /* Class field can be divided into these three. */
+       unsigned char baseclass, subclass, interface,
+               baseclass_mask, subclass_mask, interface_mask;
+
+       id->vendor = TO_NATIVE(id->vendor);
+       id->device = TO_NATIVE(id->device);
+       id->subvendor = TO_NATIVE(id->subvendor);
+       id->subdevice = TO_NATIVE(id->subdevice);
+       id->class = TO_NATIVE(id->class);
+       id->class_mask = TO_NATIVE(id->class_mask);
+
+       strcpy(alias, "pci:");
+       ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor);
+       ADD(alias, "d", id->device != PCI_ANY_ID, id->device);
+       ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor);
+       ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice);
+
+       baseclass = (id->class) >> 16;
+       baseclass_mask = (id->class_mask) >> 16;
+       subclass = (id->class) >> 8;
+       subclass_mask = (id->class_mask) >> 8;
+       interface = id->class;
+       interface_mask = id->class_mask;
+
+       if ((baseclass_mask != 0 && baseclass_mask != 0xFF)
+           || (subclass_mask != 0 && subclass_mask != 0xFF)
+           || (interface_mask != 0 && interface_mask != 0xFF)) {
+               fprintf(stderr,
+                       "*** Warning: Can't handle masks in %s:%04X\n",
+                       filename, id->class_mask);
+               return 0;
+       }
+
+       ADD(alias, "bc", baseclass_mask == 0xFF, baseclass);
+       ADD(alias, "sc", subclass_mask == 0xFF, subclass);
+       ADD(alias, "i", interface_mask == 0xFF, interface);
+       return 1;
+}
+
+/* looks like: "ccw:tNmNdtNdmN" */ 
+static int do_ccw_entry(const char *filename,
+                       struct ccw_device_id *id, char *alias)
+{
+       id->match_flags = TO_NATIVE(id->match_flags);
+       id->cu_type = TO_NATIVE(id->cu_type);
+       id->cu_model = TO_NATIVE(id->cu_model);
+       id->dev_type = TO_NATIVE(id->dev_type);
+       id->dev_model = TO_NATIVE(id->dev_model);
+
+       strcpy(alias, "ccw:");
+       ADD(alias, "t", id->match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE,
+           id->cu_type);
+       ADD(alias, "m", id->match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL,
+           id->cu_model);
+       ADD(alias, "dt", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE,
+           id->dev_type);
+       ADD(alias, "dm", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE,
+           id->dev_model);
+       return 1;
+}
+
+/* looks like: "pnp:dD" */
+static int do_pnp_entry(const char *filename,
+                       struct pnp_device_id *id, char *alias)
+{
+       sprintf(alias, "pnp:d%s", id->id);
+       return 1;
+}
+
+/* looks like: "pnp:cCdD..." */
+static int do_pnp_card_entry(const char *filename,
+                       struct pnp_card_device_id *id, char *alias)
+{
+       int i;
+
+       sprintf(alias, "pnp:c%s", id->id);
+       for (i = 0; i < PNP_MAX_DEVICES; i++) {
+               if (! *id->devs[i].id)
+                       break;
+               sprintf(alias + strlen(alias), "d%s", id->devs[i].id);
+       }
+       return 1;
+}
+
+/* Ignore any prefix, eg. v850 prepends _ */
+static inline int sym_is(const char *symbol, const char *name)
+{
+       const char *match;
+
+       match = strstr(symbol, name);
+       if (!match)
+               return 0;
+       return match[strlen(symbol)] == '\0';
+}
+
+static void do_table(void *symval, unsigned long size,
+                    unsigned long id_size,
+                    void *function,
+                    struct module *mod)
+{
+       unsigned int i;
+       char alias[500];
+       int (*do_entry)(const char *, void *entry, char *alias) = function;
+
+       if (size % id_size || size < id_size) {
+               fprintf(stderr, "*** Warning: %s ids %lu bad size "
+                       "(each on %lu)\n", mod->name, size, id_size);
+       }
+       /* Leave last one: it's the terminator. */
+       size -= id_size;
+
+       for (i = 0; i < size; i += id_size) {
+               if (do_entry(mod->name, symval+i, alias)) {
+                       /* Always end in a wildcard, for future extension */
+                       if (alias[strlen(alias)-1] != '*')
+                               strcat(alias, "*");
+                       buf_printf(&mod->dev_table_buf,
+                                  "MODULE_ALIAS(\"%s\");\n", alias);
+               }
+       }
+}
+
+/* Create MODULE_ALIAS() statements.
+ * At this time, we cannot write the actual output C source yet,
+ * so we write into the mod->dev_table_buf buffer. */
+void handle_moddevtable(struct module *mod, struct elf_info *info,
+                       Elf_Sym *sym, const char *symname)
+{
+       void *symval;
+
+       /* We're looking for a section relative symbol */
+       if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
+               return;
+
+       symval = (void *)info->hdr
+               + info->sechdrs[sym->st_shndx].sh_offset
+               + sym->st_value;
+
+       if (sym_is(symname, "__mod_pci_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct pci_device_id),
+                        do_pci_entry, mod);
+       else if (sym_is(symname, "__mod_usb_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct usb_device_id),
+                        do_usb_entry, mod);
+       else if (sym_is(symname, "__mod_ieee1394_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct ieee1394_device_id),
+                        do_ieee1394_entry, mod);
+       else if (sym_is(symname, "__mod_ccw_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct ccw_device_id),
+                        do_ccw_entry, mod);
+       else if (sym_is(symname, "__mod_pnp_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct pnp_device_id),
+                        do_pnp_entry, mod);
+       else if (sym_is(symname, "__mod_pnp_card_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
+                        do_pnp_card_entry, mod);
+}
+
+/* Now add out buffered information to the generated C source */
+void add_moddevtable(struct buffer *buf, struct module *mod)
+{
+       buf_printf(buf, "\n");
+       buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
+       free(mod->dev_table_buf.p);
+}
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
new file mode 100644 (file)
index 0000000..de2aabf
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+int
+main(int argc, char **argv)
+{
+       unsigned char ei[EI_NIDENT];    
+       union { short s; char c[2]; } endian_test;
+
+       if (argc != 2) {
+               fprintf(stderr, "Error: no arch\n");
+       }
+       if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) {
+               fprintf(stderr, "Error: input truncated\n");
+               return 1;
+       }
+       if (memcmp(ei, ELFMAG, SELFMAG) != 0) {
+               fprintf(stderr, "Error: not ELF\n");
+               return 1;
+       }
+       switch (ei[EI_CLASS]) {
+       case ELFCLASS32:
+               printf("#define KERNEL_ELFCLASS ELFCLASS32\n");
+               break;
+       case ELFCLASS64:
+               printf("#define KERNEL_ELFCLASS ELFCLASS64\n");
+               break;
+       default:
+               abort();
+       }
+       switch (ei[EI_DATA]) {
+       case ELFDATA2LSB:
+               printf("#define KERNEL_ELFDATA ELFDATA2LSB\n");
+               break;
+       case ELFDATA2MSB:
+               printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
+               break;
+       default:
+               abort();
+       }
+
+       if (sizeof(unsigned long) == 4) {
+               printf("#define HOST_ELFCLASS ELFCLASS32\n");
+       } else if (sizeof(unsigned long) == 8) {
+               printf("#define HOST_ELFCLASS ELFCLASS64\n");
+       }
+
+       endian_test.s = 0x0102;
+       if (memcmp(endian_test.c, "\x01\x02", 2) == 0)
+               printf("#define HOST_ELFDATA ELFDATA2MSB\n");
+       else if (memcmp(endian_test.c, "\x02\x01", 2) == 0)
+               printf("#define HOST_ELFDATA ELFDATA2LSB\n");
+       else
+               abort();
+
+       if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0))
+               printf("#define MODULE_SYMBOL_PREFIX \"_\"\n");
+       else 
+               printf("#define MODULE_SYMBOL_PREFIX \"\"\n");
+
+       return 0;
+}
+
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
new file mode 100644 (file)
index 0000000..662e75b
--- /dev/null
@@ -0,0 +1,739 @@
+/* Postprocess module symbol versions
+ *
+ * Copyright 2003       Kai Germaschewski
+ *           2002-2003  Rusty Russell, IBM Corporation
+ *
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: modpost vmlinux module1.o module2.o ...
+ */
+
+#include <ctype.h>
+#include "modpost.h"
+
+/* Are we using CONFIG_MODVERSIONS? */
+int modversions = 0;
+/* Warn about undefined symbols? (do so if we have vmlinux) */
+int have_vmlinux = 0;
+
+void
+fatal(const char *fmt, ...)
+{
+       va_list arglist;
+
+       fprintf(stderr, "FATAL: ");
+
+       va_start(arglist, fmt);
+       vfprintf(stderr, fmt, arglist);
+       va_end(arglist);
+
+       exit(1);
+}
+
+void
+warn(const char *fmt, ...)
+{
+       va_list arglist;
+
+       fprintf(stderr, "WARNING: ");
+
+       va_start(arglist, fmt);
+       vfprintf(stderr, fmt, arglist);
+       va_end(arglist);
+}
+
+void *do_nofail(void *ptr, const char *file, int line, const char *expr)
+{
+       if (!ptr) {
+               fatal("Memory allocation failure %s line %d: %s.\n",
+                     file, line, expr);
+       }
+       return ptr;
+}
+
+/* A list of all modules we processed */
+
+static struct module *modules;
+
+struct module *
+find_module(char *modname)
+{
+       struct module *mod;
+
+       for (mod = modules; mod; mod = mod->next)
+               if (strcmp(mod->name, modname) == 0)
+                       break;
+       return mod;
+}
+
+struct module *
+new_module(char *modname)
+{
+       struct module *mod;
+       char *p, *s;
+       
+       mod = NOFAIL(malloc(sizeof(*mod)));
+       memset(mod, 0, sizeof(*mod));
+       p = NOFAIL(strdup(modname));
+
+       /* strip trailing .o */
+       if ((s = strrchr(p, '.')) != NULL)
+               if (strcmp(s, ".o") == 0)
+                       *s = '\0';
+
+       /* add to list */
+       mod->name = p;
+       mod->next = modules;
+       modules = mod;
+
+       return mod;
+}
+
+/* A hash of all exported symbols,
+ * struct symbol is also used for lists of unresolved symbols */
+
+#define SYMBOL_HASH_SIZE 1024
+
+struct symbol {
+       struct symbol *next;
+       struct module *module;
+       unsigned int crc;
+       int crc_valid;
+       char name[0];
+};
+
+static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
+
+/* This is based on the hash agorithm from gdbm, via tdb */
+static inline unsigned int tdb_hash(const char *name)
+{
+       unsigned value; /* Used to compute the hash value.  */
+       unsigned   i;   /* Used to cycle through random values. */
+
+       /* Set the initial value from the key size. */
+       for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+               value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
+
+       return (1103515243 * value + 12345);
+}
+
+/* Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module */
+
+struct symbol *
+alloc_symbol(const char *name, struct symbol *next)
+{
+       struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
+
+       memset(s, 0, sizeof(*s));
+       strcpy(s->name, name);
+       s->next = next;
+       return s;
+}
+
+/* For the hash of exported symbols */
+
+void
+new_symbol(const char *name, struct module *module, unsigned int *crc)
+{
+       unsigned int hash;
+       struct symbol *new;
+
+       hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
+       new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]);
+       new->module = module;
+       if (crc) {
+               new->crc = *crc;
+               new->crc_valid = 1;
+       }
+}
+
+struct symbol *
+find_symbol(const char *name)
+{
+       struct symbol *s;
+
+       /* For our purposes, .foo matches foo.  PPC64 needs this. */
+       if (name[0] == '.')
+               name++;
+
+       for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) {
+               if (strcmp(s->name, name) == 0)
+                       return s;
+       }
+       return NULL;
+}
+
+/* Add an exported symbol - it may have already been added without a
+ * CRC, in this case just update the CRC */
+void
+add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
+{
+       struct symbol *s = find_symbol(name);
+
+       if (!s) {
+               new_symbol(name, module, crc);
+               return;
+       }
+       if (crc) {
+               s->crc = *crc;
+               s->crc_valid = 1;
+       }
+}
+
+void *
+grab_file(const char *filename, unsigned long *size)
+{
+       struct stat st;
+       void *map;
+       int fd;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0 || fstat(fd, &st) != 0)
+               return NULL;
+
+       *size = st.st_size;
+       map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+       close(fd);
+
+       if (map == MAP_FAILED)
+               return NULL;
+       return map;
+}
+
+/*
+   Return a copy of the next line in a mmap'ed file.
+   spaces in the beginning of the line is trimmed away.
+   Return a pointer to a static buffer.
+*/
+char*
+get_next_line(unsigned long *pos, void *file, unsigned long size)
+{
+       static char line[4096];
+       int skip = 1;
+       size_t len = 0;
+       char *p = (char *)file + *pos;
+       char *s = line;
+
+       for (; *pos < size ; (*pos)++)
+       {
+               if (skip && isspace(*p)) {
+                       p++;
+                       continue;
+               }
+               skip = 0;
+               if (*p != '\n' && (*pos < size)) {
+                       len++;
+                       *s++ = *p++;
+                       if (len > 4095)
+                               break; /* Too long, stop */
+               } else {
+                       /* End of string */
+                       *s = '\0';
+                       return line;
+               }
+       }
+       /* End of buffer */
+       return NULL;
+}
+
+void
+release_file(void *file, unsigned long size)
+{
+       munmap(file, size);
+}
+
+void
+parse_elf(struct elf_info *info, const char *filename)
+{
+       unsigned int i;
+       Elf_Ehdr *hdr = info->hdr;
+       Elf_Shdr *sechdrs;
+       Elf_Sym  *sym;
+
+       hdr = grab_file(filename, &info->size);
+       if (!hdr) {
+               perror(filename);
+               abort();
+       }
+       info->hdr = hdr;
+       if (info->size < sizeof(*hdr))
+               goto truncated;
+
+       /* Fix endianness in ELF header */
+       hdr->e_shoff    = TO_NATIVE(hdr->e_shoff);
+       hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+       hdr->e_shnum    = TO_NATIVE(hdr->e_shnum);
+       hdr->e_machine  = TO_NATIVE(hdr->e_machine);
+       sechdrs = (void *)hdr + hdr->e_shoff;
+       info->sechdrs = sechdrs;
+
+       /* Fix endianness in section headers */
+       for (i = 0; i < hdr->e_shnum; i++) {
+               sechdrs[i].sh_type   = TO_NATIVE(sechdrs[i].sh_type);
+               sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+               sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
+               sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
+               sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
+       }
+       /* Find symbol table. */
+       for (i = 1; i < hdr->e_shnum; i++) {
+               const char *secstrings
+                       = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+               if (sechdrs[i].sh_offset > info->size)
+                       goto truncated;
+               if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
+                       info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
+                       info->modinfo_len = sechdrs[i].sh_size;
+               }
+               if (sechdrs[i].sh_type != SHT_SYMTAB)
+                       continue;
+
+               info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
+               info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset 
+                                                + sechdrs[i].sh_size;
+               info->strtab       = (void *)hdr + 
+                                    sechdrs[sechdrs[i].sh_link].sh_offset;
+       }
+       if (!info->symtab_start) {
+               fprintf(stderr, "modpost: %s no symtab?\n", filename);
+               abort();
+       }
+       /* Fix endianness in symbols */
+       for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+               sym->st_shndx = TO_NATIVE(sym->st_shndx);
+               sym->st_name  = TO_NATIVE(sym->st_name);
+               sym->st_value = TO_NATIVE(sym->st_value);
+               sym->st_size  = TO_NATIVE(sym->st_size);
+       }
+       return;
+
+ truncated:
+       fprintf(stderr, "modpost: %s is truncated.\n", filename);
+       abort();
+}
+
+void
+parse_elf_finish(struct elf_info *info)
+{
+       release_file(info->hdr, info->size);
+}
+
+#define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_"
+#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
+
+void
+handle_modversions(struct module *mod, struct elf_info *info,
+                  Elf_Sym *sym, const char *symname)
+{
+       unsigned int crc;
+
+       switch (sym->st_shndx) {
+       case SHN_COMMON:
+               fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
+                       symname, mod->name);
+               break;
+       case SHN_ABS:
+               /* CRC'd symbol */
+               if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
+                       crc = (unsigned int) sym->st_value;
+                       add_exported_symbol(symname + strlen(CRC_PFX),
+                                           mod, &crc);
+                       modversions = 1;
+               }
+               break;
+       case SHN_UNDEF:
+               /* undefined symbol */
+               if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
+                       break;
+               /* ignore global offset table */
+               if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+                       break;
+               /* ignore __this_module, it will be resolved shortly */
+               if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0)
+                       break;
+#ifdef STT_REGISTER
+               if (info->hdr->e_machine == EM_SPARC ||
+                   info->hdr->e_machine == EM_SPARCV9) {
+                       /* Ignore register directives. */
+                       if (ELF_ST_TYPE(sym->st_info) == STT_REGISTER)
+                               break;
+               }
+#endif
+               
+               if (memcmp(symname, MODULE_SYMBOL_PREFIX,
+                          strlen(MODULE_SYMBOL_PREFIX)) == 0)
+                       mod->unres = alloc_symbol(symname +
+                                                 strlen(MODULE_SYMBOL_PREFIX),
+                                                 mod->unres);
+               break;
+       default:
+               /* All exported symbols */
+               if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
+                       add_exported_symbol(symname + strlen(KSYMTAB_PFX),
+                                           mod, NULL);
+               }
+               break;
+       }
+}
+
+int
+is_vmlinux(const char *modname)
+{
+       const char *myname;
+
+       if ((myname = strrchr(modname, '/')))
+               myname++;
+       else
+               myname = modname;
+
+       return strcmp(myname, "vmlinux") == 0;
+}
+
+void
+read_symbols(char *modname)
+{
+       const char *symname;
+       struct module *mod;
+       struct elf_info info = { };
+       Elf_Sym *sym;
+
+       parse_elf(&info, modname);
+
+       mod = new_module(modname);
+
+       /* When there's no vmlinux, don't print warnings about
+        * unresolved symbols (since there'll be too many ;) */
+       if (is_vmlinux(modname)) {
+               unsigned int fake_crc = 0;
+               have_vmlinux = 1;
+               /* May not have this if !CONFIG_MODULE_UNLOAD: fake it.
+                  If it appears, we'll get the real CRC. */
+               add_exported_symbol("cleanup_module", mod, &fake_crc);
+               add_exported_symbol("struct_module", mod, &fake_crc);
+               mod->skip = 1;
+       }
+
+       for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+               symname = info.strtab + sym->st_name;
+
+               handle_modversions(mod, &info, sym, symname);
+               handle_moddevtable(mod, &info, sym, symname);
+       }
+       maybe_frob_version(modname, info.modinfo, info.modinfo_len,
+                          (void *)info.modinfo - (void *)info.hdr);
+       parse_elf_finish(&info);
+
+       /* Our trick to get versioning for struct_module - it's
+        * never passed as an argument to an exported function, so
+        * the automatic versioning doesn't pick it up, but it's really
+        * important anyhow */
+       if (modversions) {
+               mod->unres = alloc_symbol("struct_module", mod->unres);
+
+               /* Always version init_module and cleanup_module, in
+                * case module doesn't have its own. */
+               mod->unres = alloc_symbol("init_module", mod->unres);
+               mod->unres = alloc_symbol("cleanup_module", mod->unres);
+       }
+}
+
+#define SZ 500
+
+/* We first write the generated file into memory using the
+ * following helper, then compare to the file on disk and
+ * only update the later if anything changed */
+
+void __attribute__((format(printf, 2, 3)))
+buf_printf(struct buffer *buf, const char *fmt, ...)
+{
+       char tmp[SZ];
+       int len;
+       va_list ap;
+       
+       va_start(ap, fmt);
+       len = vsnprintf(tmp, SZ, fmt, ap);
+       if (buf->size - buf->pos < len + 1) {
+               buf->size += 128;
+               buf->p = realloc(buf->p, buf->size);
+       }
+       strncpy(buf->p + buf->pos, tmp, len + 1);
+       buf->pos += len;
+       va_end(ap);
+}
+
+void
+buf_write(struct buffer *buf, const char *s, int len)
+{
+       if (buf->size - buf->pos < len) {
+               buf->size += len;
+               buf->p = realloc(buf->p, buf->size);
+       }
+       strncpy(buf->p + buf->pos, s, len);
+       buf->pos += len;
+}
+
+/* Header for the generated file */
+
+void
+add_header(struct buffer *b)
+{
+       buf_printf(b, "#include <linux/module.h>\n");
+       buf_printf(b, "#include <linux/vermagic.h>\n");
+       buf_printf(b, "#include <linux/compiler.h>\n");
+       buf_printf(b, "\n");
+       buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+       buf_printf(b, "\n");
+       buf_printf(b, "#undef unix\n"); /* We have a module called "unix" */
+       buf_printf(b, "struct module __this_module\n");
+       buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+       buf_printf(b, " .name = __stringify(KBUILD_MODNAME),\n");
+       buf_printf(b, " .init = init_module,\n");
+       buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n");
+       buf_printf(b, " .exit = cleanup_module,\n");
+       buf_printf(b, "#endif\n");
+       buf_printf(b, "};\n");
+}
+
+/* Record CRCs for unresolved symbols */
+
+void
+add_versions(struct buffer *b, struct module *mod)
+{
+       struct symbol *s, *exp;
+
+       for (s = mod->unres; s; s = s->next) {
+               exp = find_symbol(s->name);
+               if (!exp || exp->module == mod) {
+                       if (have_vmlinux)
+                               fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
+                               "undefined!\n", s->name, mod->name);
+                       continue;
+               }
+               s->module = exp->module;
+               s->crc_valid = exp->crc_valid;
+               s->crc = exp->crc;
+       }
+
+       if (!modversions)
+               return;
+
+       buf_printf(b, "\n");
+       buf_printf(b, "static const struct modversion_info ____versions[]\n");
+       buf_printf(b, "__attribute_used__\n");
+       buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
+
+       for (s = mod->unres; s; s = s->next) {
+               if (!s->module) {
+                       continue;
+               }
+               if (!s->crc_valid) {
+                       fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
+                               "has no CRC!\n",
+                               s->name, mod->name);
+                       continue;
+               }
+               buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name);
+       }
+
+       buf_printf(b, "};\n");
+}
+
+void
+add_depends(struct buffer *b, struct module *mod, struct module *modules)
+{
+       struct symbol *s;
+       struct module *m;
+       int first = 1;
+
+       for (m = modules; m; m = m->next) {
+               m->seen = is_vmlinux(m->name);
+       }
+
+       buf_printf(b, "\n");
+       buf_printf(b, "static const char __module_depends[]\n");
+       buf_printf(b, "__attribute_used__\n");
+       buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
+       buf_printf(b, "\"depends=");
+       for (s = mod->unres; s; s = s->next) {
+               if (!s->module)
+                       continue;
+
+               if (s->module->seen)
+                       continue;
+
+               s->module->seen = 1;
+               buf_printf(b, "%s%s", first ? "" : ",",
+                          strrchr(s->module->name, '/') + 1);
+               first = 0;
+       }
+       buf_printf(b, "\";\n");
+}
+
+void
+write_if_changed(struct buffer *b, const char *fname)
+{
+       char *tmp;
+       FILE *file;
+       struct stat st;
+
+       file = fopen(fname, "r");
+       if (!file)
+               goto write;
+
+       if (fstat(fileno(file), &st) < 0)
+               goto close_write;
+
+       if (st.st_size != b->pos)
+               goto close_write;
+
+       tmp = NOFAIL(malloc(b->pos));
+       if (fread(tmp, 1, b->pos, file) != b->pos)
+               goto free_write;
+
+       if (memcmp(tmp, b->p, b->pos) != 0)
+               goto free_write;
+
+       free(tmp);
+       fclose(file);
+       return;
+
+ free_write:
+       free(tmp);
+ close_write:
+       fclose(file);
+ write:
+       file = fopen(fname, "w");
+       if (!file) {
+               perror(fname);
+               exit(1);
+       }
+       if (fwrite(b->p, 1, b->pos, file) != b->pos) {
+               perror(fname);
+               exit(1);
+       }
+       fclose(file);
+}
+
+void
+read_dump(const char *fname)
+{
+       unsigned long size, pos = 0;
+       void *file = grab_file(fname, &size);
+       char *line;
+
+        if (!file)
+               /* No symbol versions, silently ignore */
+               return;
+
+       while ((line = get_next_line(&pos, file, size))) {
+               char *symname, *modname, *d;
+               unsigned int crc;
+               struct module *mod;
+
+               if (!(symname = strchr(line, '\t')))
+                       goto fail;
+               *symname++ = '\0';
+               if (!(modname = strchr(symname, '\t')))
+                       goto fail;
+               *modname++ = '\0';
+               if (strchr(modname, '\t'))
+                       goto fail;
+               crc = strtoul(line, &d, 16);
+               if (*symname == '\0' || *modname == '\0' || *d != '\0')
+                       goto fail;
+
+               if (!(mod = find_module(modname))) {
+                       if (is_vmlinux(modname)) {
+                               modversions = 1;
+                               have_vmlinux = 1;
+                       }
+                       mod = new_module(NOFAIL(strdup(modname)));
+                       mod->skip = 1;
+               }
+               add_exported_symbol(symname, mod, &crc);
+       }
+       return;
+fail:
+       fatal("parse error in symbol dump file\n");
+}
+
+void
+write_dump(const char *fname)
+{
+       struct buffer buf = { };
+       struct symbol *symbol;
+       int n;
+
+       for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+               symbol = symbolhash[n];
+               while (symbol) {
+                       symbol = symbol->next;
+               }
+       }
+
+       for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+               symbol = symbolhash[n];
+               while (symbol) {
+                       buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
+                               symbol->name, symbol->module->name);
+                       symbol = symbol->next;
+               }
+       }
+       write_if_changed(&buf, fname);
+}
+
+int
+main(int argc, char **argv)
+{
+       struct module *mod;
+       struct buffer buf = { };
+       char fname[SZ];
+       char *dump_read = NULL, *dump_write = NULL;
+       int opt;
+
+       while ((opt = getopt(argc, argv, "i:o:")) != -1) {
+               switch(opt) {
+                       case 'i':
+                               dump_read = optarg;
+                               break;
+                       case 'o':
+                               dump_write = optarg;
+                               break;
+                       default:
+                               exit(1);
+               }
+       }
+
+       if (dump_read)
+               read_dump(dump_read);
+
+       while (optind < argc) {
+               read_symbols(argv[optind++]);
+       }
+
+       for (mod = modules; mod; mod = mod->next) {
+               if (mod->skip)
+                       continue;
+
+               buf.pos = 0;
+
+               add_header(&buf);
+               add_versions(&buf, mod);
+               add_depends(&buf, mod, modules);
+               add_moddevtable(&buf, mod);
+
+               sprintf(fname, "%s.mod.c", mod->name);
+               write_if_changed(&buf, fname);
+       }
+
+       if (dump_write)
+               write_dump(dump_write);
+
+       return 0;
+}
+
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
new file mode 100644 (file)
index 0000000..ddb013d
--- /dev/null
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf.h>
+
+#include "elfconfig.h"
+
+#if KERNEL_ELFCLASS == ELFCLASS32
+
+#define Elf_Ehdr    Elf32_Ehdr 
+#define Elf_Shdr    Elf32_Shdr 
+#define Elf_Sym     Elf32_Sym
+#define ELF_ST_BIND ELF32_ST_BIND
+#define ELF_ST_TYPE ELF32_ST_TYPE
+
+#else
+
+#define Elf_Ehdr    Elf64_Ehdr 
+#define Elf_Shdr    Elf64_Shdr 
+#define Elf_Sym     Elf64_Sym
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_ST_TYPE ELF64_ST_TYPE
+
+#endif
+
+#if KERNEL_ELFDATA != HOST_ELFDATA
+
+static inline void __endian(const void *src, void *dest, unsigned int size)
+{
+       unsigned int i;
+       for (i = 0; i < size; i++)
+               ((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
+}
+
+
+
+#define TO_NATIVE(x)                                           \
+({                                                             \
+       typeof(x) __x;                                          \
+       __endian(&(x), &(__x), sizeof(__x));                    \
+       __x;                                                    \
+})
+
+#else /* endianness matches */
+
+#define TO_NATIVE(x) (x)
+
+#endif
+
+#define NOFAIL(ptr)   do_nofail((ptr), __FILE__, __LINE__, #ptr)
+void *do_nofail(void *ptr, const char *file, int line, const char *expr);
+
+struct buffer {
+       char *p;
+       int pos;
+       int size;
+};
+
+void __attribute__((format(printf, 2, 3)))
+buf_printf(struct buffer *buf, const char *fmt, ...);
+
+void
+buf_write(struct buffer *buf, const char *s, int len);
+
+struct module {
+       struct module *next;
+       const char *name;
+       struct symbol *unres;
+       int seen;
+       int skip;
+       struct buffer dev_table_buf;
+};
+
+struct elf_info {
+       unsigned long size;
+       Elf_Ehdr     *hdr;
+       Elf_Shdr     *sechdrs;
+       Elf_Sym      *symtab_start;
+       Elf_Sym      *symtab_stop;
+       const char   *strtab;
+       char         *modinfo;
+       unsigned int modinfo_len;
+};
+
+void handle_moddevtable(struct module *mod, struct elf_info *info,
+                       Elf_Sym *sym, const char *symname);
+
+void add_moddevtable(struct buffer *buf, struct module *mod);
+
+void maybe_frob_version(const char *modfilename,
+                       void *modinfo,
+                       unsigned long modinfo_len,
+                       unsigned long modinfo_offset);
+
+void *grab_file(const char *filename, unsigned long *size);
+char* get_next_line(unsigned long *pos, void *file, unsigned long size);
+void release_file(void *file, unsigned long size);
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
new file mode 100644 (file)
index 0000000..b41b718
--- /dev/null
@@ -0,0 +1,544 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+       /* Skip non-zero chars */
+       while (string[0]) {
+               string++;
+               if ((*secsize)-- <= 1)
+                       return NULL;
+       }
+
+       /* Skip any zero padding. */
+       while (!string[0]) {
+               string++;
+               if ((*secsize)-- <= 1)
+                       return NULL;
+       }
+       return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+                        const char *tag)
+{
+       char *p;
+       unsigned int taglen = strlen(tag);
+       unsigned long size = modinfo_len;
+
+       for (p = modinfo; p; p = next_string(p, &size)) {
+               if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+                       return p + taglen + 1;
+       }
+       return NULL;
+}
+
+/*
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; 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.
+ *
+ */
+#define MD4_DIGEST_SIZE                16
+#define MD4_HMAC_BLOCK_SIZE    64
+#define MD4_BLOCK_WORDS                16
+#define MD4_HASH_WORDS         4
+
+struct md4_ctx {
+       uint32_t hash[MD4_HASH_WORDS];
+       uint32_t block[MD4_BLOCK_WORDS];
+       uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+       x &= 0xFFFFFFFF;
+       return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+       return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+       return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+       return x ^ y ^ z;
+}
+
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+       while (words--) {
+               *buf = ntohl(*buf);
+               buf++;
+       }
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+       while (words--) {
+               *buf = htonl(*buf);
+               buf++;
+       }
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+       uint32_t a, b, c, d;
+
+       a = hash[0];
+       b = hash[1];
+       c = hash[2];
+       d = hash[3];
+
+       ROUND1(a, b, c, d, in[0], 3);
+       ROUND1(d, a, b, c, in[1], 7);
+       ROUND1(c, d, a, b, in[2], 11);
+       ROUND1(b, c, d, a, in[3], 19);
+       ROUND1(a, b, c, d, in[4], 3);
+       ROUND1(d, a, b, c, in[5], 7);
+       ROUND1(c, d, a, b, in[6], 11);
+       ROUND1(b, c, d, a, in[7], 19);
+       ROUND1(a, b, c, d, in[8], 3);
+       ROUND1(d, a, b, c, in[9], 7);
+       ROUND1(c, d, a, b, in[10], 11);
+       ROUND1(b, c, d, a, in[11], 19);
+       ROUND1(a, b, c, d, in[12], 3);
+       ROUND1(d, a, b, c, in[13], 7);
+       ROUND1(c, d, a, b, in[14], 11);
+       ROUND1(b, c, d, a, in[15], 19);
+
+       ROUND2(a, b, c, d,in[ 0], 3);
+       ROUND2(d, a, b, c, in[4], 5);
+       ROUND2(c, d, a, b, in[8], 9);
+       ROUND2(b, c, d, a, in[12], 13);
+       ROUND2(a, b, c, d, in[1], 3);
+       ROUND2(d, a, b, c, in[5], 5);
+       ROUND2(c, d, a, b, in[9], 9);
+       ROUND2(b, c, d, a, in[13], 13);
+       ROUND2(a, b, c, d, in[2], 3);
+       ROUND2(d, a, b, c, in[6], 5);
+       ROUND2(c, d, a, b, in[10], 9);
+       ROUND2(b, c, d, a, in[14], 13);
+       ROUND2(a, b, c, d, in[3], 3);
+       ROUND2(d, a, b, c, in[7], 5);
+       ROUND2(c, d, a, b, in[11], 9);
+       ROUND2(b, c, d, a, in[15], 13);
+
+       ROUND3(a, b, c, d,in[ 0], 3);
+       ROUND3(d, a, b, c, in[8], 9);
+       ROUND3(c, d, a, b, in[4], 11);
+       ROUND3(b, c, d, a, in[12], 15);
+       ROUND3(a, b, c, d, in[2], 3);
+       ROUND3(d, a, b, c, in[10], 9);
+       ROUND3(c, d, a, b, in[6], 11);
+       ROUND3(b, c, d, a, in[14], 15);
+       ROUND3(a, b, c, d, in[1], 3);
+       ROUND3(d, a, b, c, in[9], 9);
+       ROUND3(c, d, a, b, in[5], 11);
+       ROUND3(b, c, d, a, in[13], 15);
+       ROUND3(a, b, c, d, in[3], 3);
+       ROUND3(d, a, b, c, in[11], 9);
+       ROUND3(c, d, a, b, in[7], 11);
+       ROUND3(b, c, d, a, in[15], 15);
+
+       hash[0] += a;
+       hash[1] += b;
+       hash[2] += c;
+       hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+       le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+       md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+       mctx->hash[0] = 0x67452301;
+       mctx->hash[1] = 0xefcdab89;
+       mctx->hash[2] = 0x98badcfe;
+       mctx->hash[3] = 0x10325476;
+       mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+                      const unsigned char *data, unsigned int len)
+{
+       const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+       mctx->byte_count += len;
+
+       if (avail > len) {
+               memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+                      data, len);
+               return;
+       }
+
+       memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+              data, avail);
+
+       md4_transform_helper(mctx);
+       data += avail;
+       len -= avail;
+
+       while (len >= sizeof(mctx->block)) {
+               memcpy(mctx->block, data, sizeof(mctx->block));
+               md4_transform_helper(mctx);
+               data += sizeof(mctx->block);
+               len -= sizeof(mctx->block);
+       }
+
+       memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+       const unsigned int offset = mctx->byte_count & 0x3f;
+       char *p = (char *)mctx->block + offset;
+       int padding = 56 - (offset + 1);
+
+       *p++ = 0x80;
+       if (padding < 0) {
+               memset(p, 0x00, padding + sizeof (uint64_t));
+               md4_transform_helper(mctx);
+               p = (char *)mctx->block;
+               padding = 56;
+       }
+
+       memset(p, 0, padding);
+       mctx->block[14] = mctx->byte_count << 3;
+       mctx->block[15] = mctx->byte_count >> 29;
+       le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+                         sizeof(uint64_t)) / sizeof(uint32_t));
+       md4_transform(mctx->hash, mctx->block);
+       cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+
+       snprintf(out, len, "%08X%08X%08X%08X",
+                mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+       md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+                       struct md4_ctx *md)
+{
+       unsigned long i;
+
+       add_char(file[0], md);
+       for (i = 1; i < len; i++) {
+               add_char(file[i], md);
+               if (file[i] == '"' && file[i-1] != '\\')
+                       break;
+       }
+       return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+       unsigned long i;
+
+       for (i = 2; i < len; i++) {
+               if (file[i-1] == '*' && file[i] == '/')
+                       break;
+       }
+       return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+       char *file;
+       unsigned long i, len;
+
+       file = grab_file(fname, &len);
+       if (!file)
+               return 0;
+
+       for (i = 0; i < len; i++) {
+               /* Collapse and ignore \ and CR. */
+               if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+                       i++;
+                       continue;
+               }
+
+               /* Ignore whitespace */
+               if (isspace(file[i]))
+                       continue;
+
+               /* Handle strings as whole units */
+               if (file[i] == '"') {
+                       i += parse_string(file+i, len - i, md);
+                       continue;
+               }
+
+               /* Comments: ignore */
+               if (file[i] == '/' && file[i+1] == '*') {
+                       i += parse_comment(file+i, len - i);
+                       continue;
+               }
+
+               add_char(file[i], md);
+       }
+       release_file(file, len);
+       return 1;
+}
+
+/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
+ * figure out source file. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+       char *cmd, *file, *line, *dir;
+       const char *base;
+       unsigned long flen, pos = 0;
+       int dirlen, ret = 0, check_files = 0;
+
+       cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd")));
+
+       base = strrchr(objfile, '/');
+       if (base) {
+               base++;
+               dirlen = base - objfile;
+               sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+       } else {
+               dirlen = 0;
+               sprintf(cmd, ".%s.cmd", objfile);
+       }
+       dir = NOFAIL(malloc(dirlen + 1));
+       strncpy(dir, objfile, dirlen);
+       dir[dirlen] = '\0';
+
+       file = grab_file(cmd, &flen);
+       if (!file) {
+               fprintf(stderr, "Warning: could not find %s for %s\n",
+                       cmd, objfile);
+               goto out;
+       }
+
+       /* There will be a line like so:
+               deps_drivers/net/dummy.o := \
+                 drivers/net/dummy.c \
+                   $(wildcard include/config/net/fastroute.h) \
+                 include/linux/config.h \
+                   $(wildcard include/config/h.h) \
+                 include/linux/module.h \
+
+          Sum all files in the same dir or subdirs.
+       */
+       while ((line = get_next_line(&pos, file, flen)) != NULL) {
+               char* p = line;
+               if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
+                       check_files = 1;
+                       continue;
+               }
+               if (!check_files)
+                       continue;
+
+               /* Continue until line does not end with '\' */
+               if ( *(p + strlen(p)-1) != '\\')
+                       break;
+               /* Terminate line at first space, to get rid of final ' \' */
+               while (*p) {
+                       if (isspace(*p)) {
+                               *p = '\0';
+                               break;
+                       }
+                       p++;
+               }
+
+               /* Check if this file is in same dir as objfile */
+               if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) {
+                       if (!parse_file(line, md)) {
+                               fprintf(stderr,
+                                       "Warning: could not open %s: %s\n",
+                                       line, strerror(errno));
+                               goto out_file;
+                       }
+
+               }
+
+       }
+
+       /* Everyone parsed OK */
+       ret = 1;
+out_file:
+       release_file(file, flen);
+out:
+       free(dir);
+       free(cmd);
+       return ret;
+}
+
+static int get_version(const char *modname, char sum[])
+{
+       void *file;
+       unsigned long len;
+       int ret = 0;
+       struct md4_ctx md;
+       char *sources, *end, *fname;
+       const char *basename;
+       char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+       /* Source files for module are in .tmp_versions/modname.mod,
+          after the first line. */
+       if (strrchr(modname, '/'))
+               basename = strrchr(modname, '/') + 1;
+       else
+               basename = modname;
+       sprintf(filelist, ".tmp_versions/%s", basename);
+       /* Truncate .o, add .mod */
+       strcpy(filelist + strlen(filelist)-2, ".mod");
+
+       file = grab_file(filelist, &len);
+       if (!file) {
+               fprintf(stderr, "Warning: could not find versions for %s\n",
+                       filelist);
+               return 0;
+       }
+
+       sources = strchr(file, '\n');
+       if (!sources) {
+               fprintf(stderr, "Warning: malformed versions file for %s\n",
+                       modname);
+               goto release;
+       }
+
+       sources++;
+       end = strchr(sources, '\n');
+       if (!end) {
+               fprintf(stderr, "Warning: bad ending versions file for %s\n",
+                       modname);
+               goto release;
+       }
+       *end = '\0';
+
+       md4_init(&md);
+       for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " ")) {
+               if (!parse_source_files(fname, &md))
+                       goto release;
+       }
+
+       /* sum is of form \0<padding>. */
+       md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+       ret = 1;
+release:
+       release_file(file, len);
+       return ret;
+}
+
+static void write_version(const char *filename, const char *sum,
+                         unsigned long offset)
+{
+       int fd;
+
+       fd = open(filename, O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+                       filename, strerror(errno));
+               return;
+       }
+
+       if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+               fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+                       filename, offset, strerror(errno));
+               goto out;
+       }
+
+       if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
+               fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+                       filename, strerror(errno));
+               goto out;
+       }
+out:
+       close(fd);
+}
+
+void strip_rcs_crap(char *version)
+{
+       unsigned int len, full_len;
+
+       if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
+               return;
+
+       /* Space for version string follows. */
+       full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
+
+       /* Move string to start with version number: prefix will be
+        * $Revision$ or $Revision: */
+       len = strlen("$Revision");
+       if (version[len] == ':' || version[len] == '$')
+               len++;
+       while (isspace(version[len]))
+               len++;
+       memmove(version, version+len, full_len-len);
+       full_len -= len;
+
+       /* Preserve up to next whitespace. */
+       len = 0;
+       while (version[len] && !isspace(version[len]))
+               len++;
+       memmove(version + len, version + strlen(version),
+               full_len - strlen(version));
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+                       void *modinfo,
+                       unsigned long modinfo_len,
+                       unsigned long modinfo_offset)
+{
+       char *version, *csum;
+
+       version = get_modinfo(modinfo, modinfo_len, "version");
+       if (!version)
+               return;
+
+       /* RCS $Revision gets stripped out. */
+       strip_rcs_crap(version);
+
+       /* Check against double sumversion */
+       if (strchr(version, ' '))
+               return;
+
+       /* Version contains embedded NUL: second half has space for checksum */
+       csum = version + strlen(version);
+       *(csum++) = ' ';
+       if (get_version(modfilename, csum))
+               write_version(modfilename, version,
+                             modinfo_offset + (version - (char *)modinfo));
+}
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
new file mode 100644 (file)
index 0000000..48f89e1
--- /dev/null
@@ -0,0 +1,89 @@
+# Makefile for the different targets used to generate full packages of a kernel
+# It uses the generic clean infrastructure of kbuild
+
+# Ignore the following files/directories during tar operation
+TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS
+
+
+# RPM target
+# ---------------------------------------------------------------------------
+# The rpm target generates two rpm files:
+# /usr/src/packages/SRPMS/kernel-2.6.7rc2-1.src.rpm
+# /usr/src/packages/RPMS/i386/kernel-2.6.7rc2-1.<arch>.rpm
+# The src.rpm files includes all source for the kernel being built
+# The <arch>.rpm includes kernel configuration, modules etc.
+#
+# Process to create the rpm files
+# a) clean the kernel
+# b) Generate .spec file
+# c) Build a tar ball, using symlink to make kernel version
+#    first entry in the path
+# d) and pack the result to a tar.gz file
+# e) generate the rpm files, based on kernel.spec
+# - Use /. to avoid tar packing just the symlink
+
+# Do we have rpmbuild, otherwise fall back to the older rpm
+RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
+                  else echo rpm; fi)
+
+# Remove hyphens since they have special meaning in RPM filenames
+KERNELPATH := kernel-$(subst -,,$(KERNELRELEASE))
+MKSPEC     := $(srctree)/scripts/package/mkspec
+PREV       := set -e; cd ..;
+
+# rpm-pkg
+.PHONY: rpm-pkg rpm
+
+$(objtree)/kernel.spec: $(MKSPEC) $(srctree)/Makefile
+       $(CONFIG_SHELL) $(MKSPEC) > $@
+
+rpm-pkg rpm: $(objtree)/kernel.spec
+       $(MAKE) clean
+       $(PREV) ln -sf $(srctree) $(KERNELPATH)
+       $(PREV) tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/.
+       $(PREV) rm $(KERNELPATH)
+
+       set -e; \
+       $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
+       set -e; \
+       mv -f $(objtree)/.tmp_version $(objtree)/.version
+
+       $(RPM) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz
+       rm ../$(KERNELPATH).tar.gz
+
+clean-rule +=  rm -f $(objtree)/kernel.spec
+
+# binrpm-pkg
+.PHONY: binrpm-pkg
+$(objtree)/binkernel.spec: $(MKSPEC) $(srctree)/Makefile
+       $(CONFIG_SHELL) $(MKSPEC) prebuilt > $@
+       
+binrpm-pkg: $(objtree)/binkernel.spec
+       $(MAKE)
+       set -e; \
+       $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
+       set -e; \
+       mv -f $(objtree)/.tmp_version $(objtree)/.version
+
+       $(RPM) --define "_builddir $(srctree)" --target $(UTS_MACHINE) -bb $<
+
+clean-rule += rm -f $(objtree)/binkernel.spec
+
+# Deb target
+# ---------------------------------------------------------------------------
+#
+.PHONY: deb-pkg
+deb-pkg:
+       $(MAKE)
+       $(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
+
+clean-rule += && rm -rf $(objtree)/debian/
+
+
+# Help text displayed when executing 'make help'
+# ---------------------------------------------------------------------------
+help:
+       @echo  '  rpm-pkg         - Build the kernel as an RPM package'
+       @echo  '  binrpm-pkg      - Build an rpm package containing the compiled kernel & modules'
+       @echo  '  deb-pkg         - Build the kernel as an deb package'
+
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
new file mode 100644 (file)
index 0000000..5d94e45
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+#
+#      Output a simple RPM spec file that uses no fancy features requring
+#      RPM v4. This is intended to work with any RPM distro.
+#
+#      The only gothic bit here is redefining install_post to avoid
+#      stripping the symbols from files in the kernel which we want
+#
+#      Patched for non-x86 by Opencon (L) 2002 <opencon@rio.skydome.net>
+#
+
+# how we were called determines which rpms we build and how we build them
+if [ "$1" = "prebuilt" ]; then
+       PREBUILT=true
+else
+       PREBUILT=false
+fi
+
+# starting to output the spec
+if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
+       PROVIDES=kernel-drm
+fi
+
+PROVIDES="$PROVIDES kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+
+echo "Name: kernel"
+echo "Summary: The Linux Kernel"
+echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//g"
+# we need to determine the NEXT version number so that uname and
+# rpm -q will agree
+echo "Release: `. $srctree/scripts/mkversion`"
+echo "License: GPL"
+echo "Group: System Environment/Kernel"
+echo "Vendor: The Linux Community"
+echo "URL: http://www.kernel.org"
+
+if ! $PREBUILT; then
+echo -n "Source: kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL"
+echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//g"
+fi
+
+echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "Provides: $PROVIDES"
+echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
+echo "%define debug_package %{nil}"
+echo ""
+echo "%description"
+echo "The Linux Kernel, the operating system core itself"
+echo ""
+
+if ! $PREBUILT; then
+echo "%prep"
+echo "%setup -q"
+echo ""
+fi
+
+echo "%build"
+
+if ! $PREBUILT; then
+echo "make clean && make"
+echo ""
+fi
+
+echo "%install"
+echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+
+echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make modules_install'
+echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+
+echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+
+echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo ""
+echo "%clean"
+echo '#echo -rf $RPM_BUILD_ROOT'
+echo ""
+echo "%files"
+echo '%defattr (-, root, root)'
+echo "%dir /lib/modules"
+echo "/lib/modules/$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo "/boot/*"
+echo ""